forked from mtcontrib/Minetest-WorldEdit
Compare commits
13 Commits
ceb2c2cded
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a902a8040 | ||
|
|
fe7a552c40 | ||
|
|
be2a3d6ca7 | ||
|
|
08ab19fcbb | ||
|
|
9670a6d4e0 | ||
|
|
ebb0a95e08 | ||
|
|
0573cd8755 | ||
|
|
3a79209268 | ||
|
|
5121ffab8b | ||
|
|
1f9b8ef55b | ||
|
|
bf154b12c7 | ||
|
|
03d4e45e59 | ||
|
|
6e316105e0 |
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -11,13 +11,14 @@ jobs:
|
||||
cfg:
|
||||
- { image: 'registry.gitlab.com/minetest/minetest/server:5.0.1', mtg: false }
|
||||
- { image: 'registry.gitlab.com/minetest/minetest/server:5.5.1', mtg: false }
|
||||
- { image: '', mtg: true } # latest mater
|
||||
- { image: 'ghcr.io/minetest/minetest:5.10.0', mtg: true }
|
||||
- { image: 'ghcr.io/luanti-org/luanti:master', mtg: true } # latest git
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'minetest/minetest_game'
|
||||
repository: 'luanti-org/minetest_game'
|
||||
path: minetest_game
|
||||
if: ${{ matrix.cfg.mtg }}
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
tempdir=$(mktemp -d)
|
||||
confpath=$tempdir/minetest.conf
|
||||
worldpath=$tempdir/world
|
||||
modlist=(
|
||||
worldedit
|
||||
worldedit_commands
|
||||
)
|
||||
trap 'rm -rf "$tempdir"' EXIT
|
||||
|
||||
[ -f worldedit/mod.conf ] || { echo "Must be run in modpack root folder." >&2; exit 1; }
|
||||
@@ -11,9 +15,9 @@ if [ "$1" == "--docker" ]; then
|
||||
command -v docker >/dev/null || { echo "Docker is not installed." >&2; exit 1; }
|
||||
[ -d minetest_game ] || echo "A source checkout of minetest_game was not found. This can fail if your docker image does not ship a game." >&2;
|
||||
else
|
||||
mtserver=$(command -v minetestserver)
|
||||
[[ -z "$mtserver" && -x ../../bin/minetestserver ]] && mtserver=../../bin/minetestserver
|
||||
[ -z "$mtserver" ] && { echo "To run the test outside of Docker, an installation of minetestserver is required." >&2; exit 1; }
|
||||
mtserver=$(command -v luantiserver)
|
||||
[[ -z "$mtserver" && -x ../../bin/luantiserver ]] && mtserver=../../bin/luantiserver
|
||||
[ -z "$mtserver" ] && { echo "To run the test outside of Docker, an installation of luantiserver is required." >&2; exit 1; }
|
||||
fi
|
||||
|
||||
mkdir $worldpath
|
||||
@@ -22,19 +26,23 @@ printf '%s\n' worldedit_run_tests=true max_forceloaded_blocks=9999 >$confpath
|
||||
|
||||
if [ -z "$mtserver" ]; then
|
||||
chmod -R 777 $tempdir
|
||||
[ -z "$DOCKER_IMAGE" ] && DOCKER_IMAGE="ghcr.io/minetest/minetest:master"
|
||||
[ -n "$DOCKER_IMAGE" ] || { echo "Missing DOCKER_IMAGE env variable" >&2; exit 1; }
|
||||
vol=(
|
||||
-v "$confpath":/etc/minetest/minetest.conf
|
||||
-v "$tempdir":/var/lib/minetest/.minetest
|
||||
-v "$PWD/worldedit":/var/lib/minetest/.minetest/world/worldmods/worldedit
|
||||
)
|
||||
for mod in "${modlist[@]}"; do
|
||||
vol+=(-v "$PWD/$mod":/var/lib/minetest/.minetest/world/worldmods/$mod)
|
||||
done
|
||||
[ -d minetest_game ] && vol+=(
|
||||
-v "$PWD/minetest_game":/var/lib/minetest/.minetest/games/minetest_game
|
||||
)
|
||||
docker run --rm -i "${vol[@]}" "$DOCKER_IMAGE"
|
||||
else
|
||||
mkdir $worldpath/worldmods
|
||||
ln -s "$PWD/worldedit" $worldpath/worldmods/worldedit
|
||||
for mod in "${modlist[@]}"; do
|
||||
ln -s "$PWD/$mod" $worldpath/worldmods/$mod
|
||||
done
|
||||
$mtserver --config "$confpath" --world "$worldpath" --logfile /dev/null
|
||||
fi
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ Set the WorldEdit region position 1 or 2 to the position (`<x>`, `<y>`, `<z>`).
|
||||
//fixedpos set1 -30 5 28
|
||||
//fixedpos set2 1004 -200 432
|
||||
|
||||
Note that the `~` syntax can be used here to indicate a coordinate relative to the player.
|
||||
|
||||
### `//volume`
|
||||
|
||||
Display the volume of the current WorldEdit region.
|
||||
@@ -107,7 +109,13 @@ Display the volume of the current WorldEdit region.
|
||||
|
||||
### `//deleteblocks`
|
||||
|
||||
Delete the MapBlocks (16x16x16 units) that contain the selected region. This means that mapgen will be invoked for that area. As only whole MapBlocks get removed, the deleted area is usually larger than the selected one. Also, mapgen can trigger mechanisms like mud reflow or cavegen, which affects nodes (up to 112 nodes away) outside the MapBlock, so dont use this near buildings. Note that active entities are not part of a MapBlock and do not get deleted.
|
||||
Delete the MapBlocks (16x16x16 units) that contain the selected region.
|
||||
|
||||
This means that mapgen will run again 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 entities are not part of a MapBlock and will not get deleted (use `//clearobjects`).
|
||||
|
||||
//deleteblocks
|
||||
|
||||
@@ -262,7 +270,7 @@ height `<height>`, space between walls `<spacer>`, composed of `<node>`.
|
||||
//spiral 5 2 1 glass
|
||||
//spiral 7 1 5 mesecons:wire_00000000_off
|
||||
|
||||
### `//copy x/y/z/? <amount>`
|
||||
### `//copy x/y/z/?/up/down/left/right/front/back <amount>`
|
||||
|
||||
Copy the current WorldEdit region along the given axis by `<amount>` nodes.
|
||||
|
||||
@@ -271,7 +279,7 @@ Copy the current WorldEdit region along the given axis by `<amount>` nodes.
|
||||
//copy z +4
|
||||
//copy ? 8
|
||||
|
||||
### `//move x/y/z/? <amount>`
|
||||
### `//move x/y/z/?/up/down/left/right/front/back <amount>`
|
||||
|
||||
Move the current WorldEdit positions and region along the given axis by `<amount>` nodes.
|
||||
|
||||
@@ -280,7 +288,7 @@ Move the current WorldEdit positions and region along the given axis by `<amount
|
||||
//move z +4
|
||||
//move ? -1
|
||||
|
||||
### `//stack x/y/z/? <count>`
|
||||
### `//stack x/y/z/?/up/down/left/right/front/back <count>`
|
||||
|
||||
Stack the current WorldEdit region along the given axis `<count>` times.
|
||||
|
||||
@@ -314,14 +322,14 @@ Transpose the current WorldEdit positions and region along given axes.
|
||||
//transpose y z
|
||||
//transpose ? y
|
||||
|
||||
### `//flip x/y/z/?`
|
||||
### `//flip x/y/z/?/up/down/left/right/front/back`
|
||||
|
||||
Flip the current WorldEdit region along the given axis.
|
||||
|
||||
//flip x
|
||||
//flip ?
|
||||
|
||||
### `//rotate x/y/z/? <angle>`
|
||||
### `//rotate x/y/z/?/up/down/left/right/front/back <angle>`
|
||||
|
||||
Rotate the current WorldEdit positions and region along the given axis by angle `<angle>` (90 degree increment).
|
||||
|
||||
@@ -354,7 +362,9 @@ Removes any fluid node within the current WorldEdit region.
|
||||
### `//clearcut`
|
||||
|
||||
Removes any plant, tree or foilage-like nodes in the selected region.
|
||||
|
||||
The idea is to remove anything that isn't part of the terrain, leaving a "natural" empty space ready for building.
|
||||
However note that this relies on heuristics.
|
||||
|
||||
//clearcut
|
||||
|
||||
@@ -440,6 +450,7 @@ Valid values for `[rotation]` are 0, 90, 180 and 270.
|
||||
### `//mtschemprob start/finish/get`
|
||||
|
||||
After using `//mtschemprob start` all nodes punched will bring up a text field where a probablity can be entered.
|
||||
|
||||
This mode can be left with `//mtschemprob finish`. `//mtschemprob get` will display the probabilities saved for the nodes.
|
||||
|
||||
//mtschemprob get
|
||||
@@ -492,6 +503,7 @@ or vertically in the y axis using `v`.
|
||||
Assigns the given `<command>` to the currently held brush item, it will be ran with the first pointed solid node (as determined via raycast) as
|
||||
WorldEdit position 1 when using that specific brush item.
|
||||
Passing `none` instead clears the command assigned to the currently held brush item.
|
||||
|
||||
Note that this functionality requires the `worldedit_brush` mod enabled.
|
||||
|
||||
//brush cube 8 8 8 Cobblestone
|
||||
@@ -502,6 +514,7 @@ Note that this functionality requires the `worldedit_brush` mod enabled.
|
||||
|
||||
Selects a cube with side length of `<size>` around the WorldEdit position 1 and runs the given `<command>` on the newly selected region.
|
||||
If `<sizex>`, `<sizey>` and `<sizez>` are given, they instead specify the length of the cuboid in X, Y, Z direction.
|
||||
|
||||
This is mostly useful for brushes since it allows commands such as `//replace` to be ran, but it can also be used standalone.
|
||||
|
||||
//cubeapply 10 replaceinverse air default:water_source
|
||||
|
||||
44
README.md
44
README.md
@@ -1,30 +1,32 @@
|
||||
WorldEdit v1.3
|
||||
==============
|
||||
The ultimate in-game world editing tool for [Minetest](http://minetest.net/)! Tons of functionality to help with building, fixing, and more.
|
||||
The ultimate in-game world editing tool for [Luanti](https://www.luanti.org/)! Tons of functionality to help with building, fixing, and more.
|
||||
|
||||
For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?t=572) at the Minetest forums.
|
||||
For more information, see the [forum topic](https://forum.luanti.org/viewtopic.php?t=572) at the Luanti forums.
|
||||
|
||||
# New users should see the [tutorial](Tutorial.md).
|
||||
**New users should see the [tutorial](Tutorial.md).**
|
||||
|
||||

|
||||

|
||||
|
||||
Installing
|
||||
----------
|
||||
[](https://content.luanti.org/packages/sfan5/worldedit/)
|
||||
|
||||
There is a nice installation guide over at the [Minetest Wiki](http://wiki.minetest.com/wiki/Installing_mods). Here is a short summary:
|
||||
Head over to ContentDB **⇈** to install it directly.
|
||||
|
||||
1. Download the mod from the [official releases page](https://github.com/Uberi/Minetest-WorldEdit/releases). The download links are labelled "Source Code". If you are using Windows, you'll want to download the ZIP version.
|
||||
2. You should have a file named `Minetest-WorldEdit-x.x.zip`.
|
||||
3. Extract this file using your archiver of choice. If you are using Windows, open the ZIP file and move the folder inside to a safe place outside of the ZIP file.
|
||||
4. Make sure that you now have a folder with a file named README.md inside it. If you just have another folder inside this folder, use the nested folder instead.
|
||||
5. Move this folder into the `MINETEST_FOLDER/mods` folder, where `MINETEST_FOLDER` is the folder Minetest is located in.
|
||||
6. Open Minetest to a world selection screen.
|
||||
7. Select a world you want to use WorldEdit in by left clicking on it once and press the **Configure** button.
|
||||
8. You should have a mod selection screen. Select the one named something like `Minetest-WorldEdit` by left clicking once and press the **Enable Modpack** button.
|
||||
9. Press the **Save** button. You can now use WorldEdit in that world. Repeat steps 7 to 9 to enable WorldEdit for other worlds too.
|
||||
Otherwise, you may install it manually:
|
||||
|
||||
If you are having trouble, try asking for help in the [IRC channel](https://web.libera.chat/#minetest) (faster but may not always have helpers online)
|
||||
or ask on the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) (slower but more likely to get help).
|
||||
1. Download the ZIP file from the [here](https://github.com/Uberi/Minetest-WorldEdit/archive/refs/heads/master.zip) (rolling release version)
|
||||
2. You should have a file named `Minetest-WorldEdit-xxxx.zip`.
|
||||
3. Extract this file. If you are using Windows, open the ZIP file and move the folder inside to a safe place outside of the ZIP file.
|
||||
4. Make sure that you now have a folder with a file called "README.md" inside it. If you just have another folder inside this folder, use the nested folder instead.
|
||||
5. Move this folder into the `mods` folder of your Luanti installation.
|
||||
6. Open Luanti to a world selection screen.
|
||||
7. Select a world you want to use WorldEdit in by left clicking on it once and press the *Configure* button.
|
||||
8. You should have a mod selection screen. Double-click on the entry named something like `Minetest-WorldEdit`, which will enable it.
|
||||
9. Press the *Save* button. You can now use WorldEdit in that world. Repeat steps 7 to 9 to enable WorldEdit for other worlds too.
|
||||
|
||||
If you prefer to have a "stable" release, take a look at the [releases page](https://github.com/Uberi/Minetest-WorldEdit/releases).
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -50,7 +52,8 @@ The chat interface adds many chat commands that perform various WorldEdit powere
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
This mod supports Minetest versions 5.0 and newer. Older versions of WorldEdit may work with older versions of Minetest, but are not recommended or supported.
|
||||
This mod supports Luanti (or Minetest) versions 5.0 and newer.
|
||||
Older versions of WorldEdit are not recommended or supported, and may be **insecure**.
|
||||
|
||||
WorldEdit works quite well with other mods and does not have any known mod conflicts.
|
||||
|
||||
@@ -58,7 +61,8 @@ WorldEdit GUI requires one of [sfinv](https://github.com/minetest/minetest_game/
|
||||
[Unified Inventory](https://forum.minetest.net/viewtopic.php?t=12767),
|
||||
[Inventory++](https://forum.minetest.net/viewtopic.php?id=6204) or [Smart Inventory](https://forum.minetest.net/viewtopic.php?t=16597).
|
||||
|
||||
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.
|
||||
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
|
||||
-------------
|
||||
@@ -72,7 +76,7 @@ This API is documented in the [WorldEdit API Reference](WorldEdit%20API.md).
|
||||
|
||||
Axes
|
||||
----
|
||||
The coordinate system is the same as that used by Minetest; positive Y is upwards, positive X is rightwards, and positive Z is forwards, if a player is facing North (positive Z axis).
|
||||
The coordinate system is the same as that used by Luanti; positive Y is upwards, positive X is rightwards, and positive Z is forwards, if a player is facing North (positive Z axis).
|
||||
|
||||
When an axis is specified in a WorldEdit chat command, it is specified as one of the following values: `x`, `y`, `z`, or `?`.
|
||||
|
||||
@@ -140,7 +144,7 @@ The ordering of the values and minor aspects of the syntax, such as trailing com
|
||||
|
||||
The WorldEdit Schematic format is accessed via the WorldEdit API, or WorldEdit serialization chat commands such as `//serialize` and `//deserialize`.
|
||||
|
||||
The second is the Minetest Schematic format (MTS). The details of this format may be found in the Minetest documentation and are out of the scope of this document.
|
||||
The second is the *Minetest Schematic format (MTS)*. The details of this format may be found in the Luanti documentation and are out of the scope of this document.
|
||||
Access to this format is done via specialized MTS commands such as `//mtschemcreate` and `//mtschemplace`.
|
||||
|
||||
Authors
|
||||
|
||||
@@ -133,7 +133,9 @@ function mh.finish(manip, data)
|
||||
manip:set_data(data)
|
||||
end
|
||||
manip:write_to_map()
|
||||
manip:update_map()
|
||||
if manip.close ~= nil then
|
||||
manip:close() -- explicitly free memory
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
-- 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
|
||||
|
||||
assert(not rawequal(pos1, pos2)) -- vectors must not alias
|
||||
|
||||
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
|
||||
|
||||
|
||||
-- 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 player = assert(minetest.get_player_by_name(name))
|
||||
local playerpos = player:get_pos()
|
||||
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,4 +1,4 @@
|
||||
--- WorldEdit mod for the Minetest engine
|
||||
--- WorldEdit mod for the Luanti engine
|
||||
-- @module worldedit
|
||||
-- @release 1.3
|
||||
-- @copyright 2012 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote)
|
||||
@@ -32,7 +32,6 @@ 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.settings:get_bool("log_mods") then
|
||||
|
||||
@@ -56,8 +56,7 @@ function worldedit.set_param2(pos1, pos2, param2)
|
||||
|
||||
-- Update map
|
||||
manip:set_param2_data(param2_data)
|
||||
manip:write_to_map()
|
||||
manip:update_map()
|
||||
mh.finish(manip)
|
||||
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
@@ -269,8 +268,10 @@ function worldedit.fixlight(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local vmanip = minetest.get_voxel_manip(pos1, pos2)
|
||||
vmanip:write_to_map()
|
||||
vmanip:update_map() -- this updates the lighting
|
||||
vmanip:write_to_map() -- this updates the lighting
|
||||
if vmanip.close ~= nil then
|
||||
vmanip:close()
|
||||
end
|
||||
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
---------------------
|
||||
local vec = vector.new
|
||||
local vecw = function(axis, n, base)
|
||||
local ret = vec(base)
|
||||
local ret = vector.copy(base)
|
||||
ret[axis] = n
|
||||
return ret
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@ local brush_on_use = function(itemstack, placer)
|
||||
if cmd == "" then
|
||||
worldedit.player_notify(name,
|
||||
S("This brush is not bound, use @1 to bind a command to it.",
|
||||
minetest.colorize("#00ffff", "//brush")), "info")
|
||||
minetest.colorize("#0ff", "//brush")), "info")
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -100,7 +100,7 @@ worldedit.register_command("brush", {
|
||||
local cmddef = worldedit.registered_commands[cmd]
|
||||
if cmddef == nil or cmddef.require_pos ~= 1 then
|
||||
return false, S("@1 cannot be used with brushes",
|
||||
minetest.colorize("#00ffff", "//"..cmd))
|
||||
minetest.colorize("#0ff", "//"..cmd))
|
||||
end
|
||||
|
||||
-- Try parsing command params so we can give the user feedback
|
||||
@@ -112,7 +112,7 @@ worldedit.register_command("brush", {
|
||||
|
||||
meta:set_string("command", cmd)
|
||||
meta:set_string("params", params)
|
||||
local fullcmd = minetest.colorize("#00ffff", "//"..cmd) .. " " .. params
|
||||
local fullcmd = minetest.colorize("#0ff", "//"..cmd) .. " " .. params
|
||||
meta:set_string("description",
|
||||
minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
|
||||
worldedit.player_notify(name, S("Brush assigned to command: @1", fullcmd), "ok")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
local S = minetest.get_translator("worldedit_commands")
|
||||
|
||||
local VALID_DIR = worldedit.valid_directions
|
||||
|
||||
worldedit.register_command("outset", {
|
||||
params = "[h/v] <amount>",
|
||||
description = S("Outset the selected region."),
|
||||
@@ -7,7 +9,7 @@ worldedit.register_command("outset", {
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
|
||||
local find, _, dir, amount = param:find("^(%a*)%s+([+-]?%d+)$")
|
||||
if find == nil then
|
||||
return false
|
||||
end
|
||||
@@ -47,7 +49,7 @@ worldedit.register_command("inset", {
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local find, _, dir, amount = param:find("(%a*)%s*([+-]?%d+)")
|
||||
local find, _, dir, amount = param:find("^(%a*)%s+([+-]?%d+)$")
|
||||
if find == nil then
|
||||
return false
|
||||
end
|
||||
@@ -79,29 +81,21 @@ worldedit.register_command("inset", {
|
||||
|
||||
|
||||
worldedit.register_command("shift", {
|
||||
params = "x/y/z/?/up/down/left/right/front/back [+/-]<amount>",
|
||||
params = tostring(VALID_DIR) .. " [+/-]<amount>",
|
||||
description = S("Shifts the selection area without moving its contents"),
|
||||
category = S("Region operations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local find, _, direction, amount = param:find("([%?%l]+)%s*([+-]?%d+)")
|
||||
if find == nil then
|
||||
local find, _, direction, amount = param:find("^([^%s]+)%s+([+-]?%d+)$")
|
||||
if find == nil or not VALID_DIR[direction] then
|
||||
return false
|
||||
end
|
||||
|
||||
return true, direction, tonumber(amount)
|
||||
end,
|
||||
func = function(name, direction, amount)
|
||||
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
|
||||
|
||||
local axis, dir = worldedit.player_direction(name, direction)
|
||||
if axis == nil or dir == nil then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
@@ -115,15 +109,15 @@ worldedit.register_command("shift", {
|
||||
|
||||
|
||||
worldedit.register_command("expand", {
|
||||
params = "[+/-]x/y/z/?/up/down/left/right/front/back <amount> [reverse amount]",
|
||||
params = "[+/-]" .. tostring(VALID_DIR) .. " <amount> [reverse amount]",
|
||||
description = S("Expands the selection in the selected absolute or relative axis"),
|
||||
category = S("Region operations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local find, _, sign, direction, amount,
|
||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
||||
if find == nil then
|
||||
rev_amount = param:find("^([+-]?)([^%s]+)%s+(%d+)%s*(%d*)$")
|
||||
if find == nil or not VALID_DIR[direction] then
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -134,24 +128,10 @@ worldedit.register_command("expand", {
|
||||
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
||||
end,
|
||||
func = function(name, sign, direction, amount, rev_amount)
|
||||
local absolute = direction:find("[xyz?]")
|
||||
local dir, axis
|
||||
|
||||
if absolute == nil then
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
local axis, dir = worldedit.player_direction(name, direction)
|
||||
if axis == nil or dir == nil then
|
||||
return false, S("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
|
||||
@@ -165,15 +145,15 @@ worldedit.register_command("expand", {
|
||||
|
||||
|
||||
worldedit.register_command("contract", {
|
||||
params = "[+/-]x/y/z/?/up/down/left/right/front/back <amount> [reverse amount]",
|
||||
params = "[+/-]" .. tostring(VALID_DIR) .. " [reverse amount]",
|
||||
description = S("Contracts the selection in the selected absolute or relative axis"),
|
||||
category = S("Region operations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local find, _, sign, direction, amount,
|
||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
||||
if find == nil then
|
||||
rev_amount = param:find("^([+-]?)([^%s]+)%s+(%d+)%s*(%d*)$")
|
||||
if find == nil or not VALID_DIR[direction] then
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -184,24 +164,10 @@ worldedit.register_command("contract", {
|
||||
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
||||
end,
|
||||
func = function(name, sign, direction, amount, rev_amount)
|
||||
local absolute = direction:find("[xyz?]")
|
||||
local dir, axis
|
||||
|
||||
if absolute == nil then
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
local axis, dir = worldedit.player_direction(name, direction)
|
||||
if axis == nil or dir == nil then
|
||||
return false, S("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
|
||||
@@ -238,7 +204,7 @@ worldedit.register_command("cubeapply", {
|
||||
local cmddef = worldedit.registered_commands[cmd]
|
||||
if cmddef == nil or cmddef.require_pos ~= 2 then
|
||||
return false, S("invalid usage: @1 cannot be used with cubeapply",
|
||||
minetest.colorize("#00ffff", "//"..cmd))
|
||||
minetest.colorize("#0ff", "//"..cmd))
|
||||
end
|
||||
-- run parsing of target command
|
||||
local parsed = {cmddef.parse(args)}
|
||||
|
||||
152
worldedit_commands/cuboid_funcs.lua
Normal file
152
worldedit_commands/cuboid_funcs.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
-- Moves the location of a single marker by adding deltavector
|
||||
local function marker_move(name, marker, deltavector)
|
||||
if marker == 1 then
|
||||
local pos = worldedit.pos1[name]
|
||||
worldedit.pos1[name] = vector.add(deltavector, pos)
|
||||
elseif marker == 2 then
|
||||
local pos = worldedit.pos2[name]
|
||||
worldedit.pos2[name] = vector.add(deltavector, pos)
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Returns two vectors with the directions for volumetric expansion
|
||||
local function get_expansion_directions(mark1, mark2)
|
||||
assert(mark1 and mark2)
|
||||
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
|
||||
|
||||
|
||||
-- Returns the closest marker to the specified axis and direction
|
||||
local function marker_get_closest_to_axis(name, axis, direction)
|
||||
assert(direction == 1 or direction == -1)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if axis == "x" then
|
||||
if pos1.x * direction > pos2.x * direction then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
elseif axis == "y" then
|
||||
if pos1.y * direction > pos2.y * direction then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
elseif axis == "z" then
|
||||
if pos1.z * direction > pos2.z * direction then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- 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(amount, amount, amount)
|
||||
local delta2 = vector.new(amount, amount, amount)
|
||||
local delta_dir1, delta_dir2 = 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 = 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
|
||||
|
||||
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
|
||||
|
||||
local delta = vector.new()
|
||||
if axis == "x" then
|
||||
delta.x = amount
|
||||
elseif axis == "y" then
|
||||
delta.y = amount
|
||||
elseif axis == "z" then
|
||||
delta.z = amount
|
||||
else
|
||||
return false, "invalid axis"
|
||||
end
|
||||
|
||||
worldedit.pos1[name] = vector.add(pos1, delta)
|
||||
worldedit.pos2[name] = vector.add(pos2, delta)
|
||||
return true
|
||||
end
|
||||
@@ -25,6 +25,15 @@ local function copy_state(which, name)
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_state(state, old_state)
|
||||
for i, v in ipairs(state) do
|
||||
if not (v == nil and old_state[i] == nil) and not vector.equals(v, old_state[i]) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function chatcommand_handler(cmd_name, name, param)
|
||||
local def = assert(worldedit.registered_commands[cmd_name])
|
||||
|
||||
@@ -42,6 +51,7 @@ local function chatcommand_handler(cmd_name, name, param)
|
||||
end
|
||||
end
|
||||
|
||||
param = param:trim()
|
||||
local parsed = {def.parse(param)}
|
||||
local success = table.remove(parsed, 1)
|
||||
if not success then
|
||||
@@ -66,11 +76,7 @@ local function chatcommand_handler(cmd_name, name, param)
|
||||
local old_state = copy_state(def.require_pos, name)
|
||||
safe_region(name, count, function()
|
||||
local state = copy_state(def.require_pos, name)
|
||||
local ok = true
|
||||
for i, v in ipairs(state) do
|
||||
ok = ok and ( (v == nil and old_state[i] == nil) or vector.equals(v, old_state[i]) )
|
||||
end
|
||||
if not ok then
|
||||
if not compare_state(state, old_state) then
|
||||
worldedit.player_notify(name, S("ERROR: the operation was cancelled because the region has changed."), "error")
|
||||
return
|
||||
end
|
||||
@@ -111,7 +117,9 @@ function worldedit.register_command(name, def)
|
||||
def.require_pos = def.require_pos or 0
|
||||
assert(def.require_pos >= 0 and def.require_pos < 3)
|
||||
if def.params == "" and not def.parse then
|
||||
def.parse = function(param) return true end
|
||||
def.parse = function(param)
|
||||
return param == ""
|
||||
end
|
||||
else
|
||||
assert(def.parse)
|
||||
end
|
||||
@@ -124,7 +132,7 @@ function worldedit.register_command(name, def)
|
||||
end--]]
|
||||
|
||||
-- disable further modification
|
||||
setmetatable(def, {__newindex = {}})
|
||||
setmetatable(def, {__newindex = function() end})
|
||||
|
||||
minetest.register_chatcommand("/" .. name, {
|
||||
privs = def.privs,
|
||||
@@ -137,18 +145,6 @@ function worldedit.register_command(name, def)
|
||||
worldedit.registered_commands[name] = def
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
local modpath = minetest.get_modpath("worldedit_commands")
|
||||
for _, name in ipairs({
|
||||
"code", "cuboid", "manipulations", "marker", "nodename", "primitives",
|
||||
"region", "schematics", "transform", "wand"
|
||||
}) do
|
||||
dofile(modpath .. "/" .. name .. ".lua")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Notifies a player of something related to WorldEdit.
|
||||
-- Message types:
|
||||
-- "error" = An operation did not work as expected.
|
||||
@@ -172,7 +168,9 @@ function worldedit.player_notify(name, message, typ)
|
||||
minetest.chat_send_player(name, table.concat(t, " "))
|
||||
end
|
||||
|
||||
-- Determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
|
||||
-- Determines the axis in which a player is facing
|
||||
-- @return axis ("x", "y", or "z") and the sign (1 or -1)
|
||||
-- @note Not part of API
|
||||
function worldedit.player_axis(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
@@ -191,6 +189,79 @@ function worldedit.player_axis(name)
|
||||
return "z", dir.z > 0 and 1 or -1
|
||||
end
|
||||
|
||||
-- Look-up table of valid directions (for worldedit.player_direction)
|
||||
-- Can be stringified for usage in help texts
|
||||
-- @note Not part of API
|
||||
worldedit.valid_directions = setmetatable({
|
||||
x = true, y = true, z = true,
|
||||
["?"] = true,
|
||||
up = true, down = true,
|
||||
front = true, back = true,
|
||||
left = true, right = true,
|
||||
}, {
|
||||
__tostring = function()
|
||||
return "x/y/z/?/up/down/left/right/front/back"
|
||||
end
|
||||
})
|
||||
|
||||
-- Accepts a valid directions as above
|
||||
-- @return axis ("x", "y", or "z") and the sign (1 or -1) *or* nil for invalid combinations
|
||||
-- @note Not part of API
|
||||
worldedit.player_direction = function(name, str)
|
||||
if str == "x" or str == "y" or str == "z" then
|
||||
return str, 1
|
||||
elseif str == "up" then
|
||||
return "y", 1
|
||||
elseif str == "down" then
|
||||
return "y", -1
|
||||
end
|
||||
|
||||
local axis, dir = worldedit.player_axis(name)
|
||||
|
||||
if str == "?" then
|
||||
return axis, dir
|
||||
elseif str == "front" then
|
||||
if axis ~= "y" then
|
||||
return axis, dir
|
||||
end
|
||||
elseif str == "back" then
|
||||
if axis ~= "y" then
|
||||
return axis, -dir
|
||||
end
|
||||
elseif str == "left" then
|
||||
if axis == "x" then
|
||||
return "z", dir
|
||||
elseif axis == "z" then
|
||||
return "x", -dir
|
||||
end
|
||||
elseif str == "right" then
|
||||
if axis == "x" then
|
||||
return "z", -dir
|
||||
elseif axis == "z" then
|
||||
return "x", dir
|
||||
end
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
-- Wrapper for the engine"s parse_coordinates
|
||||
-- @return vector or nil
|
||||
-- @note Not part of API
|
||||
function worldedit.parse_coordinates(x, y, z, player_name)
|
||||
local relpos
|
||||
local player = minetest.get_player_by_name(player_name or "")
|
||||
if player then
|
||||
relpos = player:get_pos()
|
||||
end
|
||||
-- we don't bother to support ~ in the fallback path here
|
||||
if not minetest.parse_coordinates then
|
||||
x, y, z = tonumber(x), tonumber(y), tonumber(z)
|
||||
return x and y and z and vector.new(x, y, z)
|
||||
end
|
||||
return minetest.parse_coordinates(x, y, z, relpos)
|
||||
end
|
||||
|
||||
|
||||
worldedit.register_command("about", {
|
||||
privs = {},
|
||||
@@ -200,7 +271,7 @@ worldedit.register_command("about", {
|
||||
worldedit.player_notify(name, S("WorldEdit @1"..
|
||||
" is available on this server. Type @2 to get a list of "..
|
||||
"commands, or find more information at @3",
|
||||
worldedit.version_string, minetest.colorize("#00ffff", "//help"),
|
||||
worldedit.version_string, minetest.colorize("#0ff", "//help"),
|
||||
"https://github.com/Uberi/Minetest-WorldEdit"
|
||||
), "info")
|
||||
end,
|
||||
@@ -209,10 +280,10 @@ worldedit.register_command("about", {
|
||||
-- initially copied from builtin/chatcommands.lua
|
||||
local function help_command(name, param)
|
||||
local function format_help_line(cmd, def, follow_alias)
|
||||
local msg = minetest.colorize("#00ffff", "//"..cmd)
|
||||
local msg = minetest.colorize("#0ff", "//"..cmd)
|
||||
if def.name ~= cmd then
|
||||
msg = msg .. ": " .. S("alias to @1",
|
||||
minetest.colorize("#00ffff", "//"..def.name))
|
||||
minetest.colorize("#0ff", "//"..def.name))
|
||||
if follow_alias then
|
||||
msg = msg .. "\n" .. format_help_line(def.name, def)
|
||||
end
|
||||
@@ -255,7 +326,7 @@ local function help_command(name, param)
|
||||
end
|
||||
end
|
||||
table.sort(list)
|
||||
local help = minetest.colorize("#00ffff", "//help")
|
||||
local help = minetest.colorize("#0ff", "//help")
|
||||
return true, S("Available commands: @1@n"
|
||||
.. "Use '@2' to get more information,"
|
||||
.. " or '@3' to list everything.",
|
||||
@@ -320,3 +391,17 @@ worldedit.register_command("reset", {
|
||||
end,
|
||||
})
|
||||
|
||||
-- Load the other parts
|
||||
do
|
||||
local modpath = minetest.get_modpath("worldedit_commands")
|
||||
for _, name in ipairs({
|
||||
"code", "cuboid_funcs", "cuboid", "manipulations", "marker", "nodename",
|
||||
"primitives", "region", "schematics", "transform", "wand"
|
||||
}) do
|
||||
dofile(modpath .. "/" .. name .. ".lua")
|
||||
end
|
||||
|
||||
if worldedit.register_test then
|
||||
dofile(modpath .. "/test/init.lua")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -51,6 +51,7 @@ select position @1 by punching a node=
|
||||
position @1: @2=
|
||||
position @1 not set=
|
||||
Set a WorldEdit region position to the position at (<x>, <y>, <z>)=
|
||||
invalid position=
|
||||
Display the volume of the current WorldEdit region=
|
||||
current region has a volume of @1 nodes (@2*@3*@4)=
|
||||
Remove all MapBlocks (16x16x16) containing the selected area from the map=
|
||||
@@ -150,4 +151,5 @@ WARNING: this operation could affect up to @1 nodes; type @2 to continue or @3 t
|
||||
Confirm a pending operation=
|
||||
no operation pending=
|
||||
Abort a pending operation=
|
||||
WorldEdit Wand tool@nLeft-click to set 1st position, right-click to set 2nd=
|
||||
WorldEdit Wand tool=
|
||||
Left-click to set 1st position, right-click to set 2nd=
|
||||
|
||||
@@ -62,6 +62,7 @@ select position @1 by punching a node=Wählen Sie Position @1 durch Hauen eines
|
||||
position @1: @2=Position @1: @2
|
||||
position @1 not set=Position @1 ist nicht gesetzt
|
||||
Set a WorldEdit region position to the position at (<x>, <y>, <z>)=Eine Position des WorldEdit-Gebiets auf (<x>, <y>, <z>) setzen
|
||||
invalid position=Ungültige Position
|
||||
Display the volume of the current WorldEdit region=Volumen des aktuellen WorldEdit-Gebiets anzeigen
|
||||
current region has a volume of @1 nodes (@2*@3*@4)=Das aktuelle Gebiet hat ein Volumen von @1 Blöcken (@2×@3×@4)
|
||||
Remove all MapBlocks (16x16x16) containing the selected area from the map=Alle Kartenblöcke (16×16×16) entfernen, die das gewählte Gebiet enthalten
|
||||
@@ -161,4 +162,5 @@ WARNING: this operation could affect up to @1 nodes; type @2 to continue or @3 t
|
||||
Confirm a pending operation=Einen ausstehenden Vorgang bestätigen
|
||||
no operation pending=Kein Vorgang ausstehend
|
||||
Abort a pending operation=Einen ausstehenden Vorgang abbrechen
|
||||
WorldEdit Wand tool@nLeft-click to set 1st position, right-click to set 2nd=WorldEdit-Zauberstab@nSetzen der 1. Position mit Linksklick, der 2. mit Rechtsklick
|
||||
WorldEdit Wand tool=WorldEdit-Zauberstab
|
||||
Left-click to set 1st position, right-click to set 2nd=Setzen der 1. Position mit Linksklick, der 2. mit Rechtsklick
|
||||
|
||||
@@ -73,7 +73,7 @@ Stack the current WorldEdit region along the given axis <count> times=Размн
|
||||
@1 nodes stacked=размножено @1 нод(а/ы)
|
||||
Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>=Размножить текущий WorldEdit-регион <count> раз с шагом <x>, <y>, <z> по соответствующим осям
|
||||
invalid count: @1=неверное количество: @1
|
||||
invalid increments: @1=неверные приращения(шаг)
|
||||
invalid increments: @1=неверные приращения(шаг): @1
|
||||
Scale the current WorldEdit positions and region by a factor of <stretchx>, <stretchy>, <stretchz> along the X, Y, and Z axes, repectively, with position 1 as the origin=Масштабировать текущий WorldEdit-регион с коэффициентами <stretchx>, <stretchy>, <stretchz> вдоль осей X, Y и Z, используя WorldEdit-позицию 1 в качестве точки отсчёта
|
||||
invalid scaling factors: @1=неверные коэффициенты масштабирования: @1
|
||||
@1 nodes stretched=масштабировано @1 нод(а/ы)
|
||||
@@ -152,4 +152,5 @@ invalid usage: @1 cannot be used with cubeapply=недопустимое исп
|
||||
Missing privileges: @1=Отсутствуют привилегии: @1
|
||||
|
||||
### wand.lua ###
|
||||
WorldEdit Wand tool@nLeft-click to set 1st position, right-click to set 2nd=Инструмент WorldEdit Wand@nЛевая кнопка мыши, чтобы установить 1-ю позицию, правая кнопка мыши, чтобы установить 2-ю
|
||||
WorldEdit Wand tool=Инструмент WorldEdit Wand
|
||||
Left-click to set 1st position, right-click to set 2nd=Левая кнопка мыши, чтобы установить 1-ю позицию, правая кнопка мыши, чтобы установить 2-ю
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
-- Strips any kind of escape codes (translation, colors) from a string
|
||||
-- https://github.com/minetest/minetest/blob/53dd7819277c53954d1298dfffa5287c306db8d0/src/util/string.cpp#L777
|
||||
local function strip_escapes(input)
|
||||
local strip_escapes = minetest.strip_escapes or function(input)
|
||||
local s = function(idx) return input:sub(idx, idx) end
|
||||
local out = ""
|
||||
local i = 1
|
||||
@@ -22,42 +20,63 @@ local function strip_escapes(input)
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
--print(("%q -> %q"):format(input, out))
|
||||
return out
|
||||
end
|
||||
|
||||
local function string_endswith(full, part)
|
||||
return full:find(part, 1, true) == #full - #part + 1
|
||||
if #full < #part then
|
||||
return false
|
||||
end
|
||||
return full:sub(-#part) == part
|
||||
end
|
||||
|
||||
local function make_description_cache()
|
||||
local t = {}
|
||||
for key, def in pairs(minetest.registered_nodes) do
|
||||
local desc = def.short_description or (def.description or ""):gsub("\n.*", "", 1)
|
||||
desc = strip_escapes(desc):lower()
|
||||
if def.groups.not_in_creative_inventory ~= 1 and desc ~= "" then
|
||||
t[key] = desc
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local description_cache = nil
|
||||
|
||||
-- normalizes node "description" `nodename`, returning a string (or nil)
|
||||
worldedit.normalize_nodename = function(nodename)
|
||||
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
|
||||
if nodename == "" then return nil end
|
||||
nodename = nodename:trim()
|
||||
if nodename == "" then
|
||||
return nil
|
||||
end
|
||||
|
||||
if nodename:find(" ", 1, true) == nil then
|
||||
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
|
||||
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
|
||||
if minetest.registered_nodes[fullname] then -- full name
|
||||
return fullname
|
||||
end
|
||||
nodename = nodename:lower()
|
||||
end
|
||||
|
||||
local match
|
||||
for key, _ in pairs(minetest.registered_nodes) do
|
||||
if string_endswith(key:lower(), ":" .. nodename) then -- matches name (w/o mod part)
|
||||
return key
|
||||
if string_endswith(key, ":" .. nodename) then
|
||||
if match then
|
||||
match = nil
|
||||
break
|
||||
end
|
||||
match = key -- matches name w/o mod part (only if unique)
|
||||
end
|
||||
end
|
||||
if match then
|
||||
return match
|
||||
end
|
||||
|
||||
nodename = nodename:lower()
|
||||
if description_cache == nil then
|
||||
-- cache stripped descriptions
|
||||
description_cache = {}
|
||||
for key, value in pairs(minetest.registered_nodes) do
|
||||
local desc = strip_escapes(value.description):gsub("\n.*", "", 1):lower()
|
||||
if desc ~= "" then
|
||||
description_cache[key] = desc
|
||||
end
|
||||
end
|
||||
-- Note: since we don't handle translations this will work only in the original
|
||||
-- language of the description (English)
|
||||
description_cache = make_description_cache()
|
||||
end
|
||||
|
||||
for key, desc in pairs(description_cache) do
|
||||
@@ -72,14 +91,16 @@ worldedit.normalize_nodename = function(nodename)
|
||||
end
|
||||
end
|
||||
|
||||
local match = nil
|
||||
match = nil
|
||||
for key, value in pairs(description_cache) do
|
||||
if value:find(nodename, 1, true) ~= nil then
|
||||
if match ~= nil then
|
||||
return nil
|
||||
if match then
|
||||
match = nil
|
||||
break
|
||||
end
|
||||
match = key -- substring description match (only if no ambiguities)
|
||||
match = key -- substring description match (only if unique)
|
||||
end
|
||||
end
|
||||
|
||||
return match
|
||||
end
|
||||
|
||||
@@ -95,6 +95,7 @@ worldedit.register_command("unmark", {
|
||||
|
||||
local function set_pos1(name, pos)
|
||||
assert(pos)
|
||||
pos = vector.round(pos)
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.player_notify(name, S("position @1 set to @2", 1, minetest.pos_to_string(pos)), "ok")
|
||||
@@ -102,6 +103,7 @@ end
|
||||
|
||||
local function set_pos2(name, pos)
|
||||
assert(pos)
|
||||
pos = vector.round(pos)
|
||||
worldedit.pos2[name] = pos
|
||||
worldedit.mark_pos2(name)
|
||||
worldedit.player_notify(name, S("position @1 set to @2", 2, minetest.pos_to_string(pos)), "ok")
|
||||
@@ -115,7 +117,7 @@ worldedit.register_command("pos1", {
|
||||
func = function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
set_pos1(name, vector.round(player:get_pos()))
|
||||
set_pos1(name, player:get_pos())
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -127,7 +129,7 @@ worldedit.register_command("pos2", {
|
||||
func = function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return end
|
||||
set_pos2(name, vector.round(player:get_pos()))
|
||||
set_pos2(name, player:get_pos())
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -178,13 +180,18 @@ worldedit.register_command("fixedpos", {
|
||||
category = S("Region operations"),
|
||||
privs = {worldedit=true},
|
||||
parse = function(param)
|
||||
local found, _, flag, x, y, z = param:find("^(set[12])%s+([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
local found, _, flag, x, y, z = param:find("^(set[12])%s+(~?[+-]?%d+)%s+(~?[+-]?%d+)%s+(~?[+-]?%d+)$")
|
||||
if not found then
|
||||
return false
|
||||
end
|
||||
return true, flag, vector.new(tonumber(x), tonumber(y), tonumber(z))
|
||||
return true, flag, x, y, z
|
||||
end,
|
||||
func = function(name, flag, pos)
|
||||
func = function(name, flag, x, y, z)
|
||||
-- Parse here, since player name isn't known in parse()
|
||||
local pos = worldedit.parse_coordinates(x, y, z, name)
|
||||
if not pos then
|
||||
return false, S("invalid position")
|
||||
end
|
||||
if flag == "set1" then
|
||||
set_pos1(name, pos)
|
||||
else --flag == "set2"
|
||||
|
||||
@@ -20,8 +20,8 @@ local function safe_region(name, count, callback)
|
||||
count_str = minetest.colorize("#f33", count_str:sub(1, -7)) .. count_str:sub(-6, -1)
|
||||
end
|
||||
|
||||
local yes_cmd = minetest.colorize("#00ffff", "//y")
|
||||
local no_cmd = minetest.colorize("#00ffff", "//n")
|
||||
local yes_cmd = minetest.colorize("#0ff", "//y")
|
||||
local no_cmd = minetest.colorize("#0ff", "//n")
|
||||
local msg = S("WARNING: this operation could affect up to @1 nodes; type @2 to continue or @3 to cancel",
|
||||
count_str, yes_cmd, no_cmd)
|
||||
worldedit.player_notify(name, msg, "info")
|
||||
|
||||
143
worldedit_commands/test/init.lua
Normal file
143
worldedit_commands/test/init.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
local register_test = worldedit.register_test
|
||||
|
||||
-- Basic test that just checks if certain parameter combinations
|
||||
-- parse correctly (valid or invalid)
|
||||
local make_parsing_test = function(cmd, valid, invalid)
|
||||
return function()
|
||||
local def = worldedit.registered_commands[cmd]
|
||||
assert(def, "Command not defined")
|
||||
for _, param in ipairs(valid or {}) do
|
||||
local parsed = {def.parse(param)}
|
||||
assert(parsed[1], string.format("Did not parse: %q", param))
|
||||
end
|
||||
for _, param in ipairs(invalid or {}) do
|
||||
local parsed = {def.parse(param)}
|
||||
assert(not parsed[1], string.format("Did parse: %q", param))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
register_test("Command parsing")
|
||||
register_test("//set", make_parsing_test("set", {
|
||||
"air",
|
||||
"mapgen_stone",
|
||||
minetest.registered_aliases["mapgen_dirt"],
|
||||
}, {
|
||||
"this long text could not possibly ever match a node",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//mix", make_parsing_test("mix", {
|
||||
"air",
|
||||
"air 2",
|
||||
"air mapgen_stone",
|
||||
"air 2 air 1 mapgen_stone 1",
|
||||
}, {
|
||||
"this_will_never_match_any_node",
|
||||
"air 1 this_will_never_match_any_node",
|
||||
"air this_will_never_match_any_node",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//fixedpos", make_parsing_test("fixedpos", {
|
||||
"set1 0 0 0",
|
||||
"set2 -10 20 31000",
|
||||
"set1 ~0 ~0 ~0",
|
||||
"set2 ~-5 2 ~+2",
|
||||
}, {
|
||||
"set1 0 0",
|
||||
"set 1 2 3",
|
||||
"set2 ~ ~ ~",
|
||||
"set2 + 0 0",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//copy", make_parsing_test("copy", {
|
||||
"x 10",
|
||||
"right +1",
|
||||
"? -4",
|
||||
}, {
|
||||
"eee 1",
|
||||
"up 0",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//rotate", make_parsing_test("rotate", {
|
||||
"z 90",
|
||||
"left -180",
|
||||
}, {
|
||||
"x 0",
|
||||
"back 77",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//flip", make_parsing_test("flip", {
|
||||
"y",
|
||||
"down",
|
||||
"?",
|
||||
}, {
|
||||
"1",
|
||||
"",
|
||||
}))
|
||||
|
||||
|
||||
register_test("//inset", make_parsing_test("inset", {
|
||||
"h 1",
|
||||
"v 0",
|
||||
"hv 2",
|
||||
"vh 3",
|
||||
}, {
|
||||
"x 4",
|
||||
"xyz 5",
|
||||
"v foo",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//shift", make_parsing_test("shift", {
|
||||
"x 1",
|
||||
"x -4",
|
||||
"back 1",
|
||||
"? 1",
|
||||
}, {
|
||||
"+z 1212",
|
||||
"-z 9",
|
||||
"xx -5",
|
||||
"?? 123",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//expand", make_parsing_test("expand", {
|
||||
"x 1",
|
||||
"z 1 2",
|
||||
"? 1",
|
||||
"+? 1",
|
||||
"+left 1",
|
||||
"-right 1",
|
||||
}, {
|
||||
"x -4",
|
||||
"? 4 -333",
|
||||
"stupid 5 5",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//cubeapply", make_parsing_test("cubeapply", {
|
||||
"2 orient 90",
|
||||
"2 3 4 orient 90",
|
||||
"1 1 1 drain",
|
||||
"4 stack z 1",
|
||||
}, {
|
||||
"1 1 1 orient",
|
||||
"0 drain",
|
||||
"4 stack z",
|
||||
"2 2 2 asasasasasas",
|
||||
"",
|
||||
}))
|
||||
|
||||
register_test("//save", make_parsing_test("save", {
|
||||
"filename",
|
||||
"filename.abc",
|
||||
}, {
|
||||
"\"hmm",
|
||||
"../../oops",
|
||||
"",
|
||||
}))
|
||||
@@ -1,32 +1,38 @@
|
||||
local S = minetest.get_translator("worldedit_commands")
|
||||
|
||||
local VALID_DIR = worldedit.valid_directions
|
||||
|
||||
local function check_region(name)
|
||||
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||
end
|
||||
|
||||
local function parse_copylike(param)
|
||||
local found, _, direction, amount = param:find("^([^%s]+)%s+([+-]?%d+)$")
|
||||
if found == nil or not VALID_DIR[direction] then
|
||||
return false
|
||||
end
|
||||
if tonumber(amount) == 0 then
|
||||
return false
|
||||
end
|
||||
return true, direction, tonumber(amount)
|
||||
end
|
||||
|
||||
worldedit.register_command("copy", {
|
||||
params = "x/y/z/? <amount>",
|
||||
params = tostring(VALID_DIR) .. " <amount>",
|
||||
description = S("Copy the current WorldEdit region along the given axis by <amount> nodes"),
|
||||
category = S("Transformations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
return false
|
||||
end
|
||||
return true, axis, tonumber(amount)
|
||||
end,
|
||||
nodes_needed = function(name, axis, amount)
|
||||
parse = parse_copylike,
|
||||
nodes_needed = function(name, direction, amount)
|
||||
return check_region(name) * 2
|
||||
end,
|
||||
func = function(name, axis, amount)
|
||||
if axis == "?" then
|
||||
local sign
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
amount = amount * sign
|
||||
func = function(name, direction, amount)
|
||||
local axis, sign = worldedit.player_direction(name, direction)
|
||||
if not axis or not sign then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
amount = amount * sign
|
||||
|
||||
local count = worldedit.copy(worldedit.pos1[name], worldedit.pos2[name], axis, amount)
|
||||
return true, S("@1 nodes copied", count)
|
||||
@@ -34,27 +40,21 @@ worldedit.register_command("copy", {
|
||||
})
|
||||
|
||||
worldedit.register_command("move", {
|
||||
params = "x/y/z/? <amount>",
|
||||
params = tostring(VALID_DIR) .. " <amount>",
|
||||
description = S("Move the current WorldEdit region along the given axis by <amount> nodes"),
|
||||
category = S("Transformations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
return false
|
||||
end
|
||||
return true, axis, tonumber(amount)
|
||||
end,
|
||||
nodes_needed = function(name, axis, amount)
|
||||
parse = parse_copylike,
|
||||
nodes_needed = function(name, direction, amount)
|
||||
return check_region(name) * 2
|
||||
end,
|
||||
func = function(name, axis, amount)
|
||||
if axis == "?" then
|
||||
local sign
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
amount = amount * sign
|
||||
func = function(name, direction, amount)
|
||||
local axis, sign = worldedit.player_direction(name, direction)
|
||||
if not axis or not sign then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
amount = amount * sign
|
||||
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local count = worldedit.move(pos1, pos2, axis, amount)
|
||||
@@ -67,27 +67,21 @@ worldedit.register_command("move", {
|
||||
})
|
||||
|
||||
worldedit.register_command("stack", {
|
||||
params = "x/y/z/? <count>",
|
||||
params = tostring(VALID_DIR) .. " <count>",
|
||||
description = S("Stack the current WorldEdit region along the given axis <count> times"),
|
||||
category = S("Transformations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
return false
|
||||
end
|
||||
return true, axis, tonumber(repetitions)
|
||||
end,
|
||||
nodes_needed = function(name, axis, repetitions)
|
||||
parse = parse_copylike,
|
||||
nodes_needed = function(name, direction, repetitions)
|
||||
return check_region(name) * math.abs(repetitions)
|
||||
end,
|
||||
func = function(name, axis, repetitions)
|
||||
if axis == "?" then
|
||||
local sign
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
repetitions = repetitions * sign
|
||||
func = function(name, direction, repetitions)
|
||||
local axis, sign = worldedit.player_direction(name, direction)
|
||||
if not axis or not sign then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
repetitions = repetitions * sign
|
||||
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local count = worldedit.volume(pos1, pos2) * math.abs(repetitions)
|
||||
@@ -149,7 +143,8 @@ worldedit.register_command("stretch", {
|
||||
end,
|
||||
func = function(name, stretchx, stretchy, stretchz)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)
|
||||
local count
|
||||
count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)
|
||||
|
||||
-- reset markers to scaled positions
|
||||
worldedit.pos1[name] = pos1
|
||||
@@ -180,7 +175,8 @@ worldedit.register_command("transpose", {
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if axis1 == "?" then axis1 = worldedit.player_axis(name) end
|
||||
if axis2 == "?" then axis2 = worldedit.player_axis(name) end
|
||||
local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
|
||||
local count
|
||||
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
|
||||
|
||||
-- reset markers to transposed positions
|
||||
worldedit.pos1[name] = pos1
|
||||
@@ -192,47 +188,56 @@ worldedit.register_command("transpose", {
|
||||
})
|
||||
|
||||
worldedit.register_command("flip", {
|
||||
params = "x/y/z/?",
|
||||
params = tostring(VALID_DIR),
|
||||
description = S("Flip the current WorldEdit region along the given axis"),
|
||||
category = S("Transformations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then
|
||||
if not VALID_DIR[param] then
|
||||
return false
|
||||
end
|
||||
return true, param
|
||||
end,
|
||||
nodes_needed = check_region,
|
||||
func = function(name, param)
|
||||
if param == "?" then param = worldedit.player_axis(name) end
|
||||
local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[name], param)
|
||||
local axis = worldedit.player_direction(name, param)
|
||||
if axis == nil then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
|
||||
local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[name], axis)
|
||||
return true, S("@1 nodes flipped", count)
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_command("rotate", {
|
||||
params = "x/y/z/? <angle>",
|
||||
params = tostring(VALID_DIR) .. " <angle>",
|
||||
description = S("Rotate the current WorldEdit region around the given axis by angle <angle> (90 degree increment)"),
|
||||
category = S("Transformations"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
local found, _, direction, angle = param:find("^([^%s]+)%s+([+-]?%d+)$")
|
||||
if found == nil or not VALID_DIR[direction] then
|
||||
return false
|
||||
end
|
||||
angle = tonumber(angle)
|
||||
if angle % 90 ~= 0 or angle % 360 == 0 then
|
||||
return false, S("invalid usage: angle must be multiple of 90")
|
||||
end
|
||||
return true, axis, angle
|
||||
return true, direction, angle
|
||||
end,
|
||||
nodes_needed = check_region,
|
||||
func = function(name, axis, angle)
|
||||
func = function(name, direction, angle)
|
||||
local axis = worldedit.player_direction(name, direction)
|
||||
if axis == nil then
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if axis == "?" then axis = worldedit.player_axis(name) end
|
||||
local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)
|
||||
local count
|
||||
count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)
|
||||
|
||||
-- reset markers to rotated positions
|
||||
worldedit.pos1[name] = pos1
|
||||
|
||||
@@ -11,7 +11,7 @@ end
|
||||
local punched_air_time = {}
|
||||
|
||||
minetest.register_tool(":worldedit:wand", {
|
||||
description = S("WorldEdit Wand tool\nLeft-click to set 1st position, right-click to set 2nd"),
|
||||
description = S("WorldEdit Wand tool") .. "\n" .. S("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
|
||||
|
||||
Reference in New Issue
Block a user