forked from mtcontrib/Minetest-WorldEdit
Compare commits
99 Commits
Author | SHA1 | Date | |
---|---|---|---|
59dc2d34d9 | |||
283f47f10d | |||
35ad2f031d | |||
d572d769ce | |||
5bbb6b3909 | |||
d6a9b517b5 | |||
3c61759bae | |||
2f4eb19a3a | |||
2cb3fcde66 | |||
e680d8087e | |||
870873ad15 | |||
e356f4521c | |||
bf8e2a8233 | |||
6ceb56c3dc | |||
1fabe60d77 | |||
acc9188828 | |||
3240167b13 | |||
66b1fa032d | |||
a31f955fb1 | |||
38e9b42caf | |||
ea465f8fe4 | |||
0ce45a5900 | |||
56f77a2f27 | |||
610cd9981d | |||
c0f3bb6958 | |||
e49f717000 | |||
6e7b9a60be | |||
bcac45a476 | |||
426f3b949f | |||
78e4ba828e | |||
92fe95fab7 | |||
3a7fb5bf1e | |||
aa0e46d4e2 | |||
83288c969e | |||
f9311b2b15 | |||
15f0cea72e | |||
6e2e2385e9 | |||
152707a322 | |||
d040d324e8 | |||
df6b54d2f5 | |||
5abe1cee3d | |||
5afea424ba | |||
2aed498849 | |||
0b68b2aec6 | |||
f72abdb766 | |||
e18525d8c9 | |||
78890dde07 | |||
b922097e7a | |||
48f3f59fc3 | |||
f8f1f3b9cc | |||
d5e004be67 | |||
fad021d0ba | |||
f1fe0c6bba | |||
40cee99700 | |||
04d20de4cd | |||
859c6bd12a | |||
240380ff16 | |||
8d213d32a0 | |||
ae29a9f064 | |||
6cf8b92434 | |||
0b97a7c740 | |||
900b2f25aa | |||
f49663902c | |||
d475682d8f | |||
9e087ff995 | |||
b23e92921c | |||
61ab240cea | |||
b06e004d80 | |||
6dddc93ed7 | |||
b99a51f468 | |||
91c5053e67 | |||
f2f714c19e | |||
47712844a3 | |||
2bd4d6fa8f | |||
e9e8de385c | |||
2e2fcfdfa2 | |||
e0a2661700 | |||
7a19c5303b | |||
35b68c481b | |||
51158eca9f | |||
3aa315f134 | |||
3d30588a68 | |||
48f9c6c23f | |||
5f9efb1205 | |||
fc037e9c82 | |||
90d6b3d237 | |||
4bd5d56909 | |||
163dffccb3 | |||
6b2fe397e6 | |||
5c115e282c | |||
ab47385f7b | |||
78915d4a54 | |||
09de34aabf | |||
c1bd4986b0 | |||
bea38a116a | |||
4336e7ca14 | |||
eca54f0851 | |||
b0fbcf197f | |||
b468e24a20 |
@ -17,11 +17,15 @@ 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` |
|
||||
| `//do` | `//dome` |
|
||||
| `//hcyl` | `//hollowcylinder` |
|
||||
| `//cyl` | `//cylinder` |
|
||||
| `//hpyr` | `//hollowpyramid` |
|
||||
| `//pyr` | `//pyramid` |
|
||||
|
||||
### `//about`
|
||||
|
||||
@ -98,6 +102,12 @@ Display the volume of the current WorldEdit region.
|
||||
|
||||
//volume
|
||||
|
||||
### `//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. Note that active entities are not part of a MapBlock and do not get deleted.
|
||||
|
||||
//deleteblocks
|
||||
|
||||
### `//set <node>`
|
||||
|
||||
Set the current WorldEdit region to `<node>`.
|
||||
@ -107,6 +117,10 @@ 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>`, `...`.
|
||||
@ -134,6 +148,19 @@ 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>`.
|
||||
@ -166,24 +193,45 @@ 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> <radius> <node>`
|
||||
### `//hollowcylinder x/y/z/? <length> <radius1> [radius2] <node>`
|
||||
|
||||
Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<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.
|
||||
|
||||
//hollowcylinder x +5 8 Bronze Block
|
||||
//hollowcylinder y 28 10 glass
|
||||
//hollowcylinder z -12 3 mesecons:wire_00000000_off
|
||||
//hollowcylinder ? 2 4 default:stone
|
||||
|
||||
### `//cylinder x/y/z/? <length> <radius> <node>`
|
||||
//hollowcylinder y 10 10 0 walls:cobble
|
||||
//hollowcylinder x 6 0 5 Dirt
|
||||
//hollowcylinder z 20 10 20 default:desert_stone
|
||||
|
||||
Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<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).
|
||||
|
||||
//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>`.
|
||||
|
||||
//hollowpyramid x 8 Diamond Block
|
||||
//hollowpyramid y -5 glass
|
||||
//hollowpyramid z 2 mesecons:wire_00000000_off
|
||||
//hollowpyramid ? 12 mesecons:wire_00000000_off
|
||||
|
||||
### `//pyramid x/y/z? <height> <node>`
|
||||
|
||||
Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height `<height>`, composed of `<node>`.
|
||||
@ -285,6 +333,12 @@ Fixes the lighting in the current WorldEdit region.
|
||||
|
||||
//fixlight
|
||||
|
||||
### `//drain`
|
||||
|
||||
Removes any fluid node within the current WorldEdit region.
|
||||
|
||||
//drain
|
||||
|
||||
### `//hide`
|
||||
|
||||
Hide all nodes in the current WorldEdit region non-destructively.
|
||||
@ -374,3 +428,38 @@ This mode can be left with `//mtschemprob finish`. `//mtschemprob get` will disp
|
||||
Clears all objects within the WorldEdit region.
|
||||
|
||||
//clearobjects
|
||||
|
||||
### `//shift x/y/z/?/up/down/left/right/front/back [+|-]<amount>`
|
||||
|
||||
Shifts the selection area by `[+|-]<amount>` without touching its contents. The shifting axis can be absolute (`x/y/z`) or
|
||||
relative (`up/down/left/right/front/back`).
|
||||
|
||||
//shift left 5
|
||||
|
||||
### `//expand [+|-]x/y/z/?/up/down/left/right/front/back <amount> [reverse-amount]`
|
||||
|
||||
Expands the selection by `<amount>` in the selected absolute or relative axis. If specified, the selection can be expanded in the
|
||||
opposite direction over the same axis by `[reverse-amount]`.
|
||||
|
||||
//expand right 7 5
|
||||
|
||||
### `//contract [+|-]x/y/z/?/up/down/left/right/front/back <amount> [reverse-amount]`
|
||||
|
||||
Contracts the selection by `<amount>` in the selected absolute or relative axis. If specified, the selection can be contracted in the
|
||||
opposite direction over the same axis by `[reverse-amount]`.
|
||||
|
||||
//expand right 7 5
|
||||
|
||||
### `//outset [hv] <amount>`
|
||||
|
||||
Expands the selection in all directions by `<amount>`. If specified, the selection can be expanded horizontally in the x and z axes `[h]`
|
||||
or vertically in the y axis `[v]`.
|
||||
|
||||
//outset v 5
|
||||
|
||||
### `//inset [hv] <amount>`
|
||||
|
||||
Contracts the selection in all directions by `<amount>`. If specified, the selection can be contracted horizontally in the x and z axes `[h]`
|
||||
or vertically in the y axis `[v]`.
|
||||
|
||||
//outset v 5
|
||||
|
21
README.md
21
README.md
@ -1,5 +1,5 @@
|
||||
WorldEdit v1.1 for Minetest 0.4.8+
|
||||
==================================
|
||||
WorldEdit v1.2
|
||||
==============
|
||||
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 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.
|
||||
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.
|
||||
|
||||
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,21 +51,19 @@ 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 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.
|
||||
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).
|
||||
|
||||
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. 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.
|
||||
WorldEdit exposes all significant functionality in a simple Lua interface.
|
||||
|
||||
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")
|
||||
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.
|
||||
|
||||
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 API.md).
|
||||
This API is documented in the [WorldEdit API Reference](WorldEdit%20API.md).
|
||||
|
||||
Axes
|
||||
----
|
||||
@ -141,9 +139,13 @@ 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
|
||||
@ -156,5 +158,4 @@ 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.
|
||||
|
@ -27,6 +27,12 @@ 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`.
|
||||
@ -45,6 +51,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.
|
||||
@ -109,6 +121,12 @@ 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`.
|
||||
@ -121,15 +139,15 @@ 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, radius, node_name, hollow)
|
||||
### count = worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
|
||||
|
||||
Adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `node_name`.
|
||||
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`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = worldedit.pyramid(pos, axis, height, node_name)
|
||||
### count = worldedit.pyramid(pos, axis, height, node_name, hollow)
|
||||
|
||||
Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`.
|
||||
Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`, composed of `node_name`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
|
258
worldedit/cuboid.lua
Normal file
258
worldedit/cuboid.lua
Normal file
@ -0,0 +1,258 @@
|
||||
-- Expands or contracts the cuboid in all axes by amount (positive or negative)
|
||||
worldedit.cuboid_volumetric_expand = function(name, amount)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false, "Undefined cuboid"
|
||||
end
|
||||
|
||||
local delta1 = vector.new()
|
||||
local delta2 = vector.new()
|
||||
local delta_dir1
|
||||
local delta_dir2
|
||||
|
||||
delta1 = vector.add(delta1, amount)
|
||||
delta2 = vector.add(delta2, amount)
|
||||
delta_dir1, delta_dir2 = worldedit.get_expansion_directions(pos1, pos2)
|
||||
delta1 = vector.multiply(delta1, delta_dir1)
|
||||
delta2 = vector.multiply(delta2, delta_dir2)
|
||||
worldedit.pos1[name] = vector.add(pos1, delta1)
|
||||
worldedit.pos2[name] = vector.add(pos2, delta2)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Expands or contracts the cuboid in a single axis by amount (positive or negative)
|
||||
worldedit.cuboid_linear_expand = function(name, axis, direction, amount)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false, "undefined cuboid"
|
||||
end
|
||||
|
||||
if direction ~= 1 and direction ~= -1 then
|
||||
return false, "invalid marker"
|
||||
end
|
||||
|
||||
local marker = worldedit.marker_get_closest_to_axis(name, axis, direction)
|
||||
local deltavect = vector.new()
|
||||
|
||||
if axis == 'x' then
|
||||
deltavect.x = amount * direction
|
||||
elseif axis == 'y' then
|
||||
deltavect.y = amount * direction
|
||||
elseif axis == 'z' then
|
||||
deltavect.z = amount * direction
|
||||
else
|
||||
return false, "invalid axis"
|
||||
end
|
||||
|
||||
worldedit.marker_move(name, marker, deltavect)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Shifts the cuboid by '+-amount' in axis 'axis'
|
||||
worldedit.cuboid_shift = function(name, axis, amount)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false, "undefined cuboid"
|
||||
end
|
||||
|
||||
if axis == 'x' then
|
||||
worldedit.pos1[name].x = pos1.x + amount
|
||||
worldedit.pos2[name].x = pos2.x + amount
|
||||
elseif axis == 'y' then
|
||||
worldedit.pos1[name].y = pos1.y + amount
|
||||
worldedit.pos2[name].y = pos2.y + amount
|
||||
elseif axis == 'z' then
|
||||
worldedit.pos1[name].z = pos1.z + amount
|
||||
worldedit.pos2[name].z = pos2.z + amount
|
||||
else
|
||||
return false, "invalid axis"
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Moves the location of a single marker by adding deltavector
|
||||
worldedit.marker_move = function(name, marker, deltavector)
|
||||
if marker ~= 1 and marker ~= 2 then
|
||||
return false
|
||||
end
|
||||
|
||||
if marker == 1 then
|
||||
local pos = worldedit.pos1[name]
|
||||
worldedit.pos1[name] = vector.add(deltavector, pos)
|
||||
else
|
||||
local pos = worldedit.pos2[name]
|
||||
worldedit.pos2[name] = vector.add(deltavector, pos)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Updates the location ingame of the markers
|
||||
worldedit.marker_update = function(name, marker)
|
||||
if marker == nil then
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
elseif marker == 1 then
|
||||
worldedit.mark_pos1(name)
|
||||
elseif marker == 2 then
|
||||
worldedit.mark_pos2(name)
|
||||
else
|
||||
minetest.debug(
|
||||
"worldedit: Invalid execution of function update_markers")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Returns two vectors with the directions for volumetric expansion
|
||||
worldedit.get_expansion_directions = function(mark1, mark2)
|
||||
if mark1 == nil or mark2 == nil then
|
||||
return
|
||||
end
|
||||
local dir1 = vector.new()
|
||||
local dir2 = vector.new()
|
||||
|
||||
if mark1.x < mark2.x then
|
||||
dir1.x = -1
|
||||
dir2.x = 1
|
||||
else
|
||||
dir1.x = 1
|
||||
dir2.x = -1
|
||||
end
|
||||
if mark1.y < mark2.y then
|
||||
dir1.y = -1
|
||||
dir2.y = 1
|
||||
else
|
||||
dir1.y = 1
|
||||
dir2.y = -1
|
||||
end
|
||||
if mark1.z < mark2.z then
|
||||
dir1.z = -1
|
||||
dir2.z = 1
|
||||
else
|
||||
dir1.z = 1
|
||||
dir2.z = -1
|
||||
end
|
||||
return dir1, dir2
|
||||
end
|
||||
|
||||
|
||||
-- Return the marker that is closest to the player
|
||||
worldedit.marker_get_closest_to_player = function(name)
|
||||
local playerpos = minetest.get_player_by_name(name):getpos()
|
||||
local dist1 = vector.distance(playerpos, worldedit.pos1[name])
|
||||
local dist2 = vector.distance(playerpos, worldedit.pos2[name])
|
||||
|
||||
if dist1 < dist2 then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Returns the closest marker to the specified axis and direction
|
||||
worldedit.marker_get_closest_to_axis = function(name, axis, direction)
|
||||
local pos1 = vector.new()
|
||||
local pos2 = vector.new()
|
||||
|
||||
if direction ~= 1 and direction ~= -1 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if axis == 'x' then
|
||||
pos1.x = worldedit.pos1[name].x * direction
|
||||
pos2.x = worldedit.pos2[name].x * direction
|
||||
if pos1.x > pos2.x then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
elseif axis == 'y' then
|
||||
pos1.y = worldedit.pos1[name].y * direction
|
||||
pos2.y = worldedit.pos2[name].y * direction
|
||||
if pos1.y > pos2.y then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
elseif axis == 'z' then
|
||||
pos1.z = worldedit.pos1[name].z * direction
|
||||
pos2.z = worldedit.pos2[name].z * direction
|
||||
if pos1.z > pos2.z then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Translates up, down, left, right, front, back to their corresponding axes and
|
||||
-- directions according to faced direction
|
||||
worldedit.translate_direction = function(name, direction)
|
||||
local axis, dir = worldedit.player_axis(name)
|
||||
local resaxis, resdir
|
||||
|
||||
if direction == "up" then
|
||||
return 'y', 1
|
||||
end
|
||||
|
||||
if direction == "down" then
|
||||
return 'y', -1
|
||||
end
|
||||
|
||||
if direction == "front" then
|
||||
if axis == "y" then
|
||||
resaxis = nil
|
||||
resdir = nil
|
||||
else
|
||||
resaxis = axis
|
||||
resdir = dir
|
||||
end
|
||||
end
|
||||
|
||||
if direction == "back" then
|
||||
if axis == "y" then
|
||||
resaxis = nil
|
||||
resdir = nil
|
||||
else
|
||||
resaxis = axis
|
||||
resdir = -dir
|
||||
end
|
||||
end
|
||||
|
||||
if direction == "left" then
|
||||
if axis == 'x' then
|
||||
resaxis = 'z'
|
||||
resdir = dir
|
||||
elseif axis == 'z' then
|
||||
resaxis = 'x'
|
||||
resdir = -dir
|
||||
end
|
||||
end
|
||||
|
||||
if direction == "right" then
|
||||
if axis == 'x' then
|
||||
resaxis = 'z'
|
||||
resdir = -dir
|
||||
elseif axis == 'z' then
|
||||
resaxis = 'x'
|
||||
resdir = dir
|
||||
end
|
||||
end
|
||||
|
||||
return resaxis, resdir
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
--- Worldedit.
|
||||
-- @module worldedit
|
||||
-- @release 1.1
|
||||
-- @release 1.2
|
||||
-- @copyright 2013 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote).
|
||||
-- @license GNU Affero General Public License version 3 (AGPLv3)
|
||||
-- @author sfan5
|
||||
@ -8,9 +8,12 @@
|
||||
-- @author Bret O'Donnel (cornernote)
|
||||
-- @author ShadowNinja
|
||||
|
||||
|
||||
worldedit = {}
|
||||
worldedit.version = {1, 1, major=1, minor=1}
|
||||
worldedit.version_string = table.concat(worldedit.version, ".")
|
||||
|
||||
local ver = {major=1, minor=2}
|
||||
worldedit.version = ver
|
||||
worldedit.version_string = string.format("%d.%d", ver.major, ver.minor)
|
||||
|
||||
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."
|
||||
@ -23,7 +26,7 @@ end
|
||||
local path = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local function load_module(path)
|
||||
local file = io.open(path)
|
||||
local file = io.open(path, "r")
|
||||
if not file then return end
|
||||
file:close()
|
||||
return dofile(path)
|
||||
@ -36,6 +39,7 @@ load_module(path .. "/visualization.lua")
|
||||
load_module(path .. "/serialization.lua")
|
||||
load_module(path .. "/code.lua")
|
||||
load_module(path .. "/compatibility.lua")
|
||||
load_module(path .. "/cuboid.lua")
|
||||
|
||||
|
||||
if minetest.setting_getbool("log_mods") then
|
||||
|
@ -38,6 +38,29 @@ 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`.
|
||||
@ -90,7 +113,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
|
||||
@ -164,6 +187,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.
|
||||
@ -503,8 +558,8 @@ function worldedit.orient(pos1, pos2, angle)
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
local count = 0
|
||||
local get_node, get_meta, swap_node = minetest.get_node,
|
||||
minetest.get_meta, minetest.swap_node
|
||||
local set_node, get_node, get_meta, swap_node = minetest.set_node,
|
||||
minetest.get_node, minetest.get_meta, minetest.swap_node
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
@ -543,14 +598,11 @@ end
|
||||
function worldedit.fixlight(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
local vmanip = minetest.get_voxel_manip(pos1, pos2)
|
||||
vmanip:write_to_map()
|
||||
vmanip:update_map() -- this updates the lighting
|
||||
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, "air")
|
||||
local dig_node = minetest.dig_node
|
||||
for _, pos in ipairs(nodes) do
|
||||
dig_node(pos)
|
||||
end
|
||||
return #nodes
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
|
||||
|
@ -4,6 +4,47 @@
|
||||
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.
|
||||
@ -92,49 +133,60 @@ end
|
||||
-- @param pos Position to center base of cylinder at.
|
||||
-- @param axis Axis ("x", "y", or "z")
|
||||
-- @param length Cylinder length.
|
||||
-- @param radius Cylinder radius.
|
||||
-- @param radius1 Cylinder base radius.
|
||||
-- @param radius2 Cylinder top 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, radius, node_name, hollow)
|
||||
function worldedit.cylinder(pos, axis, length, radius1, radius2, 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, radius, length)
|
||||
local manip, area = mh.init_axis_radius_length(current_pos, axis, math.max(radius1, radius2), length)
|
||||
local data = mh.get_empty_data(area)
|
||||
|
||||
-- Add cylinder
|
||||
-- Add desired shape (anything inbetween cylinder & cone)
|
||||
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 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]
|
||||
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]
|
||||
data[vi] = node_id
|
||||
count = count + 1
|
||||
end
|
||||
count = count + length
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -150,14 +202,15 @@ end
|
||||
-- @param axis Axis ("x", "y", or "z")
|
||||
-- @param height Pyramid height.
|
||||
-- @param node_name Name of node to make pyramid of.
|
||||
-- @param hollow Whether the pyramid should be hollow.
|
||||
-- @return The number of nodes added.
|
||||
function worldedit.pyramid(pos, axis, height, node_name)
|
||||
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)
|
||||
local data = mh.get_empty_data()
|
||||
local data = mh.get_empty_data(area)
|
||||
|
||||
-- Handle inverted pyramids
|
||||
local start_axis, end_axis, step
|
||||
@ -177,7 +230,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
|
||||
@ -187,10 +240,12 @@ function worldedit.pyramid(pos, axis, height, node_name)
|
||||
local new_index2 = new_index1 + (index2 + offset[other1]) * stride[other1]
|
||||
for index3 = -size, size do
|
||||
local i = new_index2 + (index3 + offset[other2]) * stride[other2]
|
||||
data[i] = node_id
|
||||
if (not hollow or size - math.abs(index2) < 2 or size - math.abs(index3) < 2) then
|
||||
data[i] = node_id
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
count = count + (size * 2 + 1) ^ 2
|
||||
size = size - 1
|
||||
end
|
||||
|
||||
|
@ -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,
|
||||
@ -159,20 +159,20 @@ local function load_schematic(value)
|
||||
else
|
||||
-- XXX: This is a filthy hack that works surprisingly well - in LuaJIT, `minetest.deserialize` will fail due to the register limit
|
||||
nodes = {}
|
||||
value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1) -- remove the starting and ending values to leave only the node data
|
||||
local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
|
||||
content = content:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1) -- remove the starting and ending values to leave only the node data
|
||||
local escaped = content:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
|
||||
local startpos, startpos1, endpos = 1, 1
|
||||
while true do -- go through each individual node entry (except the last)
|
||||
startpos, endpos = escaped:find("},%s*{", startpos)
|
||||
if not startpos then
|
||||
break
|
||||
end
|
||||
local current = value:sub(startpos1, startpos)
|
||||
local current = content:sub(startpos1, startpos)
|
||||
local entry = minetest.deserialize("return " .. current)
|
||||
table.insert(nodes, entry)
|
||||
startpos, startpos1 = endpos, endpos
|
||||
end
|
||||
local entry = minetest.deserialize("return " .. value:sub(startpos1)) -- process the last entry
|
||||
local entry = minetest.deserialize("return " .. content:sub(startpos1)) -- process the last entry
|
||||
table.insert(nodes, entry)
|
||||
end
|
||||
else
|
||||
|
BIN
worldedit/textures/worldedit_wand.png
Normal file
BIN
worldedit/textures/worldedit_wand.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 442 B |
1
worldedit_commands/.gitignore
vendored
Normal file
1
worldedit_commands/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*~
|
240
worldedit_commands/cuboid.lua
Normal file
240
worldedit_commands/cuboid.lua
Normal file
@ -0,0 +1,240 @@
|
||||
minetest.register_chatcommand("/outset", {
|
||||
params = "[h|v] <amount>",
|
||||
description = "outset the selection",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
|
||||
|
||||
if find == nil then
|
||||
return false, "invalid usage: " .. param
|
||||
end
|
||||
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false,
|
||||
"Undefined region. Region must be defined beforehand."
|
||||
end
|
||||
|
||||
local hv_test = dir:find("[^hv]+")
|
||||
|
||||
if hv_test ~= nil then
|
||||
return false, "Invalid direction."
|
||||
end
|
||||
|
||||
if dir == "" or dir == "hv" or dir == "vh" then
|
||||
assert(worldedit.cuboid_volumetric_expand(name, amount))
|
||||
elseif dir == "h" then
|
||||
assert(worldedit.cuboid_linear_expand(name, 'x', 1, amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'x', -1, amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'z', 1, amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'z', -1, amount))
|
||||
elseif dir == "v" then
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', 1, amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', -1, amount))
|
||||
else
|
||||
return false, "Invalid number of arguments"
|
||||
end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region outset by " .. amount .. " blocks"
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
minetest.register_chatcommand("/inset", {
|
||||
params = "[h|v] <amount>",
|
||||
description = "inset the selection",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
|
||||
|
||||
if find == nil then
|
||||
return false, "invalid usage: " .. param
|
||||
end
|
||||
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false,
|
||||
"Undefined region. Region must be defined beforehand."
|
||||
end
|
||||
|
||||
local hv_test = dir:find("[^hv]+")
|
||||
|
||||
if hv_test ~= nil then
|
||||
return false, "Invalid direction."
|
||||
end
|
||||
|
||||
if dir == "" or dir == "vh" or dir == "hv" then
|
||||
assert(worldedit.cuboid_volumetric_expand(name, -amount))
|
||||
elseif dir == "h" then
|
||||
assert(worldedit.cuboid_linear_expand(name, 'x', 1, -amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'x', -1, -amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'z', 1, -amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'z', -1, -amount))
|
||||
elseif dir == "v" then
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', 1, -amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', -1, -amount))
|
||||
else
|
||||
return false, "Invalid number of arguments"
|
||||
end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region inset by " .. amount .. " blocks"
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
minetest.register_chatcommand("/shift", {
|
||||
params = "[x|y|z|?|up|down|left|right|front|back] [+|-]<amount>",
|
||||
description = "Moves the selection region. Does not move contents.",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
local find, _, direction, amount = param:find("([%?%l]+)%s*([+-]?%d+)")
|
||||
|
||||
if find == nil then
|
||||
worldedit.player_notify(name, "invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
worldedit.player_notify(name,
|
||||
"Undefined region. Region must be defined beforehand.")
|
||||
return
|
||||
end
|
||||
|
||||
local axis, dir
|
||||
if direction == "x" or direction == "y" or direction == "z" then
|
||||
axis, dir = direction, 1
|
||||
elseif direction == "?" then
|
||||
axis, dir = worldedit.player_axis(name)
|
||||
else
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
end
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
end
|
||||
|
||||
assert(worldedit.cuboid_shift(name, axis, amount * dir))
|
||||
worldedit.marker_update(name)
|
||||
|
||||
return true, "Region shifted by " .. amount .. " nodes"
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
minetest.register_chatcommand("/expand", {
|
||||
params = "[+|-]<x|y|z|?|up|down|left|right|front|back> <amount> [reverse-amount]",
|
||||
description = "expand the selection in one or two directions at once",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local find, _, sign, direction, amount,
|
||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
||||
|
||||
if find == nil then
|
||||
worldedit.player_notify(name, "invalid use: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
if worldedit.pos1[name] == nil or worldedit.pos2[name] == nil then
|
||||
worldedit.player_notify(name,
|
||||
"Undefined region. Region must be defined beforehand.")
|
||||
return
|
||||
end
|
||||
|
||||
local absolute = direction:find("[xyz?]")
|
||||
local dir, axis
|
||||
|
||||
if rev_amount == "" then
|
||||
rev_amount = 0
|
||||
end
|
||||
|
||||
if absolute == nil then
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
end
|
||||
else
|
||||
if direction == "?" then
|
||||
axis, dir = worldedit.player_axis(name)
|
||||
else
|
||||
axis = direction
|
||||
dir = 1
|
||||
end
|
||||
end
|
||||
|
||||
if sign == "-" then
|
||||
dir = -dir
|
||||
end
|
||||
|
||||
worldedit.cuboid_linear_expand(name, axis, dir, amount)
|
||||
worldedit.cuboid_linear_expand(name, axis, -dir, rev_amount)
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region expanded by " .. (amount + rev_amount) .. " nodes"
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
minetest.register_chatcommand("/contract", {
|
||||
params = "[+|-]<x|y|z|?|up|down|left|right|front|back> <amount> [reverse-amount]",
|
||||
description = "contract the selection in one or two directions at once",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local find, _, sign, direction, amount,
|
||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
||||
|
||||
if find == nil then
|
||||
worldedit.player_notify(name, "invalid use: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
if worldedit.pos1[name] == nil or worldedit.pos2[name] == nil then
|
||||
worldedit.player_notify(name,
|
||||
"Undefined region. Region must be defined beforehand.")
|
||||
return
|
||||
end
|
||||
|
||||
local absolute = direction:find("[xyz?]")
|
||||
local dir, axis
|
||||
|
||||
if rev_amount == "" then
|
||||
rev_amount = 0
|
||||
end
|
||||
|
||||
if absolute == nil then
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
end
|
||||
else
|
||||
if direction == "?" then
|
||||
axis, dir = worldedit.player_axis(name)
|
||||
else
|
||||
axis = direction
|
||||
dir = 1
|
||||
end
|
||||
end
|
||||
|
||||
if sign == "-" then
|
||||
dir = -dir
|
||||
end
|
||||
|
||||
worldedit.cuboid_linear_expand(name, axis, dir, -amount)
|
||||
worldedit.cuboid_linear_expand(name, axis, -dir, -rev_amount)
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region contracted by " .. (amount + rev_amount) .. " nodes"
|
||||
end,
|
||||
}
|
||||
)
|
@ -10,10 +10,12 @@ if minetest.place_schematic then
|
||||
worldedit.prob_list = {}
|
||||
end
|
||||
|
||||
dofile(minetest.get_modpath("worldedit_commands") .. "/cuboid.lua")
|
||||
dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua")
|
||||
dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua"); safe_region = safe_region or function(callback) return callback end
|
||||
dofile(minetest.get_modpath("worldedit_commands") .. "/wand.lua")
|
||||
local safe_region, check_region, reset_pending = dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua")
|
||||
|
||||
local get_position = function(name) --position 1 retrieval function for when not using `safe_region`
|
||||
local function get_position(name) --position 1 retrieval function for when not using `safe_region`
|
||||
local pos1 = worldedit.pos1[name]
|
||||
if pos1 == nil then
|
||||
worldedit.player_notify(name, "no position 1 selected")
|
||||
@ -21,7 +23,8 @@ local get_position = function(name) --position 1 retrieval function for when not
|
||||
return pos1
|
||||
end
|
||||
|
||||
local get_node = function(name, nodename)
|
||||
-- normalize_nodename wrapper for convenience purposes
|
||||
local function get_node(name, nodename)
|
||||
local node = worldedit.normalize_nodename(nodename)
|
||||
if not node then
|
||||
worldedit.player_notify(name, "invalid node name: " .. nodename)
|
||||
@ -30,34 +33,54 @@ local get_node = function(name, nodename)
|
||||
return node
|
||||
end
|
||||
|
||||
worldedit.player_notify = function(name, message)
|
||||
function worldedit.player_notify(name, message)
|
||||
minetest.chat_send_player(name, "WorldEdit -!- " .. message, false)
|
||||
end
|
||||
|
||||
--determines whether `nodename` is a valid node name, returning a boolean
|
||||
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)
|
||||
worldedit.normalize_nodename = function(nodename)
|
||||
nodename = nodename:gsub("^%s*(.-)%s*$", "%1")
|
||||
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
|
||||
if nodename == "" then return nil end
|
||||
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
|
||||
|
||||
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
|
||||
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
|
||||
return fullname
|
||||
end
|
||||
for key, value in pairs(minetest.registered_nodes) do
|
||||
if key:find(":" .. nodename, 1, true) then --found in mod
|
||||
if string_endswith(key, ":" .. nodename) then -- matches name (w/o mod part)
|
||||
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
|
||||
if value.description:lower() == nodename then --found in description
|
||||
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")
|
||||
return key
|
||||
end
|
||||
end
|
||||
return nil
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
--determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
|
||||
worldedit.player_axis = function(name)
|
||||
-- Determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
|
||||
function worldedit.player_axis(name)
|
||||
local dir = minetest.get_player_by_name(name):get_look_dir()
|
||||
local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)
|
||||
if x > y then
|
||||
@ -70,6 +93,19 @@ worldedit.player_axis = function(name)
|
||||
return "z", dir.z > 0 and 1 or -1
|
||||
end
|
||||
|
||||
local function mkdir(path)
|
||||
if minetest.mkdir then
|
||||
minetest.mkdir(path)
|
||||
else
|
||||
os.execute('mkdir "' .. path .. '"')
|
||||
end
|
||||
end
|
||||
|
||||
local function check_filename(name)
|
||||
return name:find("^[%w%s%^&'@{}%[%],%$=!%-#%(%)%%%.%+~_]+$") ~= nil
|
||||
end
|
||||
|
||||
|
||||
minetest.register_chatcommand("/about", {
|
||||
params = "",
|
||||
description = "Get information about the mod",
|
||||
@ -78,6 +114,56 @@ minetest.register_chatcommand("/about", {
|
||||
end,
|
||||
})
|
||||
|
||||
-- mostly copied from builtin/chatcommands.lua with minor modifications
|
||||
minetest.register_chatcommand("/help", {
|
||||
privs = {},
|
||||
params = "[all/<cmd>]",
|
||||
description = "Get help for WorldEdit commands",
|
||||
func = function(name, param)
|
||||
local function is_we_command(cmd)
|
||||
return cmd:sub(0, 1) == "/"
|
||||
end
|
||||
local function format_help_line(cmd, def)
|
||||
local msg = minetest.colorize("#00ffff", "/"..cmd)
|
||||
if def.params and def.params ~= "" then
|
||||
msg = msg .. " " .. def.params
|
||||
end
|
||||
if def.description and def.description ~= "" then
|
||||
msg = msg .. ": " .. def.description
|
||||
end
|
||||
return msg
|
||||
end
|
||||
|
||||
if not minetest.check_player_privs(name, "worldedit") then
|
||||
return false, "You are not allowed to use any WorldEdit commands."
|
||||
end
|
||||
if param == "" then
|
||||
local msg = ""
|
||||
local cmds = {}
|
||||
for cmd, def in pairs(minetest.chatcommands) do
|
||||
if is_we_command(cmd) and minetest.check_player_privs(name, def.privs) then
|
||||
cmds[#cmds + 1] = cmd:sub(2) -- strip the /
|
||||
end
|
||||
end
|
||||
table.sort(cmds)
|
||||
return true, "Available commands: " .. table.concat(cmds, " ") .. "\n"
|
||||
.. "Use '//help <cmd>' to get more information,"
|
||||
.. " or '//help all' to list everything."
|
||||
elseif param == "all" then
|
||||
local cmds = {}
|
||||
for cmd, def in pairs(minetest.chatcommands) do
|
||||
if is_we_command(cmd) and minetest.check_player_privs(name, def.privs) then
|
||||
cmds[#cmds + 1] = format_help_line(cmd, def)
|
||||
end
|
||||
end
|
||||
table.sort(cmds)
|
||||
return true, "Available commands:\n"..table.concat(cmds, "\n")
|
||||
else
|
||||
return minetest.chatcommands["help"].func(name, "/" .. param)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/inspect", {
|
||||
params = "on/off/1/0/true/false/yes/no/enable/disable/<blank>",
|
||||
description = "Enable or disable node inspection",
|
||||
@ -97,16 +183,28 @@ minetest.register_chatcommand("/inspect", {
|
||||
end,
|
||||
})
|
||||
|
||||
local function get_node_rlight(pos)
|
||||
local vecs = { -- neighboring nodes
|
||||
{x= 1, y= 0, z= 0},
|
||||
{x=-1, y= 0, z= 0},
|
||||
{x= 0, y= 1, z= 0},
|
||||
{x= 0, y=-1, z= 0},
|
||||
{x= 0, y= 0, z= 1},
|
||||
{x= 0, y= 0, z=-1},
|
||||
}
|
||||
local ret = 0
|
||||
for _, v in ipairs(vecs) do
|
||||
ret = math.max(ret, minetest.get_node_light(vector.add(pos, v)))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if worldedit.inspect[name] then
|
||||
if minetest.check_player_privs(name, {worldedit=true}) then
|
||||
local axis, sign = worldedit.player_axis(name)
|
||||
message = string.format("inspector: %s at %s (param1=%d, param2=%d) punched by %s facing the %s axis",
|
||||
node.name, minetest.pos_to_string(pos), node.param1, node.param2, name, axis .. (sign > 0 and "+" or "-"))
|
||||
else
|
||||
message = "inspector: worldedit privileges required"
|
||||
end
|
||||
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",
|
||||
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
|
||||
end)
|
||||
@ -121,6 +219,8 @@ minetest.register_chatcommand("/reset", {
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
worldedit.set_pos[name] = nil
|
||||
--make sure the user does not try to confirm an operation after resetting pos:
|
||||
reset_pending(name)
|
||||
worldedit.player_notify(name, "region reset")
|
||||
end,
|
||||
})
|
||||
@ -277,22 +377,53 @@ minetest.register_chatcommand("/volume", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/deleteblocks", {
|
||||
params = "",
|
||||
description = "remove all MapBlocks (16x16x16) containing the selected area from the map",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local success = minetest.delete_area(pos1, pos2)
|
||||
if success then
|
||||
worldedit.player_notify(name, "Area deleted.")
|
||||
else
|
||||
worldedit.player_notify(name, "There was an error during deletion of the area.")
|
||||
end
|
||||
end),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/set", {
|
||||
params = "<node>",
|
||||
description = "Set the current WorldEdit region to <node>",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
local node = get_node(name, param)
|
||||
if not node then
|
||||
worldedit.player_notify(name, "Could not identify node \"" .. param .. "\"")
|
||||
return
|
||||
end
|
||||
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)!")
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.set_param2(worldedit.pos1[name], worldedit.pos2[name], param2)
|
||||
worldedit.player_notify(name, count .. " nodes altered")
|
||||
end, check_region),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/mix", {
|
||||
params = "<node1> ...",
|
||||
description = "Fill the current WorldEdit region with a random mix of <node1>, ...",
|
||||
@ -301,10 +432,7 @@ minetest.register_chatcommand("/mix", {
|
||||
local nodes = {}
|
||||
for nodename in param:gmatch("[^%s]+") do
|
||||
local node = get_node(name, nodename)
|
||||
if not node then
|
||||
worldedit.player_notify(name, "Could not identify node \"" .. name .. "\"")
|
||||
return
|
||||
end
|
||||
if not node then return end
|
||||
nodes[#nodes + 1] = node
|
||||
end
|
||||
|
||||
@ -361,6 +489,45 @@ 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")
|
||||
@ -444,50 +611,102 @@ local check_cylinder = function(name, param)
|
||||
worldedit.player_notify(name, "no position 1 selected")
|
||||
return nil
|
||||
end
|
||||
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
|
||||
-- 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
|
||||
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 math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length))
|
||||
local radius = math.max(tonumber(radius1), tonumber(radius2))
|
||||
return math.ceil(math.pi * (radius ^ 2) * tonumber(length))
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/hollowcylinder", {
|
||||
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>",
|
||||
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>",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
|
||||
-- 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
|
||||
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(radius), node, true)
|
||||
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node, true)
|
||||
worldedit.player_notify(name, count .. " nodes added")
|
||||
end, check_cylinder),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/cylinder", {
|
||||
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>",
|
||||
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>",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
|
||||
-- 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
|
||||
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(radius), node)
|
||||
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node)
|
||||
worldedit.player_notify(name, count .. " nodes added")
|
||||
end, check_cylinder),
|
||||
})
|
||||
|
||||
local check_pyramid = function(name, param)
|
||||
if worldedit.pos1[name] == nil then
|
||||
worldedit.player_notify(name, "no position 1 selected")
|
||||
return nil
|
||||
end
|
||||
local found, _, axis, height, nodename = param:find("^([xyz%?])%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
|
||||
height = tonumber(height)
|
||||
return math.ceil(((height * 2 + 1) ^ 2) * height / 3)
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/hollowpyramid", {
|
||||
params = "x/y/z/? <height> <node>",
|
||||
description = "Add hollow pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
|
||||
height = tonumber(height)
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
height = height * sign
|
||||
end
|
||||
local node = get_node(name, nodename)
|
||||
local count = worldedit.pyramid(worldedit.pos1[name], axis, height, node, true)
|
||||
worldedit.player_notify(name, count .. " nodes added")
|
||||
end, check_pyramid),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pyramid", {
|
||||
params = "x/y/z/? <height> <node>",
|
||||
description = "Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>",
|
||||
@ -502,22 +721,7 @@ minetest.register_chatcommand("/pyramid", {
|
||||
local node = get_node(name, nodename)
|
||||
local count = worldedit.pyramid(worldedit.pos1[name], axis, height, node)
|
||||
worldedit.player_notify(name, count .. " nodes added")
|
||||
end,
|
||||
function(name, param)
|
||||
if worldedit.pos1[name] == nil then
|
||||
worldedit.player_notify(name, "no position 1 selected")
|
||||
return nil
|
||||
end
|
||||
local found, _, axis, height, nodename = param:find("^([xyz%?])%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
|
||||
height = tonumber(height)
|
||||
return math.ceil(((height * 2 + 1) ^ 2) * height / 3)
|
||||
end),
|
||||
end, check_pyramid),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/spiral", {
|
||||
@ -542,7 +746,7 @@ minetest.register_chatcommand("/spiral", {
|
||||
end
|
||||
local node = get_node(name, nodename)
|
||||
if not node then return nil end
|
||||
return check_region(name, param)
|
||||
return 1 -- TODO: return an useful value
|
||||
end),
|
||||
})
|
||||
|
||||
@ -810,6 +1014,30 @@ minetest.register_chatcommand("/fixlight", {
|
||||
end),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/drain", {
|
||||
params = "",
|
||||
description = "Remove any fluid node within the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
-- TODO: make an API function for this
|
||||
local count = 0
|
||||
local pos1, pos2 = worldedit.sort_pos(worldedit.pos1[name], worldedit.pos2[name])
|
||||
for x = pos1.x, pos2.x do
|
||||
for y = pos1.y, pos2.y do
|
||||
for z = pos1.z, pos2.z do
|
||||
local n = minetest.get_node({x=x, y=y, z=z}).name
|
||||
local d = minetest.registered_nodes[n]
|
||||
if d ~= nil and (d["drawtype"] == "liquid" or d["drawtype"] == "flowingliquid") then
|
||||
minetest.remove_node({x=x, y=y, z=z})
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
worldedit.player_notify(name, count .. " nodes updated")
|
||||
end),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/hide", {
|
||||
params = "",
|
||||
description = "Hide all nodes in the current WorldEdit region non-destructively",
|
||||
@ -861,20 +1089,21 @@ minetest.register_chatcommand("/save", {
|
||||
worldedit.player_notify(name, "invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then
|
||||
worldedit.player_notify(name, "invalid file name: " .. param)
|
||||
if not check_filename(param) then
|
||||
worldedit.player_notify(name, "Disallowed file name: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local result, count = worldedit.serialize(worldedit.pos1[name], worldedit.pos2[name])
|
||||
local result, count = worldedit.serialize(worldedit.pos1[name],
|
||||
worldedit.pos2[name])
|
||||
|
||||
local path = minetest.get_worldpath() .. "/schems"
|
||||
-- Create directory if it does not already exist
|
||||
mkdir(path)
|
||||
|
||||
local filename = path .. "/" .. param .. ".we"
|
||||
filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters
|
||||
os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err ~= nil then
|
||||
worldedit.player_notify(name, "could not save file to \"" .. filename .. "\"")
|
||||
worldedit.player_notify(name, "Could not save file to \"" .. filename .. "\"")
|
||||
return
|
||||
end
|
||||
file:write(result)
|
||||
@ -897,8 +1126,8 @@ minetest.register_chatcommand("/allocate", {
|
||||
worldedit.player_notify(name, "invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then
|
||||
worldedit.player_notify(name, "invalid file name: " .. param)
|
||||
if not check_filename(param) then
|
||||
worldedit.player_notify(name, "Disallowed file name: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
@ -986,16 +1215,13 @@ minetest.register_chatcommand("/lua", {
|
||||
description = "Executes <code> as a Lua chunk in the global namespace",
|
||||
privs = {worldedit=true, server=true},
|
||||
func = function(name, param)
|
||||
local admin = minetest.setting_get("name")
|
||||
if not admin or not name == admin then
|
||||
worldedit.player_notify(name, "this command can only be run by the server administrator")
|
||||
return
|
||||
end
|
||||
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,
|
||||
})
|
||||
@ -1005,41 +1231,44 @@ minetest.register_chatcommand("/luatransform", {
|
||||
description = "Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region",
|
||||
privs = {worldedit=true, server=true},
|
||||
func = safe_region(function(name, param)
|
||||
local admin = minetest.setting_get("name")
|
||||
if not admin or not name == admin then
|
||||
worldedit.player_notify(name, "this command can only be run by the server administrator")
|
||||
return
|
||||
end
|
||||
|
||||
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),
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/mtschemcreate", {
|
||||
params = "<file>",
|
||||
description = "Save the current WorldEdit region using the Minetest Schematic format to \"(world folder)/schems/<filename>.mts\"",
|
||||
description = "Save the current WorldEdit region using the Minetest "..
|
||||
"Schematic format to \"(world folder)/schems/<filename>.mts\"",
|
||||
privs = {worldedit=true},
|
||||
func = safe_region(function(name, param)
|
||||
if param == nil then
|
||||
worldedit.player_notify(name, "No filename specified")
|
||||
return
|
||||
end
|
||||
if not check_filename(param) then
|
||||
worldedit.player_notify(name, "Disallowed file name: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local path = minetest.get_worldpath() .. "/schems"
|
||||
local filename = path .. "/" .. param .. ".mts"
|
||||
filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\") --escape any nasty characters
|
||||
os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
|
||||
-- Create directory if it does not already exist
|
||||
mkdir(path)
|
||||
|
||||
local ret = minetest.create_schematic(worldedit.pos1[name], worldedit.pos2[name], worldedit.prob_list[name], filename)
|
||||
local filename = path .. "/" .. param .. ".mts"
|
||||
local ret = minetest.create_schematic(worldedit.pos1[name],
|
||||
worldedit.pos2[name], worldedit.prob_list[name],
|
||||
filename)
|
||||
if ret == nil then
|
||||
worldedit.player_notify(name, "failed to create Minetest schematic", false)
|
||||
worldedit.player_notify(name, "Failed to create Minetest schematic", false)
|
||||
else
|
||||
worldedit.player_notify(name, "saved Minetest schematic to " .. param, false)
|
||||
worldedit.player_notify(name, "Saved Minetest schematic to " .. param, false)
|
||||
end
|
||||
worldedit.prob_list[name] = {}
|
||||
end),
|
||||
@ -1050,10 +1279,14 @@ minetest.register_chatcommand("/mtschemplace", {
|
||||
description = "Load nodes from \"(world folder)/schems/<file>.mts\" with position 1 of the current WorldEdit region as the origin",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
if param == nil then
|
||||
if param == "" then
|
||||
worldedit.player_notify(name, "no filename specified")
|
||||
return
|
||||
end
|
||||
if not check_filename(param) then
|
||||
worldedit.player_notify(name, "Disallowed file name: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local pos = get_position(name)
|
||||
if pos == nil then return end
|
||||
@ -1087,8 +1320,8 @@ minetest.register_chatcommand("/mtschemprob", {
|
||||
return
|
||||
end
|
||||
for k,v in pairs(problist) do
|
||||
local prob = math.floor(((v["prob"] / 256) * 100) * 100 + 0.5) / 100
|
||||
text = text .. minetest.pos_to_string(v["pos"]) .. ": " .. prob .. "% | "
|
||||
local prob = math.floor(((v.prob / 256) * 100) * 100 + 0.5) / 100
|
||||
text = text .. minetest.pos_to_string(v.pos) .. ": " .. prob .. "% | "
|
||||
end
|
||||
worldedit.player_notify(name, "currently set node probabilities:")
|
||||
worldedit.player_notify(name, text)
|
||||
@ -1098,16 +1331,14 @@ minetest.register_chatcommand("/mtschemprob", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_on_player_receive_fields(
|
||||
function(player, formname, fields)
|
||||
if (formname == "prob_val_enter") and (fields.text ~= "") then
|
||||
local name = player:get_player_name()
|
||||
local prob_entry = {pos=worldedit.prob_pos[name], prob=tonumber(fields.text)}
|
||||
local index = table.getn(worldedit.prob_list[name]) + 1
|
||||
worldedit.prob_list[name][index] = prob_entry
|
||||
end
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname == "prob_val_enter" and not (fields.text == "" or fields.text == nil) then
|
||||
local name = player:get_player_name()
|
||||
local prob_entry = {pos=worldedit.prob_pos[name], prob=tonumber(fields.text)}
|
||||
local index = table.getn(worldedit.prob_list[name]) + 1
|
||||
worldedit.prob_list[name][index] = prob_entry
|
||||
end
|
||||
)
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("/clearobjects", {
|
||||
params = "",
|
||||
|
@ -58,8 +58,19 @@ worldedit.mark_region = function(name)
|
||||
end
|
||||
worldedit.marker_region[name] = nil
|
||||
end
|
||||
|
||||
if pos1 ~= nil and pos2 ~= nil then
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local vec = vector.subtract(pos2, pos1)
|
||||
local maxside = math.max(vec.x, math.max(vec.y, vec.z))
|
||||
local limit = tonumber(minetest.setting_get("active_object_send_range_blocks")) * 16
|
||||
if maxside > limit * 1.5 then
|
||||
-- The client likely won't be able to see the plane markers as intended anyway,
|
||||
-- thus don't place them and also don't load the area into memory
|
||||
return
|
||||
end
|
||||
|
||||
local thickness = 0.2
|
||||
local sizex, sizey, sizez = (1 + pos2.x - pos1.x) / 2, (1 + pos2.y - pos1.y) / 2, (1 + pos2.z - pos1.z) / 2
|
||||
|
||||
@ -72,24 +83,28 @@ worldedit.mark_region = function(name)
|
||||
--XY plane markers
|
||||
for _, z in ipairs({pos1.z - 0.5, pos2.z + 0.5}) do
|
||||
local marker = minetest.add_entity({x=pos1.x + sizex - 0.5, y=pos1.y + sizey - 0.5, z=z}, "worldedit:region_cube")
|
||||
marker:set_properties({
|
||||
visual_size={x=sizex * 2, y=sizey * 2},
|
||||
collisionbox = {-sizex, -sizey, -thickness, sizex, sizey, thickness},
|
||||
})
|
||||
marker:get_luaentity().player_name = name
|
||||
table.insert(markers, marker)
|
||||
if marker ~= nil then
|
||||
marker:set_properties({
|
||||
visual_size={x=sizex * 2, y=sizey * 2},
|
||||
collisionbox = {-sizex, -sizey, -thickness, sizex, sizey, thickness},
|
||||
})
|
||||
marker:get_luaentity().player_name = name
|
||||
table.insert(markers, marker)
|
||||
end
|
||||
end
|
||||
|
||||
--YZ plane markers
|
||||
for _, x in ipairs({pos1.x - 0.5, pos2.x + 0.5}) do
|
||||
local marker = minetest.add_entity({x=x, y=pos1.y + sizey - 0.5, z=pos1.z + sizez - 0.5}, "worldedit:region_cube")
|
||||
marker:set_properties({
|
||||
visual_size={x=sizez * 2, y=sizey * 2},
|
||||
collisionbox = {-thickness, -sizey, -sizez, thickness, sizey, sizez},
|
||||
})
|
||||
marker:setyaw(math.pi / 2)
|
||||
marker:get_luaentity().player_name = name
|
||||
table.insert(markers, marker)
|
||||
if marker ~= nil then
|
||||
marker:set_properties({
|
||||
visual_size={x=sizez * 2, y=sizey * 2},
|
||||
collisionbox = {-thickness, -sizey, -sizez, thickness, sizey, sizez},
|
||||
})
|
||||
marker:setyaw(math.pi / 2)
|
||||
marker:get_luaentity().player_name = name
|
||||
table.insert(markers, marker)
|
||||
end
|
||||
end
|
||||
|
||||
worldedit.marker_region[name] = markers
|
||||
@ -153,7 +168,11 @@ minetest.register_entity(":worldedit:region_cube", {
|
||||
end
|
||||
end,
|
||||
on_punch = function(self, hitter)
|
||||
for _, entity in ipairs(worldedit.marker_region[self.player_name]) do
|
||||
local markers = worldedit.marker_region[self.player_name]
|
||||
if not markers then
|
||||
return
|
||||
end
|
||||
for _, entity in ipairs(markers) do
|
||||
entity:remove()
|
||||
end
|
||||
worldedit.marker_region[self.player_name] = nil
|
||||
|
@ -1,7 +1,7 @@
|
||||
local safe_region_callback = {}
|
||||
local safe_region_param = {}
|
||||
|
||||
check_region = function(name, param)
|
||||
local function check_region(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] --obtain positions
|
||||
if pos1 == nil or pos2 == nil then
|
||||
worldedit.player_notify(name, "no region selected")
|
||||
@ -12,7 +12,7 @@ end
|
||||
|
||||
--`callback` is a callback to run when the user confirms
|
||||
--`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed
|
||||
safe_region = function(callback, nodes_needed)
|
||||
local function safe_region(callback, nodes_needed)
|
||||
--default node volume calculation
|
||||
nodes_needed = nodes_needed or check_region
|
||||
|
||||
@ -30,6 +30,10 @@ safe_region = function(callback, nodes_needed)
|
||||
end
|
||||
end
|
||||
|
||||
local function reset_pending(name)
|
||||
safe_region_callback[name], safe_region_param[name] = nil, nil
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/y", {
|
||||
params = "",
|
||||
description = "Confirm a pending operation",
|
||||
@ -40,15 +44,8 @@ minetest.register_chatcommand("/y", {
|
||||
return
|
||||
end
|
||||
|
||||
--obtain positions
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
worldedit.player_notify(name, "no region selected")
|
||||
return
|
||||
end
|
||||
|
||||
safe_region_callback[name], safe_region_param[name] = nil, nil --reset pending operation
|
||||
callback(name, param, pos1, pos2)
|
||||
callback(name, param)
|
||||
end,
|
||||
})
|
||||
|
||||
@ -63,3 +60,6 @@ minetest.register_chatcommand("/n", {
|
||||
safe_region_callback[name], safe_region_param[name] = nil, nil
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
return safe_region, check_region, reset_pending
|
||||
|
24
worldedit_commands/wand.lua
Normal file
24
worldedit_commands/wand.lua
Normal file
@ -0,0 +1,24 @@
|
||||
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",
|
||||
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
|
||||
|
||||
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.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 and pointed_thing.type == "node" then
|
||||
local name = placer:get_player_name()
|
||||
worldedit.pos2[name] = pointed_thing.under
|
||||
worldedit.mark_pos2(name)
|
||||
end
|
||||
return itemstack -- nothing consumed, nothing changed
|
||||
end,
|
||||
})
|
@ -2,4 +2,5 @@ worldedit
|
||||
worldedit_commands
|
||||
unified_inventory?
|
||||
inventory_plus?
|
||||
creative?
|
||||
sfinv?
|
||||
creative?
|
||||
|
@ -1,6 +1,6 @@
|
||||
--saved state for each player
|
||||
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_nodename1 = {} --mapping of player names to node names
|
||||
local gui_nodename2 = {} --mapping of player names to node names
|
||||
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,9 +10,7 @@ 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 (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
|
||||
local gui_filename = {} --mapping of player names to file names
|
||||
|
||||
--set default values
|
||||
setmetatable(gui_nodename1, {__index = function() return "Cobblestone" end})
|
||||
@ -27,8 +25,6 @@ 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", "?"}
|
||||
@ -40,13 +36,13 @@ local angle_values = {90, 180, 270}
|
||||
setmetatable(angle_indices, {__index = function () return 1 end})
|
||||
setmetatable(angle_values, {__index = function () return 90 end})
|
||||
|
||||
--given multiple sets of privileges, produces a single set of privs that would have the same effect as requiring all of them at the same time
|
||||
-- given multiple sets of privileges, produces a single set of privs that would have the same effect as requiring all of them at the same time
|
||||
local combine_privs = function(...)
|
||||
local result = {}
|
||||
for i, privs in ipairs({...}) do
|
||||
for name, value in pairs(privs) do
|
||||
if result[name] ~= nil and result[name] ~= value then --the priv must be both true and false, which can never happen
|
||||
return {__fake_priv_that_nobody_has__=true} --priviledge table that can never be satisfied
|
||||
return {__fake_priv_that_nobody_has__=true} --privilege table that can never be satisfied
|
||||
end
|
||||
result[name] = value
|
||||
end
|
||||
@ -54,22 +50,44 @@ local combine_privs = function(...)
|
||||
return result
|
||||
end
|
||||
|
||||
-- display node (or unknown_node image otherwise) at specified pos in formspec
|
||||
local formspec_node = function(pos, nodename)
|
||||
return nodename and string.format("item_image[%s;1,1;%s]", pos, nodename)
|
||||
or string.format("image[%s;1,1;worldedit_gui_unknown.png]", pos)
|
||||
end
|
||||
|
||||
-- two further priv helpers
|
||||
local function we_privs(command)
|
||||
return minetest.chatcommands["/" .. command].privs
|
||||
end
|
||||
|
||||
local function combine_we_privs(list)
|
||||
local args = {}
|
||||
for _, t in ipairs(list) do
|
||||
table.insert(args, we_privs(t))
|
||||
end
|
||||
return combine_privs(unpack(args))
|
||||
end
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_about", {
|
||||
name = "About", privs = minetest.chatcommands["/about"].privs,
|
||||
name = "About",
|
||||
privs = {interact=true},
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/about"].func(name, "")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_inspect", {
|
||||
name = "Toggle Inspect", privs = minetest.chatcommands["/inspect"].privs,
|
||||
name = "Toggle Inspect",
|
||||
privs = we_privs("inspect"),
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/inspect"].func(name, worldedit.inspect[name] and "disable" or "enable")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_region", {
|
||||
name = "Get/Set Region", privs = combine_privs(minetest.chatcommands["/p"].privs, minetest.chatcommands["/pos1"].privs, minetest.chatcommands["/pos2"].privs, minetest.chatcommands["/reset"].privs, minetest.chatcommands["/mark"].privs, minetest.chatcommands["/unmark"].privs, minetest.chatcommands["/volume"].privs, minetest.chatcommands["/fixedpos"].privs),
|
||||
name = "Get/Set Region",
|
||||
privs = combine_we_privs({"p", "pos1", "pos2", "reset", "mark", "unmark", "volume", "fixedpos"}),
|
||||
get_formspec = function(name)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
return "size[9,7]" .. worldedit.get_formspec_header("worldedit_gui_region") ..
|
||||
@ -148,15 +166,15 @@ worldedit.register_gui_handler("worldedit_gui_region", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_set", {
|
||||
name = "Set Nodes", privs = minetest.chatcommands["/set"].privs,
|
||||
name = "Set Nodes",
|
||||
privs = we_privs("set"),
|
||||
get_formspec = function(name)
|
||||
local node = gui_nodename1[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_set") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_set_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_set_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
"button_exit[0,2.5;3,0.8;worldedit_gui_set_submit;Set Nodes]"
|
||||
end,
|
||||
})
|
||||
@ -166,7 +184,10 @@ worldedit.register_gui_handler("worldedit_gui_set", function(name, fields)
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_set_node)
|
||||
worldedit.show_page(name, "worldedit_gui_set")
|
||||
if fields.worldedit_gui_set_submit then
|
||||
minetest.chatcommands["/set"].func(name, gui_nodename1[name])
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/set"].func(name, n)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -174,19 +195,18 @@ worldedit.register_gui_handler("worldedit_gui_set", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_replace", {
|
||||
name = "Replace Nodes", privs = combine_privs(minetest.chatcommands["/replace"].privs, minetest.chatcommands["/replaceinverse"].privs),
|
||||
name = "Replace Nodes",
|
||||
privs = combine_we_privs({"replace", "replaceinverse"}),
|
||||
get_formspec = function(name)
|
||||
local search, replace = gui_nodename1[name], gui_nodename2[name]
|
||||
local search_nodename, replace_nodename = worldedit.normalize_nodename(search), worldedit.normalize_nodename(replace)
|
||||
return "size[6.5,4]" .. worldedit.get_formspec_header("worldedit_gui_replace") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_replace_search;Name;%s]", minetest.formspec_escape(search)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_replace_search_search;Search]" ..
|
||||
(search_nodename and string.format("item_image[5.5,1.1;1,1;%s]", search_nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", search_nodename) ..
|
||||
string.format("field[0.5,2.5;4,0.8;worldedit_gui_replace_replace;Name;%s]", minetest.formspec_escape(replace)) ..
|
||||
"button[4,2.18;1.5,0.8;worldedit_gui_replace_replace_search;Search]" ..
|
||||
(replace_nodename and string.format("item_image[5.5,2.1;1,1;%s]", replace_nodename)
|
||||
or "image[5.5,2.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,2.1", replace_nodename) ..
|
||||
"button_exit[0,3.5;3,0.8;worldedit_gui_replace_submit;Replace Nodes]" ..
|
||||
"button_exit[3.5,3.5;3,0.8;worldedit_gui_replace_submit_inverse;Replace Inverse]"
|
||||
end,
|
||||
@ -198,10 +218,19 @@ worldedit.register_gui_handler("worldedit_gui_replace", function(name, fields)
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_replace_search)
|
||||
gui_nodename2[name] = tostring(fields.worldedit_gui_replace_replace)
|
||||
worldedit.show_page(name, "worldedit_gui_replace")
|
||||
|
||||
local submit = nil
|
||||
if fields.worldedit_gui_replace_submit then
|
||||
minetest.chatcommands["/replace"].func(name, string.format("%s %s", gui_nodename1[name], gui_nodename2[name]))
|
||||
submit = "replace"
|
||||
elseif fields.worldedit_gui_replace_submit_inverse then
|
||||
minetest.chatcommands["/replaceinverse"].func(name, string.format("%s %s", gui_nodename1[name], gui_nodename2[name]))
|
||||
submit = "replaceinverse"
|
||||
end
|
||||
if submit then
|
||||
local n1 = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
local n2 = worldedit.normalize_nodename(gui_nodename2[name])
|
||||
if n1 and n2 then
|
||||
minetest.chatcommands["/"..submit].func(name, string.format("%s %s", n1, n2))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -209,15 +238,15 @@ worldedit.register_gui_handler("worldedit_gui_replace", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_sphere_dome", {
|
||||
name = "Sphere/Dome", privs = combine_privs(minetest.chatcommands["/hollowsphere"].privs, minetest.chatcommands["/sphere"].privs, minetest.chatcommands["/hollowdome"].privs, minetest.chatcommands["/dome"].privs),
|
||||
name = "Sphere/Dome",
|
||||
privs = combine_we_privs({"hollowsphere", "sphere", "hollowdome", "dome"}),
|
||||
get_formspec = function(name)
|
||||
local node, radius = gui_nodename1[name], gui_distance2[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,5]" .. worldedit.get_formspec_header("worldedit_gui_sphere_dome") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_sphere_dome_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_sphere_dome_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
string.format("field[0.5,2.5;4,0.8;worldedit_gui_sphere_dome_radius;Radius;%s]", minetest.formspec_escape(radius)) ..
|
||||
"button_exit[0,3.5;3,0.8;worldedit_gui_sphere_dome_submit_hollow;Hollow Sphere]" ..
|
||||
"button_exit[3.5,3.5;3,0.8;worldedit_gui_sphere_dome_submit_solid;Solid Sphere]" ..
|
||||
@ -233,14 +262,22 @@ worldedit.register_gui_handler("worldedit_gui_sphere_dome", function(name, field
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_sphere_dome_node)
|
||||
gui_distance2[name] = tostring(fields.worldedit_gui_sphere_dome_radius)
|
||||
worldedit.show_page(name, "worldedit_gui_sphere_dome")
|
||||
|
||||
local submit = nil
|
||||
if fields.worldedit_gui_sphere_dome_submit_hollow then
|
||||
minetest.chatcommands["/hollowsphere"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "hollowsphere"
|
||||
elseif fields.worldedit_gui_sphere_dome_submit_solid then
|
||||
minetest.chatcommands["/sphere"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "sphere"
|
||||
elseif fields.worldedit_gui_sphere_dome_submit_hollow_dome then
|
||||
minetest.chatcommands["/hollowdome"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "hollowdome"
|
||||
elseif fields.worldedit_gui_sphere_dome_submit_solid_dome then
|
||||
minetest.chatcommands["/dome"].func(name, string.format("%s %s", gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "dome"
|
||||
end
|
||||
if submit then
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/"..submit].func(name, string.format("%s %s", gui_distance2[name], n))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -248,20 +285,24 @@ worldedit.register_gui_handler("worldedit_gui_sphere_dome", function(name, field
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_cylinder", {
|
||||
name = "Cylinder", privs = combine_privs(minetest.chatcommands["/hollowcylinder"].privs, minetest.chatcommands["/cylinder"].privs),
|
||||
name = "Cylinder",
|
||||
privs = combine_we_privs({"hollowcylinder", "cylinder"}),
|
||||
get_formspec = function(name)
|
||||
local node, axis, length, radius = gui_nodename1[name], gui_axis1[name], gui_distance1[name], gui_distance2[name]
|
||||
local node, axis, length = gui_nodename1[name], gui_axis1[name], gui_distance1[name]
|
||||
local radius1, radius2 = gui_distance2[name], gui_distance3[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,5]" .. worldedit.get_formspec_header("worldedit_gui_cylinder") ..
|
||||
return "size[6.5,6]" .. 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]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
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;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]"
|
||||
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]"
|
||||
end,
|
||||
})
|
||||
|
||||
@ -271,58 +312,89 @@ 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_radius)
|
||||
gui_distance2[name] = tostring(fields.worldedit_gui_cylinder_radius1)
|
||||
gui_distance3[name] = tostring(fields.worldedit_gui_cylinder_radius2)
|
||||
worldedit.show_page(name, "worldedit_gui_cylinder")
|
||||
|
||||
local submit = nil
|
||||
if fields.worldedit_gui_cylinder_submit_hollow then
|
||||
minetest.chatcommands["/hollowcylinder"].func(name, string.format("%s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "hollowcylinder"
|
||||
elseif fields.worldedit_gui_cylinder_submit_solid then
|
||||
minetest.chatcommands["/cylinder"].func(name, string.format("%s %s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_distance2[name], gui_nodename1[name]))
|
||||
submit = "cylinder"
|
||||
end
|
||||
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)
|
||||
end
|
||||
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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_pyramid", {
|
||||
name = "Pyramid", privs = minetest.chatcommands["/pyramid"].privs,
|
||||
name = "Pyramid",
|
||||
privs = we_privs("pyramid"),
|
||||
get_formspec = function(name)
|
||||
local node, axis, length = gui_nodename1[name], gui_axis1[name], gui_distance1[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,4]" .. worldedit.get_formspec_header("worldedit_gui_pyramid") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_pyramid_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_pyramid_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
string.format("field[0.5,2.5;4,0.8;worldedit_gui_pyramid_length;Length;%s]", minetest.formspec_escape(length)) ..
|
||||
string.format("dropdown[4,2.18;2.5;worldedit_gui_pyramid_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) ..
|
||||
"button_exit[0,3.5;3,0.8;worldedit_gui_pyramid_submit;Pyramid]"
|
||||
"button_exit[0,3.5;3,0.8;worldedit_gui_pyramid_submit_hollow;Hollow Pyramid]" ..
|
||||
"button_exit[3.5,3.5;3,0.8;worldedit_gui_pyramid_submit_solid;Solid Pyramid]"
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_handler("worldedit_gui_pyramid", function(name, fields)
|
||||
if fields.worldedit_gui_pyramid_search or fields.worldedit_gui_pyramid_submit then
|
||||
if fields.worldedit_gui_pyramid_search or fields.worldedit_gui_pyramid_submit_solid or fields.worldedit_gui_pyramid_submit_hollow or fields.worldedit_gui_pyramid_axis then
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_pyramid_node)
|
||||
gui_axis1[name] = axis_indices[fields.worldedit_gui_pyramid_axis]
|
||||
gui_distance1[name] = tostring(fields.worldedit_gui_pyramid_length)
|
||||
worldedit.show_page(name, "worldedit_gui_pyramid")
|
||||
if fields.worldedit_gui_pyramid_submit then
|
||||
minetest.chatcommands["/pyramid"].func(name, string.format("%s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], gui_nodename1[name]))
|
||||
|
||||
local submit = nil
|
||||
if fields.worldedit_gui_pyramid_submit_solid then
|
||||
submit = "pyramid"
|
||||
elseif fields.worldedit_gui_pyramid_submit_hollow then
|
||||
submit = "hollowpyramid"
|
||||
end
|
||||
if submit then
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/"..submit].func(name, string.format("%s %s %s", axis_values[gui_axis1[name]], gui_distance1[name], n))
|
||||
end
|
||||
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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_spiral", {
|
||||
name = "Spiral", privs = minetest.chatcommands["/spiral"].privs,
|
||||
name = "Spiral",
|
||||
privs = we_privs("spiral"),
|
||||
get_formspec = function(name)
|
||||
local node, length, height, space = gui_nodename1[name], gui_distance1[name], gui_distance2[name], gui_distance3[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,6]" .. worldedit.get_formspec_header("worldedit_gui_spiral") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_spiral_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_spiral_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
string.format("field[0.5,2.5;4,0.8;worldedit_gui_spiral_length;Side Length;%s]", minetest.formspec_escape(length)) ..
|
||||
string.format("field[0.5,3.5;4,0.8;worldedit_gui_spiral_height;Height;%s]", minetest.formspec_escape(height)) ..
|
||||
string.format("field[0.5,4.5;4,0.8;worldedit_gui_spiral_space;Wall Spacing;%s]", minetest.formspec_escape(space)) ..
|
||||
@ -338,7 +410,10 @@ worldedit.register_gui_handler("worldedit_gui_spiral", function(name, fields)
|
||||
gui_distance3[name] = tostring(fields.worldedit_gui_spiral_space)
|
||||
worldedit.show_page(name, "worldedit_gui_spiral")
|
||||
if fields.worldedit_gui_spiral_submit then
|
||||
minetest.chatcommands["/spiral"].func(name, string.format("%s %s %s %s", gui_distance1[name], gui_distance2[name], gui_distance3[name], gui_nodename1[name]))
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/spiral"].func(name, string.format("%s %s %s %s", gui_distance1[name], gui_distance2[name], gui_distance3[name], n))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -346,7 +421,8 @@ worldedit.register_gui_handler("worldedit_gui_spiral", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_copy_move", {
|
||||
name = "Copy/Move", privs = combine_privs(minetest.chatcommands["/copy"].privs, minetest.chatcommands["/move"].privs),
|
||||
name = "Copy/Move",
|
||||
privs = combine_we_privs({"copy", "move"}),
|
||||
get_formspec = function(name)
|
||||
local axis = gui_axis1[name] or 4
|
||||
local amount = gui_distance1[name] or "10"
|
||||
@ -370,11 +446,17 @@ 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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_stack", {
|
||||
name = "Stack", privs = minetest.chatcommands["/stack"].privs,
|
||||
name = "Stack",
|
||||
privs = we_privs("stack"),
|
||||
get_formspec = function(name)
|
||||
local axis, count = gui_axis1[name], gui_count1[name]
|
||||
return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_stack") ..
|
||||
@ -392,11 +474,17 @@ 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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_stretch", {
|
||||
name = "Stretch", privs = minetest.chatcommands["/stretch"].privs,
|
||||
name = "Stretch",
|
||||
privs = we_privs("stretch"),
|
||||
get_formspec = function(name)
|
||||
local stretchx, stretchy, stretchz = gui_count1[name], gui_count2[name], gui_count3[name]
|
||||
return "size[5,5]" .. worldedit.get_formspec_header("worldedit_gui_stretch") ..
|
||||
@ -420,7 +508,8 @@ worldedit.register_gui_handler("worldedit_gui_stretch", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_transpose", {
|
||||
name = "Transpose", privs = minetest.chatcommands["/transpose"].privs,
|
||||
name = "Transpose",
|
||||
privs = we_privs("transpose"),
|
||||
get_formspec = function(name)
|
||||
local axis1, axis2 = gui_axis1[name], gui_axis2[name]
|
||||
return "size[5.5,3]" .. worldedit.get_formspec_header("worldedit_gui_transpose") ..
|
||||
@ -433,18 +522,28 @@ worldedit.register_gui_function("worldedit_gui_transpose", {
|
||||
worldedit.register_gui_handler("worldedit_gui_transpose", function(name, fields)
|
||||
if fields.worldedit_gui_transpose_submit then
|
||||
gui_axis1[name] = axis_indices[fields.worldedit_gui_transpose_axis1]
|
||||
gui_axis2[name] = axis_indices[fields.worldedit_gui_transpose_axis2]
|
||||
worldedit.show_page(name, "worldedit_gui_transpose")
|
||||
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,
|
||||
name = "Flip",
|
||||
privs = we_privs("flip"),
|
||||
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]"
|
||||
@ -453,16 +552,22 @@ 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
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_rotate", {
|
||||
name = "Rotate", privs = minetest.chatcommands["/rotate"].privs,
|
||||
name = "Rotate",
|
||||
privs = we_privs("rotate"),
|
||||
get_formspec = function(name)
|
||||
local axis, angle = gui_axis1[name], gui_angle[name]
|
||||
return "size[5.5,3]" .. worldedit.get_formspec_header("worldedit_gui_rotate") ..
|
||||
@ -480,15 +585,26 @@ 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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_orient", {
|
||||
name = "Orient", privs = minetest.chatcommands["/orient"].privs,
|
||||
name = "Orient",
|
||||
privs = we_privs("orient"),
|
||||
get_formspec = function(name)
|
||||
local angle = gui_angle[name]
|
||||
return "size[5,3]" .. worldedit.get_formspec_header("worldedit_gui_orient") ..
|
||||
string.format("dropdown[0,1;2.5;worldedit_gui_rotate_angle;90 degrees,180 degrees,270 degrees;%s]", angle) ..
|
||||
string.format("dropdown[0,1;2.5;worldedit_gui_orient_angle;90 degrees,180 degrees,270 degrees;%s]", angle) ..
|
||||
"button_exit[0,2.5;3,0.8;worldedit_gui_orient_submit;Orient]"
|
||||
end,
|
||||
})
|
||||
@ -497,36 +613,43 @@ worldedit.register_gui_handler("worldedit_gui_orient", function(name, fields)
|
||||
if fields.worldedit_gui_orient_submit then
|
||||
gui_angle[name] = angle_indices[fields.worldedit_gui_orient_angle]
|
||||
worldedit.show_page(name, "worldedit_gui_orient")
|
||||
minetest.chatcommands["/orient"].func(name, angle_values[gui_angle[name]])
|
||||
minetest.chatcommands["/orient"].func(name, tostring(angle_values[gui_angle[name]]))
|
||||
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)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_fixlight", {
|
||||
name = "Fix Lighting", privs = minetest.chatcommands["/fixlight"].privs,
|
||||
name = "Fix Lighting",
|
||||
privs = we_privs("fixlight"),
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/fixlight"].func(name, "")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_hide", {
|
||||
name = "Hide Region", privs = minetest.chatcommands["/hide"].privs,
|
||||
name = "Hide Region",
|
||||
privs = we_privs("hide"),
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/hide"].func(name, "")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_suppress", {
|
||||
name = "Suppress Nodes", privs = minetest.chatcommands["/suppress"].privs,
|
||||
name = "Suppress Nodes",
|
||||
privs = we_privs("suppress"),
|
||||
get_formspec = function(name)
|
||||
local node = gui_nodename1[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_suppress") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_suppress_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_suppress_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
"button_exit[0,2.5;3,0.8;worldedit_gui_suppress_submit;Suppress Nodes]"
|
||||
end,
|
||||
})
|
||||
@ -536,7 +659,10 @@ worldedit.register_gui_handler("worldedit_gui_suppress", function(name, fields)
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_suppress_node)
|
||||
worldedit.show_page(name, "worldedit_gui_suppress")
|
||||
if fields.worldedit_gui_suppress_submit then
|
||||
minetest.chatcommands["/suppress"].func(name, gui_nodename1[name])
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/suppress"].func(name, n)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -544,15 +670,15 @@ worldedit.register_gui_handler("worldedit_gui_suppress", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_highlight", {
|
||||
name = "Highlight Nodes", privs = minetest.chatcommands["/highlight"].privs,
|
||||
name = "Highlight Nodes",
|
||||
privs = we_privs("highlight"),
|
||||
get_formspec = function(name)
|
||||
local node = gui_nodename1[name]
|
||||
local nodename = worldedit.normalize_nodename(node)
|
||||
return "size[6.5,3]" .. worldedit.get_formspec_header("worldedit_gui_highlight") ..
|
||||
string.format("field[0.5,1.5;4,0.8;worldedit_gui_highlight_node;Name;%s]", minetest.formspec_escape(node)) ..
|
||||
"button[4,1.18;1.5,0.8;worldedit_gui_highlight_search;Search]" ..
|
||||
(nodename and string.format("item_image[5.5,1.1;1,1;%s]", nodename)
|
||||
or "image[5.5,1.1;1,1;unknown_node.png]") ..
|
||||
formspec_node("5.5,1.1", nodename) ..
|
||||
"button_exit[0,2.5;3,0.8;worldedit_gui_highlight_submit;Highlight Nodes]"
|
||||
end,
|
||||
})
|
||||
@ -562,7 +688,10 @@ worldedit.register_gui_handler("worldedit_gui_highlight", function(name, fields)
|
||||
gui_nodename1[name] = tostring(fields.worldedit_gui_highlight_node)
|
||||
worldedit.show_page(name, "worldedit_gui_highlight")
|
||||
if fields.worldedit_gui_highlight_submit then
|
||||
minetest.chatcommands["/highlight"].func(name, gui_nodename1[name])
|
||||
local n = worldedit.normalize_nodename(gui_nodename1[name])
|
||||
if n then
|
||||
minetest.chatcommands["/highlight"].func(name, n)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -570,14 +699,16 @@ worldedit.register_gui_handler("worldedit_gui_highlight", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_restore", {
|
||||
name = "Restore Region", privs = minetest.chatcommands["/restore"].privs,
|
||||
name = "Restore Region",
|
||||
privs = we_privs("restore"),
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/restore"].func(name, "")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_save_load", {
|
||||
name = "Save/Load", privs = combine_privs(minetest.chatcommands["/save"].privs, minetest.chatcommands["/allocate"].privs, minetest.chatcommands["/load"].privs),
|
||||
name = "Save/Load",
|
||||
privs = combine_we_privs({"save", "allocate", "load"}),
|
||||
get_formspec = function(name)
|
||||
local filename = gui_filename[name]
|
||||
return "size[6,4]" .. worldedit.get_formspec_header("worldedit_gui_save_load") ..
|
||||
@ -588,9 +719,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])
|
||||
@ -604,25 +735,46 @@ worldedit.register_gui_handler("worldedit_gui_save", function(name, fields)
|
||||
return false
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_lua", {
|
||||
name = "Run Lua",
|
||||
worldedit.register_gui_function("worldedit_gui_cube", {
|
||||
name = "Cuboid", -- technically the command is misnamed, I know...
|
||||
privs = combine_we_privs({"hollowcube", "cube"}),
|
||||
get_formspec = function(name)
|
||||
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]"
|
||||
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]"
|
||||
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_value
|
||||
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])
|
||||
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
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -630,28 +782,9 @@ worldedit.register_gui_handler("worldedit_gui_lua", function(name, fields)
|
||||
end)
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_clearobjects", {
|
||||
name = "Clear Objects", privs = minetest.chatcommands["/clearobjects"].privs,
|
||||
name = "Clear Objects",
|
||||
privs = we_privs("clearobjects"),
|
||||
on_select = function(name)
|
||||
minetest.chatcommands["/clearobjects"].func(name, "")
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_formspec_tester", {
|
||||
name = "Formspec Tester",
|
||||
get_formspec = function(name)
|
||||
local value = gui_formspec[name]
|
||||
return "size[8,6.5]" .. worldedit.get_formspec_header("worldedit_gui_formspec_tester") ..
|
||||
string.format("textarea[0.5,1;7.5,5.5;worldedit_gui_formspec_tester_value;Formspec Code;%s]", minetest.formspec_escape(value)) ..
|
||||
"button_exit[0,6;3,0.8;worldedit_gui_formspec_tester_show;Show Formspec]"
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_gui_handler("worldedit_gui_formspec_tester", function(name, fields)
|
||||
if fields.worldedit_gui_formspec_tester_show then
|
||||
gui_formspec[name] = fields.worldedit_gui_formspec_tester_value or ""
|
||||
worldedit.show_page(name, "worldedit_gui_formspec_tester")
|
||||
minetest.show_formspec(name, "worldedit:formspec_tester", gui_formspec[name])
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
@ -14,7 +14,7 @@ Use `nil` for the `options` parameter to unregister the function associated with
|
||||
|
||||
Use `nil` for the `get_formspec` field to denote that the function does not have its own screen.
|
||||
|
||||
Use `nil` for the `privs` field to denote that no special privileges are required to use the function.
|
||||
The `privs` field may not be `nil`.
|
||||
|
||||
If the identifier is already registered to another function, it will be replaced by the new one.
|
||||
|
||||
@ -24,6 +24,9 @@ The `on_select` function must not call `worldedit.show_page`
|
||||
worldedit.pages = {} --mapping of identifiers to options
|
||||
local identifiers = {} --ordered list of identifiers
|
||||
worldedit.register_gui_function = function(identifier, options)
|
||||
if options.privs == nil or next(options.privs) == nil then
|
||||
error("privs unset")
|
||||
end
|
||||
worldedit.pages[identifier] = options
|
||||
table.insert(identifiers, identifier)
|
||||
end
|
||||
@ -46,7 +49,7 @@ worldedit.register_gui_handler = function(identifier, handler)
|
||||
|
||||
--ensure the player has permission to perform the action
|
||||
local entry = worldedit.pages[identifier]
|
||||
if entry and minetest.check_player_privs(name, entry.privs or {}) then
|
||||
if entry and minetest.check_player_privs(name, entry.privs) then
|
||||
return handler(name, fields)
|
||||
end
|
||||
return false
|
||||
@ -67,7 +70,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,9 +103,12 @@ 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)
|
||||
inventory_plus.register_button(player, "worldedit_gui", "WorldEdit")
|
||||
local can_worldedit = minetest.check_player_privs(player:get_player_name(), {worldedit=true})
|
||||
if can_worldedit then
|
||||
inventory_plus.register_button(player, "worldedit_gui", "WorldEdit")
|
||||
end
|
||||
end)
|
||||
|
||||
--show the form when the button is pressed and hide it when done
|
||||
@ -115,7 +121,7 @@ elseif inventory_plus then --inventory++ installed
|
||||
return true
|
||||
elseif fields.worldedit_gui_exit then --return to original page
|
||||
if gui_player_formspecs[name] then
|
||||
inventory_plus.set_inventory_formspec(player, gui_player_formspecs[name])
|
||||
inventory_plus.set_inventory_formspec(player, inventory_plus.get_formspec(player, "main"))
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -128,60 +134,35 @@ elseif inventory_plus then --inventory++ installed
|
||||
inventory_plus.set_inventory_formspec(player, get_formspec(name, page))
|
||||
end
|
||||
end
|
||||
else --fallback button
|
||||
local player_formspecs = {}
|
||||
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
|
||||
sfinv.override_page("sfinv:crafting", {
|
||||
get = function(self, player, context)
|
||||
local can_worldedit = minetest.check_player_privs(player, {worldedit=true})
|
||||
local fs = orig_get(self, player, context)
|
||||
return fs .. (can_worldedit and "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" or "")
|
||||
end
|
||||
})
|
||||
|
||||
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_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;]"
|
||||
else
|
||||
formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
|
||||
end
|
||||
player:set_inventory_formspec(formspec)
|
||||
--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
|
||||
|
||||
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 = {}
|
||||
--show the form when the button is pressed and hide it when done
|
||||
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")
|
||||
worldedit.show_page(player:get_player_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
|
||||
set_page(player, "sfinv:crafting")
|
||||
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
|
||||
return false
|
||||
end)
|
||||
|
||||
worldedit.show_page = function(name, page)
|
||||
@ -190,10 +171,19 @@ else --fallback button
|
||||
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"
|
||||
)
|
||||
end
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui", {
|
||||
name = "WorldEdit GUI",
|
||||
privs = {interact=true},
|
||||
get_formspec = function(name)
|
||||
--create a form with all the buttons arranged in a grid
|
||||
local buttons, x, y, index = {}, 0, 1, 0
|
||||
@ -226,7 +216,7 @@ worldedit.register_gui_handler("worldedit_gui", function(name, fields)
|
||||
for identifier, entry in pairs(worldedit.pages) do --check for WorldEdit GUI main formspec button selection
|
||||
if fields[identifier] and identifier ~= "worldedit_gui" then
|
||||
--ensure player has permission to perform action
|
||||
local has_privs, missing_privs = minetest.check_player_privs(name, entry.privs or {})
|
||||
local has_privs, missing_privs = minetest.check_player_privs(name, entry.privs)
|
||||
if not has_privs then
|
||||
worldedit.player_notify(name, "you are not allowed to use this function (missing privileges: " .. table.concat(missing_privs, ", ") .. ")")
|
||||
return false
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 21 KiB |
BIN
worldedit_gui/textures/worldedit_gui_unknown.png
Normal file
BIN
worldedit_gui/textures/worldedit_gui_unknown.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 597 B |
@ -1,103 +0,0 @@
|
||||
worldedit = 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 +0,0 @@
|
||||
worldedit
|
@ -1,120 +0,0 @@
|
||||
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
|
@ -25,12 +25,14 @@ 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")
|
||||
worldedit.alias_chatcommand("/do", "/dome")
|
||||
worldedit.alias_chatcommand("/hcyl", "/hollowcylinder")
|
||||
worldedit.alias_chatcommand("/cyl", "/cylinder")
|
||||
worldedit.alias_chatcommand("/hpyr", "/hollowpyramid")
|
||||
worldedit.alias_chatcommand("/pyr", "/pyramid")
|
||||
worldedit.alias_chatcommand("/spl", "/spiral")
|
||||
worldedit.alias_chatcommand("/m", "/move")
|
||||
@ -47,4 +49,4 @@ worldedit.alias_chatcommand("/hlt", "/highlight")
|
||||
worldedit.alias_chatcommand("/rsr", "/restore")
|
||||
worldedit.alias_chatcommand("/l", "/lua")
|
||||
worldedit.alias_chatcommand("/lt", "/luatransform")
|
||||
worldedit.alias_chatcommand("/clro", "/clearobjects")
|
||||
worldedit.alias_chatcommand("/clro", "/clearobjects")
|
||||
|
Reference in New Issue
Block a user