1
0
mirror of https://github.com/Uberi/Minetest-WorldEdit.git synced 2025-06-29 06:31:06 +02:00

1 Commits
1.2 ... master

Author SHA1 Message Date
f10da8c9f6 Version MFF 2018-09-05 00:44:21 +02:00
25 changed files with 398 additions and 351 deletions

View File

@ -17,7 +17,6 @@ Many commands also have shorter names that can be typed faster. For example, if
| `//s` | `//set` |
| `//r` | `//replace` |
| `//ri` | `//replaceinverse` |
| `//hcube` | `//hollowcube` |
| `//hspr` | `//hollowsphere` |
| `//spr` | `//sphere` |
| `//hdo` | `//hollowdome` |
@ -117,10 +116,6 @@ Set the current WorldEdit region to `<node>`.
//set Blue Lightstone
//set dirt with grass
### `//param2 <param2>`
Set the param2 value of all nodes in the current WorldEdit region to `<param2>`.
### `//mix <node1> ...`
Fill the current WorldEdit region with a random mix of `<node1>`, `...`.
@ -148,19 +143,6 @@ Replace all nodes other than `<search node>` with `<replace node>` in the curren
//replaceinverse dirt Bronze Block
//replaceinverse mesecons:wire_00000000_off flowers:flower_tulip
### `//hollowcube <width> <height> <length> <node>`
Adds a hollow cube with its ground level centered at WorldEdit position 1 with dimensions `<width>` x `<height>` x `<length>`, composed of `<node>`.
//hollowcube 6 5 6 Diamond Block
### `//cube <width> <height> <length> <node>`
Adds a cube with its ground level centered at WorldEdit position 1 with dimensions `<width>` x `<height>` x `<length>`, composed of `<node>`.
//cube 6 5 6 Diamond Block
//cube 7 2 1 default:cobble
### `//hollowsphere <radius> <node>`
Add hollow sphere centered at WorldEdit position 1 with radius `<radius>`, composed of `<node>`.
@ -193,36 +175,24 @@ Add dome centered at WorldEdit position 1 with radius `<radius>`, composed of `<
//dome -12 glass
//dome 17 mesecons:wire_00000000_off
### `//hollowcylinder x/y/z/? <length> <radius1> [radius2] <node>`
### `//hollowcylinder x/y/z/? <length> <radius> <node>`
Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>`, base radius `<radius1>` (and top radius `[radius2]`), composed of `<node>`.
Despite its name this command allows you to create cones (`radius2` = 0) as well as any shapes inbetween (0 < `radius2` < `radius1`).
Swapping `radius1` and `radius2` will create the same object but upside-down.
Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<node>`.
//hollowcylinder x +5 8 Bronze Block
//hollowcylinder y 28 10 glass
//hollowcylinder z -12 3 mesecons:wire_00000000_off
//hollowcylinder ? 2 4 default:stone
//hollowcylinder y 10 10 0 walls:cobble
//hollowcylinder x 6 0 5 Dirt
//hollowcylinder z 20 10 20 default:desert_stone
### `//cylinder x/y/z/? <length> <radius> <node>`
### `//cylinder x/y/z/? <length> <radius1> [radius2] <node>`
Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>`, base radius `<radius1>` (and top radius `[radius2]`), composed of `<node>`.
Can also create shapes other than cylinders, e.g. cones (see documentation above).
Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<node>`.
//cylinder x +5 8 Bronze Block
//cylinder y 28 10 glass
//cylinder z -12 3 mesecons:wire_00000000_off
//cylinder ? 2 4 default:stone
//cylinder y 10 10 0 walls:cobble
//cylinder x 6 0 5 Dirt
//cylinder z 20 10 20 default:desert_stone
### `//hollowpyramid x/y/z? <height> <node>`
Add hollow pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height `<height>`, composed of `<node>`.

0
LICENSE.txt Normal file → Executable file
View File

21
README.md Normal file → Executable file
View File

@ -1,5 +1,5 @@
WorldEdit v1.2
==============
WorldEdit v1.1 for Minetest 0.4.8+
==================================
The ultimate in-game world editing tool for [Minetest](http://minetest.net/)! Tons of functionality to help with building, fixing, and more.
For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) at the Minetest forums.
@ -33,7 +33,7 @@ WorldEdit works primarily through the WorldEdit GUI and chat commands. Depending
WorldEdit has a huge potential for abuse by untrusted players. Therefore, users will not be able to use WorldEdit unless they have the `worldedit` privelege. This is available by default in single player, but in multiplayer the permission must be explicitly given by someone with the right credentials, using the follwoing chat command: `/grant <player name> worldedit`. This privelege can later be removed using the following chat command: `/revoke <player name> worldedit`.
Certain functions/commands such as WorldEdit `//lua` and `//luatransform` chat commands additionally require the `server` privilege. This is because it is extremely dangerous to give access to these commands to untrusted players, since they essentially are able to control the computer the server is running on. Give this privilege only to people you trust with your computer.
Certain functions/commands such as WorldEdit GUI's "Run Lua" function (equivalent to the `//lua` and `//luatransform` chat command) additionally require the `server` privilege. This is because it is extremely dangerous to give access to these commands to untrusted players, since they essentially are able to control the computer the server is running on. Give this privilege only to people you trust with your computer.
For in-game information about these commands, type `/help <command name>` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region.
@ -51,19 +51,21 @@ This mod supports Minetest versions 0.4.8 and newer. Older versions of WorldEdit
WorldEdit works quite well with other mods, and does not have any known mod conflicts.
WorldEdit GUI requires one of [sfinv](https://github.com/minetest/minetest_game/tree/master/mods/sfinv) (included in minetest_game since 0.4.15), [Unified Inventory](https://forum.minetest.net/viewtopic.php?id=3933) or [Inventory++](https://forum.minetest.net/viewtopic.php?id=6204).
WorldEdit GUI works with [Unified Inventory](https://forum.minetest.net/viewtopic.php?id=3933) and [Inventory++](https://forum.minetest.net/viewtopic.php?id=6204), but these are not required to use the mod.
If you use any other inventory manager mods, note that they may conflict with the WorldEdit GUI. If this is the case, it may be necessary to disable them.
WorldEdit API
-------------
WorldEdit exposes all significant functionality in a simple Lua interface.
WorldEdit exposes all significant functionality in a simple Lua interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. The API is useful for tasks such as high-performance node manipulation, alternative interfaces, and map creation.
Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. The API is useful for tasks such as high-performance node manipulation, alternative interfaces, and map creation.
If you don't add WorldEdit to your "depends.txt" file, each file in the WorldEdit mod is also independent. For example, one may import the WorldEdit primitives API using the following code:
dofile(minetest.get_modpath("worldedit").."/primitives.lua")
AGPLv3 compatible mods may further include WorldEdit files in their own mods. This may be useful if a modder wishes to completely avoid any dependencies on WorldEdit. Note that it is required to give credit to the authors.
This API is documented in the [WorldEdit API Reference](WorldEdit%20API.md).
This API is documented in the [WorldEdit API Reference](WorldEdit API.md).
Axes
----
@ -139,13 +141,9 @@ WorldEdit would not be possible without the contributions of many developers and
cheapie
cornernote
cyisfor
danierukun
electricface
est31
kaeza
khonkhortisan
pickardjoe
Sebastien Ponce
sfan5
ShadowNinja
spillz
@ -158,4 +156,5 @@ Copyright 2013 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (corn
This mod is licensed under the [GNU Affero General Public License](http://www.gnu.org/licenses/agpl-3.0.html).
Basically, this means everyone is free to use, modify, and distribute the files, as long as these modifications are also licensed the same way.
Most importantly, the Affero variant of the GPL requires you to publish your modifications in source form, even if the mod is run only on the server, and not distributed.

0
Tutorial.md Normal file → Executable file
View File

View File

@ -27,12 +27,6 @@ Sets a region defined by positions `pos1` and `pos2` to `node_name`. To clear a
Returns the number of nodes set.
### `count = worldedit.set_param2(pos1, pos2, param2)`
Sets the param2 values of all nodes in a region defined by positions `pos1` and `pos2` to `param2`.
Returns the number of nodes set.
### count = worldedit.replace(pos1, pos2, searchnode, replacenode)
Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
@ -121,12 +115,6 @@ Primitives
----------
Contained in primitives.lua, this module allows the creation of several geometric primitives.
### count = worldedit.cube(pos, width, height, length, node_name, hollow)
Adds a cube with its ground level centered at `pos`, the dimensions `width` x `height` x `length`, composed of `node_name`.
Returns the number of nodes added.
### count = worldedit.sphere(pos, radius, node_name, hollow)
Adds a sphere centered at `pos` with radius `radius`, composed of `node_name`.
@ -139,9 +127,9 @@ Adds a dome centered at `pos` with radius `radius`, composed of `node_name`.
Returns the number of nodes added.
### count = worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
### count = worldedit.cylinder(pos, axis, length, radius, node_name, hollow)
Adds a cylinder-like at `pos` along the `axis` axis ("x" or "y" or "z") with length `length`, base radius `radius1` and top radius `radius2`, composed of `node_name`.
Adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `node_name`.
Returns the number of nodes added.

0
config.ld Normal file → Executable file
View File

0
modpack.txt Normal file → Executable file
View File

0
worldedit/code.lua Normal file → Executable file
View File

0
worldedit/common.lua Normal file → Executable file
View File

0
worldedit/compatibility.lua Normal file → Executable file
View File

9
worldedit/init.lua Normal file → Executable file
View File

@ -1,6 +1,6 @@
--- Worldedit.
-- @module worldedit
-- @release 1.2
-- @release 1.1
-- @copyright 2013 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote).
-- @license GNU Affero General Public License version 3 (AGPLv3)
-- @author sfan5
@ -8,12 +8,9 @@
-- @author Bret O'Donnel (cornernote)
-- @author ShadowNinja
worldedit = {}
local ver = {major=1, minor=2}
worldedit.version = ver
worldedit.version_string = string.format("%d.%d", ver.major, ver.minor)
worldedit.version = {1, 1, major=1, minor=1}
worldedit.version_string = table.concat(worldedit.version, ".")
if not minetest.get_voxel_manip then
local err_msg = "This version of WorldEdit requires Minetest 0.4.8 or later! You have an old version."

View File

@ -38,29 +38,6 @@ function worldedit.set(pos1, pos2, node_names)
return worldedit.volume(pos1, pos2)
end
--- Sets param2 of a region.
-- @param pos1
-- @param pos2
-- @param param2 Value of param2 to set
-- @return The number of nodes set.
function worldedit.set_param2(pos1, pos2, param2)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local manip, area = mh.init(pos1, pos2)
local param2_data = manip:get_param2_data()
-- Set param2 for every node
for i in area:iterp(pos1, pos2) do
param2_data[i] = param2
end
-- Update map
manip:set_param2_data(param2_data)
manip:write_to_map()
manip:update_map()
return worldedit.volume(pos1, pos2)
end
--- Replaces all instances of `search_node` with `replace_node` in a region.
-- When `inverse` is `true`, replaces all instances that are NOT `search_node`.

View File

@ -4,47 +4,6 @@
local mh = worldedit.manip_helpers
--- Adds a cube
-- @param pos Position of ground level center of cube
-- @param width Cube width. (x)
-- @param height Cube height. (y)
-- @param length Cube length. (z)
-- @param node_name Name of node to make cube of.
-- @param hollow Whether the cube should be hollow.
-- @return The number of nodes added.
function worldedit.cube(pos, width, height, length, node_name, hollow)
-- Set up voxel manipulator
local basepos = vector.subtract(pos, {x=math.floor(width/2), y=0, z=math.floor(length/2)})
local manip, area = mh.init(basepos, vector.add(basepos, {x=width, y=height, z=length}))
local data = mh.get_empty_data(area)
-- Add cube
local node_id = minetest.get_content_id(node_name)
local stride = {x=1, y=area.ystride, z=area.zstride}
local offset = vector.subtract(basepos, area.MinEdge)
local count = 0
for z = 0, length-1 do
local index_z = (offset.z + z) * stride.z + 1 -- +1 for 1-based indexing
for y = 0, height-1 do
local index_y = index_z + (offset.y + y) * stride.y
for x = 0, width-1 do
local is_wall = z == 0 or z == length-1
or y == 0 or y == height-1
or x == 0 or x == width-1
if not hollow or is_wall then
local i = index_y + (offset.x + x)
data[i] = node_id
count = count + 1
end
end
end
end
mh.finish(manip, data)
return count
end
--- Adds a sphere of `node_name` centered at `pos`.
-- @param pos Position to center sphere at.
-- @param radius Sphere radius.
@ -133,60 +92,49 @@ end
-- @param pos Position to center base of cylinder at.
-- @param axis Axis ("x", "y", or "z")
-- @param length Cylinder length.
-- @param radius1 Cylinder base radius.
-- @param radius2 Cylinder top radius.
-- @param radius Cylinder radius.
-- @param node_name Name of node to make cylinder of.
-- @param hollow Whether the cylinder should be hollow.
-- @return The number of nodes added.
function worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
function worldedit.cylinder(pos, axis, length, radius, node_name, hollow)
local other1, other2 = worldedit.get_axis_others(axis)
-- Backwards compatibility
if type(radius2) == "string" then
hollow = node_name
node_name = radius2
radius2 = radius1 -- straight cylinder
end
-- Handle negative lengths
local current_pos = {x=pos.x, y=pos.y, z=pos.z}
if length < 0 then
length = -length
current_pos[axis] = current_pos[axis] - length
radius1, radius2 = radius2, radius1
end
-- Set up voxel manipulator
local manip, area = mh.init_axis_radius_length(current_pos, axis, math.max(radius1, radius2), length)
local manip, area = mh.init_axis_radius_length(current_pos, axis, radius, length)
local data = mh.get_empty_data(area)
-- Add desired shape (anything inbetween cylinder & cone)
-- Add cylinder
local node_id = minetest.get_content_id(node_name)
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
local stride = {x=1, y=area.ystride, z=area.zstride}
local offset = {
x = current_pos.x - area.MinEdge.x,
y = current_pos.y - area.MinEdge.y,
z = current_pos.z - area.MinEdge.z,
}
local min_slice, max_slice = offset[axis], offset[axis] + length - 1
local count = 0
for i = 0, length - 1 do
-- Calulate radius for this "height" in the cylinder
local radius = radius1 + (radius2 - radius1) * (i + 1) / length
radius = math.floor(radius + 0.5) -- round
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
for index2 = -radius, radius do
-- Offset contributed by other axis 1 plus 1 to make it 1-indexed
local new_index2 = (index2 + offset[other1]) * stride[other1] + 1
for index3 = -radius, radius do
local new_index3 = new_index2 + (index3 + offset[other2]) * stride[other2]
local squared = index2 * index2 + index3 * index3
if squared <= max_radius and (not hollow or squared >= min_radius) then
-- Position is in cylinder, add node here
local vi = new_index3 + (offset[axis] + i) * stride[axis]
for index2 = -radius, radius do
-- Offset contributed by other axis 1 plus 1 to make it 1-indexed
local new_index2 = (index2 + offset[other1]) * stride[other1] + 1
for index3 = -radius, radius do
local new_index3 = new_index2 + (index3 + offset[other2]) * stride[other2]
local squared = index2 * index2 + index3 * index3
if squared <= max_radius and (not hollow or squared >= min_radius) then
-- Position is in cylinder
-- Add column along axis
for index1 = min_slice, max_slice do
local vi = new_index3 + index1 * stride[axis]
data[vi] = node_id
count = count + 1
end
count = count + length
end
end
end

0
worldedit/visualization.lua Normal file → Executable file
View File

0
worldedit_commands/depends.txt Normal file → Executable file
View File

View File

@ -23,7 +23,6 @@ local function get_position(name) --position 1 retrieval function for when not u
return pos1
end
-- normalize_nodename wrapper for convenience purposes
local function get_node(name, nodename)
local node = worldedit.normalize_nodename(nodename)
if not node then
@ -37,46 +36,26 @@ function worldedit.player_notify(name, message)
minetest.chat_send_player(name, "WorldEdit -!- " .. message, false)
end
local function string_endswith(full, part)
return full:find(part, 1, true) == #full - #part + 1
end
-- normalizes node "description" `nodename`, returning a string (or nil)
--determines whether `nodename` is a valid node name, returning a boolean
worldedit.normalize_nodename = function(nodename)
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
nodename = nodename:gsub("^%s*(.-)%s*$", "%1")
if nodename == "" then return nil end
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
local fullname = ItemStack({name=nodename}):get_name() --resolve aliases of node names to full names
if minetest.registered_nodes[fullname] or fullname == "air" then --directly found node name or alias of nodename
return fullname
end
for key, value in pairs(minetest.registered_nodes) do
if string_endswith(key, ":" .. nodename) then -- matches name (w/o mod part)
if key:find(":" .. nodename, 1, true) then --found in mod
return key
end
end
nodename = nodename:lower() -- lowercase both for case insensitive comparison
nodename = nodename:lower() --lowercase both for case insensitive comparison
for key, value in pairs(minetest.registered_nodes) do
local desc = value.description:lower()
if desc == nodename then -- matches description
return key
end
if string_endswith(desc, " block") and desc == nodename.." block" then
-- fuzzy description match (e.g. "Steel" == "Steel Block")
if value.description:lower() == nodename then --found in description
return key
end
end
local match = nil
for key, value in pairs(minetest.registered_nodes) do
if value.description:lower():find(nodename, 1, true) ~= nil then
if match ~= nil then
return nil
end
match = key -- substring description match (only if no ambiguities)
end
end
return match
return nil
end
-- Determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
@ -398,29 +377,13 @@ minetest.register_chatcommand("/set", {
privs = {worldedit=true},
func = safe_region(function(name, param)
local node = get_node(name, param)
if not node then return end
local count = worldedit.set(worldedit.pos1[name], worldedit.pos2[name], node)
worldedit.player_notify(name, count .. " nodes set")
end, check_region),
})
minetest.register_chatcommand("/param2", {
params = "<param2>",
description = "Set param2 of all nodes in the current WorldEdit region to <param2>",
privs = {worldedit=true},
func = safe_region(function(name, param)
local param2 = tonumber(param)
if not param2 then
worldedit.player_notify(name, "Invalid or missing param2 argument")
return
elseif param2 < 0 or param2 > 255 then
worldedit.player_notify(name, "Param2 is out of range (must be between 0 and 255 inclusive)!")
if not node then
worldedit.player_notify(name, "Could not identify node \"" .. param .. "\"")
return
end
local count = worldedit.set_param2(worldedit.pos1[name], worldedit.pos2[name], param2)
worldedit.player_notify(name, count .. " nodes altered")
local count = worldedit.set(worldedit.pos1[name], worldedit.pos2[name], node)
worldedit.player_notify(name, count .. " nodes set")
end, check_region),
})
@ -432,7 +395,10 @@ minetest.register_chatcommand("/mix", {
local nodes = {}
for nodename in param:gmatch("[^%s]+") do
local node = get_node(name, nodename)
if not node then return end
if not node then
worldedit.player_notify(name, "Could not identify node \"" .. name .. "\"")
return
end
nodes[#nodes + 1] = node
end
@ -489,45 +455,6 @@ minetest.register_chatcommand("/replaceinverse", {
end, check_replace),
})
local check_cube = function(name, param)
if worldedit.pos1[name] == nil then
worldedit.player_notify(name, "no position 1 selected")
return nil
end
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
worldedit.player_notify(name, "invalid usage: " .. param)
return nil
end
local node = get_node(name, nodename)
if not node then return nil end
return tonumber(w) * tonumber(h) * tonumber(l)
end
minetest.register_chatcommand("/hollowcube", {
params = "<width> <height> <length> <node>",
description = "Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
local node = get_node(name, nodename)
local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node, true)
worldedit.player_notify(name, count .. " nodes added")
end, check_cube),
})
minetest.register_chatcommand("/cube", {
params = "<width> <height> <length> <node>",
description = "Add a cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
local node = get_node(name, nodename)
local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node)
worldedit.player_notify(name, count .. " nodes added")
end, check_cube),
})
local check_sphere = function(name, param)
if worldedit.pos1[name] == nil then
worldedit.player_notify(name, "no position 1 selected")
@ -611,65 +538,46 @@ local check_cylinder = function(name, param)
worldedit.player_notify(name, "no position 1 selected")
return nil
end
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
if found == nil then
worldedit.player_notify(name, "invalid usage: " .. param)
return nil
end
local node = get_node(name, nodename)
if not node then return nil end
local radius = math.max(tonumber(radius1), tonumber(radius2))
return math.ceil(math.pi * (radius ^ 2) * tonumber(length))
return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length))
end
minetest.register_chatcommand("/hollowcylinder", {
params = "x/y/z/? <length> <radius1> [radius2] <node>",
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>",
params = "x/y/z/? <length> <radius> <node>",
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
privs = {worldedit=true},
func = safe_region(function(name, param)
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
length = tonumber(length)
if axis == "?" then
axis, sign = worldedit.player_axis(name)
length = length * sign
end
local node = get_node(name, nodename)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node, true)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node, true)
worldedit.player_notify(name, count .. " nodes added")
end, check_cylinder),
})
minetest.register_chatcommand("/cylinder", {
params = "x/y/z/? <length> <radius1> [radius2] <node>",
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>",
params = "x/y/z/? <length> <radius> <node>",
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
privs = {worldedit=true},
func = safe_region(function(name, param)
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
length = tonumber(length)
if axis == "?" then
axis, sign = worldedit.player_axis(name)
length = length * sign
end
local node = get_node(name, nodename)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node)
worldedit.player_notify(name, count .. " nodes added")
end, check_cylinder),
})
@ -1218,10 +1126,8 @@ minetest.register_chatcommand("/lua", {
local err = worldedit.lua(param)
if err then
worldedit.player_notify(name, "code error: " .. err)
minetest.log("action", name.." tried to execute "..param)
else
worldedit.player_notify(name, "code successfully executed", false)
minetest.log("action", name.." executed "..param)
end
end,
})
@ -1234,10 +1140,8 @@ minetest.register_chatcommand("/luatransform", {
local err = worldedit.luatransform(worldedit.pos1[name], worldedit.pos2[name], param)
if err then
worldedit.player_notify(name, "code error: " .. err, false)
minetest.log("action", name.." tried to execute luatransform "..param)
else
worldedit.player_notify(name, "code successfully executed", false)
minetest.log("action", name.." executed luatransform "..param)
end
end),
})

82
worldedit_gui/functionality.lua Normal file → Executable file
View File

@ -1,6 +1,6 @@
--saved state for each player
local gui_nodename1 = {} --mapping of player names to node names
local gui_nodename2 = {} --mapping of player names to node names
local gui_nodename1 = {} --mapping of player names to node names (arbitrary strings may also appear as values)
local gui_nodename2 = {} --mapping of player names to node names (arbitrary strings may also appear as values)
local gui_axis1 = {} --mapping of player names to axes (one of 1, 2, 3, or 4, representing the axes in the `axis_indices` table below)
local gui_axis2 = {} --mapping of player names to axes (one of 1, 2, 3, or 4, representing the axes in the `axis_indices` table below)
local gui_distance1 = {} --mapping of player names to a distance (arbitrary strings may also appear as values)
@ -10,7 +10,9 @@ local gui_count1 = {} --mapping of player names to a quantity (arbitrary strings
local gui_count2 = {} --mapping of player names to a quantity (arbitrary strings may also appear as values)
local gui_count3 = {} --mapping of player names to a quantity (arbitrary strings may also appear as values)
local gui_angle = {} --mapping of player names to an angle (one of 90, 180, 270, representing the angle in degrees clockwise)
local gui_filename = {} --mapping of player names to file names
local gui_filename = {} --mapping of player names to file names (arbitrary strings may also appear as values)
local gui_formspec = {} --mapping of player names to formspecs
local gui_code = {} --mapping of player names to formspecs
--set default values
setmetatable(gui_nodename1, {__index = function() return "Cobblestone" end})
@ -25,6 +27,8 @@ setmetatable(gui_count2, {__index = function() return "6" end})
setmetatable(gui_count3, {__index = function() return "4" end})
setmetatable(gui_angle, {__index = function() return 90 end})
setmetatable(gui_filename, {__index = function() return "building" end})
setmetatable(gui_formspec, {__index = function() return "size[5,5]\nlabel[0,0;Hello, world!]" end})
setmetatable(gui_code, {__index = function() return "minetest.chat_send_player(\"singleplayer\", \"Hello, world!\")" end})
local axis_indices = {["X axis"]=1, ["Y axis"]=2, ["Z axis"]=3, ["Look direction"]=4}
local axis_values = {"x", "y", "z", "?"}
@ -288,21 +292,17 @@ worldedit.register_gui_function("worldedit_gui_cylinder", {
name = "Cylinder",
privs = combine_we_privs({"hollowcylinder", "cylinder"}),
get_formspec = function(name)
local node, axis, length = gui_nodename1[name], gui_axis1[name], gui_distance1[name]
local radius1, radius2 = gui_distance2[name], gui_distance3[name]
local node, axis, length, radius = gui_nodename1[name], gui_axis1[name], gui_distance1[name], gui_distance2[name]
local nodename = worldedit.normalize_nodename(node)
return "size[6.5,6]" .. worldedit.get_formspec_header("worldedit_gui_cylinder") ..
return "size[6.5,5]" .. worldedit.get_formspec_header("worldedit_gui_cylinder") ..
string.format("field[0.5,1.5;4,0.8;worldedit_gui_cylinder_node;Name;%s]", minetest.formspec_escape(node)) ..
"button[4,1.18;1.5,0.8;worldedit_gui_cylinder_search;Search]" ..
formspec_node("5.5,1.1", nodename) ..
string.format("field[0.5,2.5;4,0.8;worldedit_gui_cylinder_length;Length;%s]", minetest.formspec_escape(length)) ..
string.format("dropdown[4,2.18;2.5;worldedit_gui_cylinder_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) ..
string.format("field[0.5,3.5;2,0.8;worldedit_gui_cylinder_radius1;Base Radius;%s]", minetest.formspec_escape(radius1)) ..
string.format("field[2.5,3.5;2,0.8;worldedit_gui_cylinder_radius2;Top Radius;%s]", minetest.formspec_escape(radius2)) ..
"label[0.25,4;Equal base and top radius creates a cylinder,\n"..
"zero top radius creates a cone.\nConsult documentation for more information.]"..
"button_exit[0,5.5;3,0.8;worldedit_gui_cylinder_submit_hollow;Hollow Cylinder]" ..
"button_exit[3.5,5.5;3,0.8;worldedit_gui_cylinder_submit_solid;Solid Cylinder]"
string.format("field[0.5,3.5;4,0.8;worldedit_gui_cylinder_radius;Radius;%s]", minetest.formspec_escape(radius)) ..
"button_exit[0,4.5;3,0.8;worldedit_gui_cylinder_submit_hollow;Hollow Cylinder]" ..
"button_exit[3.5,4.5;3,0.8;worldedit_gui_cylinder_submit_solid;Solid Cylinder]"
end,
})
@ -312,8 +312,7 @@ worldedit.register_gui_handler("worldedit_gui_cylinder", function(name, fields)
gui_nodename1[name] = tostring(fields.worldedit_gui_cylinder_node)
gui_axis1[name] = axis_indices[fields.worldedit_gui_cylinder_axis]
gui_distance1[name] = tostring(fields.worldedit_gui_cylinder_length)
gui_distance2[name] = tostring(fields.worldedit_gui_cylinder_radius1)
gui_distance3[name] = tostring(fields.worldedit_gui_cylinder_radius2)
gui_distance2[name] = tostring(fields.worldedit_gui_cylinder_radius)
worldedit.show_page(name, "worldedit_gui_cylinder")
local submit = nil
@ -325,8 +324,7 @@ worldedit.register_gui_handler("worldedit_gui_cylinder", function(name, fields)
if submit then
local n = worldedit.normalize_nodename(gui_nodename1[name])
if n then
local args = string.format("%s %s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], gui_distance3[name], n)
minetest.chatcommands["/"..submit].func(name, args)
minetest.chatcommands["/"..submit].func(name, string.format("%s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], n))
end
end
return true
@ -735,46 +733,26 @@ worldedit.register_gui_handler("worldedit_gui_save_load", function(name, fields)
return false
end)
worldedit.register_gui_function("worldedit_gui_cube", {
name = "Cuboid", -- technically the command is misnamed, I know...
privs = combine_we_privs({"hollowcube", "cube"}),
worldedit.register_gui_function("worldedit_gui_lua", {
name = "Run Lua", privs = minetest.chatcommands["/clearobjects"].privs,
privs = we_privs("lua"),
get_formspec = function(name)
local width, height, length = gui_distance1[name], gui_distance2[name], gui_distance3[name]
local node = gui_nodename1[name]
local nodename = worldedit.normalize_nodename(node)
return "size[6.5,4]" .. worldedit.get_formspec_header("worldedit_gui_cube") ..
string.format("field[0.5,1.5;4,0.8;worldedit_gui_cube_node;Name;%s]", minetest.formspec_escape(node)) ..
"button[4,1.18;1.5,0.8;worldedit_gui_cube_search;Search]" ..
formspec_node("5.5,1.1", nodename) ..
string.format("field[0.5,2.5;1,0.8;worldedit_gui_cube_width;Width;%s]", minetest.formspec_escape(width)) ..
string.format("field[1.5,2.5;1,0.8;worldedit_gui_cube_height;Height;%s]", minetest.formspec_escape(height)) ..
string.format("field[2.5,2.5;1,0.8;worldedit_gui_cube_length;Length;%s]", minetest.formspec_escape(length)) ..
"button_exit[0,3.5;3,0.8;worldedit_gui_cube_submit_hollow;Hollow Cuboid]" ..
"button_exit[3.5,3.5;3,0.8;worldedit_gui_cube_submit_solid;Solid Cuboid]"
local code = gui_code[name]
return "size[8,6.5]" .. worldedit.get_formspec_header("worldedit_gui_lua") ..
string.format("textarea[0.5,1;7.5,5.5;worldedit_gui_lua_code;Lua Code;%s]", minetest.formspec_escape(code)) ..
"button_exit[0,6;3,0.8;worldedit_gui_lua_run;Run Lua]" ..
"button_exit[5,6;3,0.8;worldedit_gui_lua_transform;Lua Transform]"
end,
})
worldedit.register_gui_handler("worldedit_gui_cube", function(name, fields)
if fields.worldedit_gui_cube_search
or fields.worldedit_gui_cube_submit_hollow or fields.worldedit_gui_cube_submit_solid then
gui_nodename1[name] = tostring(fields.worldedit_gui_cube_node)
gui_distance1[name] = tostring(fields.worldedit_gui_cube_width)
gui_distance2[name] = tostring(fields.worldedit_gui_cube_height)
gui_distance3[name] = tostring(fields.worldedit_gui_cube_length)
worldedit.show_page(name, "worldedit_gui_cube")
local submit = nil
if fields.worldedit_gui_cube_submit_hollow then
submit = "hollowcube"
elseif fields.worldedit_gui_cube_submit_solid then
submit = "cube"
end
if submit then
local n = worldedit.normalize_nodename(gui_nodename1[name])
if n then
local args = string.format("%s %s %s %s", gui_distance1[name], gui_distance2[name], gui_distance3[name], n)
minetest.chatcommands["/"..submit].func(name, args)
end
worldedit.register_gui_handler("worldedit_gui_lua", function(name, fields)
if fields.worldedit_gui_lua_run or fields.worldedit_gui_lua_transform then
gui_code[name] = fields.worldedit_gui_lua_code
worldedit.show_page(name, "worldedit_gui_lua")
if fields.worldedit_gui_lua_run then
minetest.chatcommands["/lua"].func(name, gui_code[name])
else --fields.worldedit_gui_lua_transform
minetest.chatcommands["/luatransform"].func(name, gui_code[name])
end
return true
end

96
worldedit_gui/init.lua Normal file → Executable file
View File

@ -80,6 +80,8 @@ if rawget(_G, "unified_inventory") then --unified inventory installed
unified_inventory.register_button("worldedit_gui", {
type = "image",
image = "inventory_plus_worldedit_gui.png",
tooltip = "Worldedit GUI",
show_with = "worldedit", --Modiff MFF (Crabman 30/06/2015)
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
@ -145,21 +147,13 @@ elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0
end
})
--compatibility with pre-0.4.16 sfinv
local set_page = sfinv.set_page or function(player, name)
--assumptions: src pg has no leave callback, dst pg has no enter callback
local ctx = {page=name}
sfinv.contexts[player:get_player_name()] = ctx
sfinv.set_player_inventory_formspec(player, ctx)
end
--show the form when the button is pressed and hide it when done
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.worldedit_gui then --main page
worldedit.show_page(player:get_player_name(), "worldedit_gui")
return true
elseif fields.worldedit_gui_exit then --return to original page
set_page(player, "sfinv:crafting")
sfinv.set_page(player, "sfinv:crafting")
return true
end
return false
@ -171,14 +165,82 @@ elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0
player:set_inventory_formspec(get_formspec(name, page))
end
end
else
error(
"worldedit_gui requires a supported \"gui management\" mod to be installed\n"..
"To use the GUI you need to either\n"..
"* Use minetest_game (at least 0.4.15) or a subgame with compatible sfinv\n"..
"* Install Unified Inventory or Inventory++\n"..
"If you do not want to use worldedit_gui, disable it by editing world.mt or from the Main Menu"
)
else --fallback button
-- FIXME: this is a huge clusterfuck and the back button is broken
local player_formspecs = {}
local update_main_formspec = function(name)
local formspec = player_formspecs[name]
if not formspec then
return
end
local player = minetest.get_player_by_name(name)
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 then --creative 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;]"
else
return
end
else
formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
end
player:set_inventory_formspec(formspec)
end
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
minetest.after(1, function()
if minetest.get_player_by_name(name) then --ensure the player is still signed in
player_formspecs[name] = player:get_inventory_formspec()
minetest.after(0.01, function()
update_main_formspec(name)
end)
end
end)
end)
minetest.register_on_leaveplayer(function(player)
player_formspecs[player:get_player_name()] = nil
end)
local gui_player_formspecs = {}
minetest.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
if fields.worldedit_gui then --main page
gui_player_formspecs[name] = player:get_inventory_formspec()
worldedit.show_page(name, "worldedit_gui")
return true
elseif fields.worldedit_gui_exit then --return to original page
if gui_player_formspecs[name] then
player:set_inventory_formspec(gui_player_formspecs[name])
end
return true
else --deal with creative_inventory setting the formspec on every single message
minetest.after(0.01,function()
update_main_formspec(name)
end)
return false --continue processing in creative inventory
end
end)
worldedit.show_page = function(name, page)
local player = minetest.get_player_by_name(name)
if player then
player:set_inventory_formspec(get_formspec(name, page))
end
end
end
worldedit.register_gui_function("worldedit_gui", {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 25 KiB

1
worldedit_infinity/depends.txt Executable file
View File

@ -0,0 +1 @@
worldedit?

103
worldedit_infinity/init.lua Executable file
View File

@ -0,0 +1,103 @@
worldedit = rawget(_G, "worldedit") or {}
local minetest = minetest --local copy of global
local get_pointed = function(pos, nearest, distance)
if distance > 100 then
return false
end
--check for collision with node
local nodename = minetest.get_node(pos).name
if nodename ~= "air"
and nodename ~= "default:water_source"
and nodename ~= "default:water_flowing" then
if nodename ~= "ignore" then
return nearest
end
return false
end
end
local use = function(itemstack, user, pointed_thing)
if pointed_thing.type == "nothing" then --pointing at nothing
local placepos = worldedit.raytrace(user:getpos(), user:get_look_dir(), get_pointed)
if placepos then --extended reach
pointed_thing.type = "node"
pointed_thing.under = nil --wip
pointed_thing.above = nil --wip
end
end
return minetest.item_place_node(itemstack, user, pointed_thing)
end
--
worldedit.raytrace = function(pos, dir, callback)
local base = {x=math.floor(pos.x), y=math.floor(pos.y), z=math.floor(pos.z)}
local stepx, stepy, stepz = 0, 0, 0
local componentx, componenty, componentz = 0, 0, 0
local intersectx, intersecty, intersectz = 0, 0, 0
if dir.x == 0 then
intersectx = math.huge
elseif dir.x > 0 then
stepx = 1
componentx = 1 / dir.x
intersectx = ((base.x - pos.x) + 1) * componentx
else
stepx = -1
componentx = 1 / -dir.x
intersectx = (pos.x - base.x) * componentx
end
if dir.y == 0 then
intersecty = math.huge
elseif dir.y > 0 then
stepy = 1
componenty = 1 / dir.y
intersecty = ((base.y - pos.y) + 1) * componenty
else
stepy = -1
componenty = 1 / -dir.y
intersecty = (pos.y - base.y) * componenty
end
if dir.z == 0 then
intersectz = math.huge
elseif dir.z > 0 then
stepz = 1
componentz = 1 / dir.z
intersectz = ((base.z - pos.z) + 1) * componentz
else
stepz = -1
componentz = 1 / -dir.z
intersectz = (pos.z - base.z) * componentz
end
local distance = 0
local nearest = {x=base.x, y=base.y, z=base.z}
while true do
local values = {callback(base, nearest, distance)}
if #values > 0 then
return unpack(values)
end
nearest.x, nearest.y, nearest.z = base.x, base.y, base.z
if intersectx < intersecty then
if intersectx < intersectz then
base.x = base.x + stepx
distance = intersectx
intersectx = intersectx + componentx
else
base.z = base.z + stepz
distance = intersectz
intersectz = intersectz + componentz
end
elseif intersecty < intersectz then
base.y = base.y + stepy
distance = intersecty
intersecty = intersecty + componenty
else
base.z = base.z + stepz
distance = intersectz
intersectz = intersectz + componentz
end
end
end

1
worldedit_limited/depends.txt Executable file
View File

@ -0,0 +1 @@
worldedit

120
worldedit_limited/init.lua Executable file
View File

@ -0,0 +1,120 @@
do return end
do
local MAX_VOLUME = 30 * 30 * 30
local we = worldedit
local volume = we.volume
local safewrap = function(func)
return function(pos1, pos2, ...)
if validbox(pos1, pos2) then
return func(pos1, pos2, ...)
end
return 0, pos1, pos2
end
end
local validbox = function(pos1, pos2)
tpos1, tpos2 = we.sort_pos(pos1, pos2)
if volume(tpos1, tpos2) > MAX_VOLUME then
return false
end
--check for ownership of area if ownership mod is installed
if owner_defs then
local inside = false
for _, def in pairs(owner_defs) do
--sort positions
local tdef = {x1=def.x1, x2 = def.x2, y1=def.y1, y2=def.y2, z1=def.z1, z2=def.z2}
if tdef.x1 > tdef.x2 then
tdef.x1, tdef.x2 = tdef.x2, tdef.x1
end
if tdef.y1 > tdef.y2 then
tdef.y1, tdef.y2 = tdef.y2, tdef.y1
end
if tdef.z1 > tdef.z2 then
tdef.z1, tdef.z2 = tdef.z2, tdef.z1
end
--check ownership
if tpos1.x >= tdef.x1 and tpos1.x <= tdef.x2
and tpos2.x >= tdef.x1 and tpos2.x <= tdef.x2
and tpos1.y >= tdef.y1 and tpos1.y <= tdef.y2
and tpos2.y >= tdef.y1 and tpos2.y <= tdef.y2
and tpos1.z >= tdef.z1 and tpos1.z <= tdef.z2
and tpos2.z >= tdef.z1 and tpos2.z <= tdef.z2
and name == def.owner then --wip: name isn't available here
inside = true
break
end
end
if not inside then
return false
end
end
return true
end
worldedit = {
sort_pos = we.sort_pos,
set = safewrap(we.set),
replace = safewrap(we.replace),
replaceinverse = safewrap(we.replaceinverse),
copy = function(pos1, pos2, axis, amount)
tpos1, tpos2 = we.sort_pos(pos1, pos2)
tpos1[axis] = tpos1[axis] + amount
tpos2[axis] = tpos2[axis] + amount
if validbox(pos1, pos2) and validbox(tpos1, tpos2) then
we.copy(pos1, pos2, axis, amount)
else
return 0
end
end,
move = function(pos1, pos2, axis, amount)
tpos1, tpos2 = we.sort_pos(pos1, pos2)
tpos1[axis] = tpos1[axis] + amount
tpos2[axis] = tpos2[axis] + amount
if validbox(pos1, pos2) and validbox(tpos1, tpos2) then
we.move(pos1, pos2, axis, amount)
else
return 0
end
end,
stack = function(pos1, pos2, axis, count)
tpos1, tpos2 = we.sort_pos(pos1, pos2)
local length = (tpos2[axis] - tpos1[axis] + 1) * count
if count < 0 then
tpos1[axis] = tpos1[axis] + length
else
tpos2[axis] = tpos2[axis] + length
end
if validbox(tpos1, tpos2) then
we.stack(pos1, pos2, axis, amount)
else
return 0
end
end,
--wip: add transpose, rotate safely
flip = safewrap(we.flip),
orient = safewrap(we.orient),
fixlight = safewrap(we.fixlight),
--wip: add primitives here
volume = we.volume,
hide = safewrap(we.hide),
suppress = safewrap(we.suppress),
highlight = safewrap(we.highlight),
restore = safewrap(we.restore),
serialize = safewrap(we.serialize),
allocate = we.allocate,
deserialize = function(originpos, value)
local tpos1, tpos2 = we.allocate(originpos, value)
if validbox(tpos1, tpos2) then
we.deserialize(originpos, value)
else
return 0
end
end,
}
end

0
worldedit_shortcommands/depends.txt Normal file → Executable file
View File

1
worldedit_shortcommands/init.lua Normal file → Executable file
View File

@ -25,7 +25,6 @@ worldedit.alias_chatcommand("/v", "/volume")
worldedit.alias_chatcommand("/s", "/set")
worldedit.alias_chatcommand("/r", "/replace")
worldedit.alias_chatcommand("/ri", "/replaceinverse")
worldedit.alias_chatcommand("/hcube", "/hollowcube")
worldedit.alias_chatcommand("/hspr", "/hollowsphere")
worldedit.alias_chatcommand("/spr", "/sphere")
worldedit.alias_chatcommand("/hdo", "/hollowdome")