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:
|
cfg:
|
||||||
- { image: 'registry.gitlab.com/minetest/minetest/server:5.0.1', mtg: false }
|
- { 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: '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:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: 'minetest/minetest_game'
|
repository: 'luanti-org/minetest_game'
|
||||||
path: minetest_game
|
path: minetest_game
|
||||||
if: ${{ matrix.cfg.mtg }}
|
if: ${{ matrix.cfg.mtg }}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
tempdir=$(mktemp -d)
|
tempdir=$(mktemp -d)
|
||||||
confpath=$tempdir/minetest.conf
|
confpath=$tempdir/minetest.conf
|
||||||
worldpath=$tempdir/world
|
worldpath=$tempdir/world
|
||||||
|
modlist=(
|
||||||
|
worldedit
|
||||||
|
worldedit_commands
|
||||||
|
)
|
||||||
trap 'rm -rf "$tempdir"' EXIT
|
trap 'rm -rf "$tempdir"' EXIT
|
||||||
|
|
||||||
[ -f worldedit/mod.conf ] || { echo "Must be run in modpack root folder." >&2; exit 1; }
|
[ -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; }
|
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;
|
[ -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
|
else
|
||||||
mtserver=$(command -v minetestserver)
|
mtserver=$(command -v luantiserver)
|
||||||
[[ -z "$mtserver" && -x ../../bin/minetestserver ]] && mtserver=../../bin/minetestserver
|
[[ -z "$mtserver" && -x ../../bin/luantiserver ]] && mtserver=../../bin/luantiserver
|
||||||
[ -z "$mtserver" ] && { echo "To run the test outside of Docker, an installation of minetestserver is required." >&2; exit 1; }
|
[ -z "$mtserver" ] && { echo "To run the test outside of Docker, an installation of luantiserver is required." >&2; exit 1; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir $worldpath
|
mkdir $worldpath
|
||||||
@@ -22,19 +26,23 @@ printf '%s\n' worldedit_run_tests=true max_forceloaded_blocks=9999 >$confpath
|
|||||||
|
|
||||||
if [ -z "$mtserver" ]; then
|
if [ -z "$mtserver" ]; then
|
||||||
chmod -R 777 $tempdir
|
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=(
|
vol=(
|
||||||
-v "$confpath":/etc/minetest/minetest.conf
|
-v "$confpath":/etc/minetest/minetest.conf
|
||||||
-v "$tempdir":/var/lib/minetest/.minetest
|
-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+=(
|
[ -d minetest_game ] && vol+=(
|
||||||
-v "$PWD/minetest_game":/var/lib/minetest/.minetest/games/minetest_game
|
-v "$PWD/minetest_game":/var/lib/minetest/.minetest/games/minetest_game
|
||||||
)
|
)
|
||||||
docker run --rm -i "${vol[@]}" "$DOCKER_IMAGE"
|
docker run --rm -i "${vol[@]}" "$DOCKER_IMAGE"
|
||||||
else
|
else
|
||||||
mkdir $worldpath/worldmods
|
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
|
$mtserver --config "$confpath" --world "$worldpath" --logfile /dev/null
|
||||||
fi
|
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 set1 -30 5 28
|
||||||
//fixedpos set2 1004 -200 432
|
//fixedpos set2 1004 -200 432
|
||||||
|
|
||||||
|
Note that the `~` syntax can be used here to indicate a coordinate relative to the player.
|
||||||
|
|
||||||
### `//volume`
|
### `//volume`
|
||||||
|
|
||||||
Display the volume of the current WorldEdit region.
|
Display the volume of the current WorldEdit region.
|
||||||
@@ -107,7 +109,13 @@ Display the volume of the current WorldEdit region.
|
|||||||
|
|
||||||
### `//deleteblocks`
|
### `//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
|
//deleteblocks
|
||||||
|
|
||||||
@@ -262,7 +270,7 @@ height `<height>`, space between walls `<spacer>`, composed of `<node>`.
|
|||||||
//spiral 5 2 1 glass
|
//spiral 5 2 1 glass
|
||||||
//spiral 7 1 5 mesecons:wire_00000000_off
|
//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.
|
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 z +4
|
||||||
//copy ? 8
|
//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.
|
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 z +4
|
||||||
//move ? -1
|
//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.
|
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 z
|
||||||
//transpose ? y
|
//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 the current WorldEdit region along the given axis.
|
||||||
|
|
||||||
//flip x
|
//flip x
|
||||||
//flip ?
|
//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).
|
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`
|
### `//clearcut`
|
||||||
|
|
||||||
Removes any plant, tree or foilage-like nodes in the selected region.
|
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.
|
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
|
//clearcut
|
||||||
|
|
||||||
@@ -440,6 +450,7 @@ Valid values for `[rotation]` are 0, 90, 180 and 270.
|
|||||||
### `//mtschemprob start/finish/get`
|
### `//mtschemprob start/finish/get`
|
||||||
|
|
||||||
After using `//mtschemprob start` all nodes punched will bring up a text field where a probablity can be entered.
|
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.
|
This mode can be left with `//mtschemprob finish`. `//mtschemprob get` will display the probabilities saved for the nodes.
|
||||||
|
|
||||||
//mtschemprob get
|
//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
|
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.
|
WorldEdit position 1 when using that specific brush item.
|
||||||
Passing `none` instead clears the command assigned to the currently held 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.
|
Note that this functionality requires the `worldedit_brush` mod enabled.
|
||||||
|
|
||||||
//brush cube 8 8 8 Cobblestone
|
//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.
|
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.
|
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.
|
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
|
//cubeapply 10 replaceinverse air default:water_source
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -1,30 +1,32 @@
|
|||||||
WorldEdit v1.3
|
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
|
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.
|
Otherwise, you may install it manually:
|
||||||
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.
|
|
||||||
|
|
||||||
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)
|
1. Download the ZIP file from the [here](https://github.com/Uberi/Minetest-WorldEdit/archive/refs/heads/master.zip) (rolling release version)
|
||||||
or ask on the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) (slower but more likely to get help).
|
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
|
Usage
|
||||||
-----
|
-----
|
||||||
@@ -50,7 +52,8 @@ The chat interface adds many chat commands that perform various WorldEdit powere
|
|||||||
|
|
||||||
Compatibility
|
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.
|
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),
|
[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).
|
[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
|
WorldEdit API
|
||||||
-------------
|
-------------
|
||||||
@@ -72,7 +76,7 @@ This API is documented in the [WorldEdit API Reference](WorldEdit%20API.md).
|
|||||||
|
|
||||||
Axes
|
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 `?`.
|
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 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`.
|
Access to this format is done via specialized MTS commands such as `//mtschemcreate` and `//mtschemplace`.
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
|
|||||||
@@ -133,7 +133,9 @@ function mh.finish(manip, data)
|
|||||||
manip:set_data(data)
|
manip:set_data(data)
|
||||||
end
|
end
|
||||||
manip:write_to_map()
|
manip:write_to_map()
|
||||||
manip:update_map()
|
if manip.close ~= nil then
|
||||||
|
manip:close() -- explicitly free memory
|
||||||
|
end
|
||||||
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
|
-- @module worldedit
|
||||||
-- @release 1.3
|
-- @release 1.3
|
||||||
-- @copyright 2012 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote)
|
-- @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 .. "/serialization.lua")
|
||||||
load_module(path .. "/code.lua")
|
load_module(path .. "/code.lua")
|
||||||
load_module(path .. "/compatibility.lua")
|
load_module(path .. "/compatibility.lua")
|
||||||
load_module(path .. "/cuboid.lua")
|
|
||||||
|
|
||||||
|
|
||||||
if minetest.settings:get_bool("log_mods") then
|
if minetest.settings:get_bool("log_mods") then
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ function worldedit.set_param2(pos1, pos2, param2)
|
|||||||
|
|
||||||
-- Update map
|
-- Update map
|
||||||
manip:set_param2_data(param2_data)
|
manip:set_param2_data(param2_data)
|
||||||
manip:write_to_map()
|
mh.finish(manip)
|
||||||
manip:update_map()
|
|
||||||
|
|
||||||
return worldedit.volume(pos1, pos2)
|
return worldedit.volume(pos1, pos2)
|
||||||
end
|
end
|
||||||
@@ -269,8 +268,10 @@ function worldedit.fixlight(pos1, pos2)
|
|||||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
local vmanip = minetest.get_voxel_manip(pos1, pos2)
|
local vmanip = minetest.get_voxel_manip(pos1, pos2)
|
||||||
vmanip:write_to_map()
|
vmanip:write_to_map() -- this updates the lighting
|
||||||
vmanip:update_map() -- this updates the lighting
|
if vmanip.close ~= nil then
|
||||||
|
vmanip:close()
|
||||||
|
end
|
||||||
|
|
||||||
return worldedit.volume(pos1, pos2)
|
return worldedit.volume(pos1, pos2)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
---------------------
|
---------------------
|
||||||
local vec = vector.new
|
local vec = vector.new
|
||||||
local vecw = function(axis, n, base)
|
local vecw = function(axis, n, base)
|
||||||
local ret = vec(base)
|
local ret = vector.copy(base)
|
||||||
ret[axis] = n
|
ret[axis] = n
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ local brush_on_use = function(itemstack, placer)
|
|||||||
if cmd == "" then
|
if cmd == "" then
|
||||||
worldedit.player_notify(name,
|
worldedit.player_notify(name,
|
||||||
S("This brush is not bound, use @1 to bind a command to it.",
|
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
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ worldedit.register_command("brush", {
|
|||||||
local cmddef = worldedit.registered_commands[cmd]
|
local cmddef = worldedit.registered_commands[cmd]
|
||||||
if cmddef == nil or cmddef.require_pos ~= 1 then
|
if cmddef == nil or cmddef.require_pos ~= 1 then
|
||||||
return false, S("@1 cannot be used with brushes",
|
return false, S("@1 cannot be used with brushes",
|
||||||
minetest.colorize("#00ffff", "//"..cmd))
|
minetest.colorize("#0ff", "//"..cmd))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Try parsing command params so we can give the user feedback
|
-- 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("command", cmd)
|
||||||
meta:set_string("params", params)
|
meta:set_string("params", params)
|
||||||
local fullcmd = minetest.colorize("#00ffff", "//"..cmd) .. " " .. params
|
local fullcmd = minetest.colorize("#0ff", "//"..cmd) .. " " .. params
|
||||||
meta:set_string("description",
|
meta:set_string("description",
|
||||||
minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
|
minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
|
||||||
worldedit.player_notify(name, S("Brush assigned to command: @1", fullcmd), "ok")
|
worldedit.player_notify(name, S("Brush assigned to command: @1", fullcmd), "ok")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
local S = minetest.get_translator("worldedit_commands")
|
local S = minetest.get_translator("worldedit_commands")
|
||||||
|
|
||||||
|
local VALID_DIR = worldedit.valid_directions
|
||||||
|
|
||||||
worldedit.register_command("outset", {
|
worldedit.register_command("outset", {
|
||||||
params = "[h/v] <amount>",
|
params = "[h/v] <amount>",
|
||||||
description = S("Outset the selected region."),
|
description = S("Outset the selected region."),
|
||||||
@@ -7,7 +9,7 @@ worldedit.register_command("outset", {
|
|||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
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
|
if find == nil then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -47,7 +49,7 @@ worldedit.register_command("inset", {
|
|||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
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
|
if find == nil then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -79,29 +81,21 @@ worldedit.register_command("inset", {
|
|||||||
|
|
||||||
|
|
||||||
worldedit.register_command("shift", {
|
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"),
|
description = S("Shifts the selection area without moving its contents"),
|
||||||
category = S("Region operations"),
|
category = S("Region operations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
local find, _, direction, amount = param:find("([%?%l]+)%s*([+-]?%d+)")
|
local find, _, direction, amount = param:find("^([^%s]+)%s+([+-]?%d+)$")
|
||||||
if find == nil then
|
if find == nil or not VALID_DIR[direction] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true, direction, tonumber(amount)
|
return true, direction, tonumber(amount)
|
||||||
end,
|
end,
|
||||||
func = function(name, direction, amount)
|
func = function(name, direction, amount)
|
||||||
local axis, dir
|
local axis, dir = worldedit.player_direction(name, direction)
|
||||||
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
|
if axis == nil or dir == nil then
|
||||||
return false, S("Invalid if looking straight up or down")
|
return false, S("Invalid if looking straight up or down")
|
||||||
end
|
end
|
||||||
@@ -115,15 +109,15 @@ worldedit.register_command("shift", {
|
|||||||
|
|
||||||
|
|
||||||
worldedit.register_command("expand", {
|
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"),
|
description = S("Expands the selection in the selected absolute or relative axis"),
|
||||||
category = S("Region operations"),
|
category = S("Region operations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
local find, _, sign, direction, amount,
|
local find, _, sign, direction, amount,
|
||||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
rev_amount = param:find("^([+-]?)([^%s]+)%s+(%d+)%s*(%d*)$")
|
||||||
if find == nil then
|
if find == nil or not VALID_DIR[direction] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -134,24 +128,10 @@ worldedit.register_command("expand", {
|
|||||||
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
||||||
end,
|
end,
|
||||||
func = function(name, sign, direction, amount, rev_amount)
|
func = function(name, sign, direction, amount, rev_amount)
|
||||||
local absolute = direction:find("[xyz?]")
|
local axis, dir = worldedit.player_direction(name, direction)
|
||||||
local dir, axis
|
if axis == nil or dir == nil then
|
||||||
|
return false, S("Invalid if looking straight up or down")
|
||||||
if absolute == nil then
|
|
||||||
axis, dir = worldedit.translate_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
|
end
|
||||||
|
|
||||||
if sign == "-" then
|
if sign == "-" then
|
||||||
dir = -dir
|
dir = -dir
|
||||||
end
|
end
|
||||||
@@ -165,15 +145,15 @@ worldedit.register_command("expand", {
|
|||||||
|
|
||||||
|
|
||||||
worldedit.register_command("contract", {
|
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"),
|
description = S("Contracts the selection in the selected absolute or relative axis"),
|
||||||
category = S("Region operations"),
|
category = S("Region operations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
local find, _, sign, direction, amount,
|
local find, _, sign, direction, amount,
|
||||||
rev_amount = param:find("([+-]?)([%?%l]+)%s*(%d+)%s*(%d*)")
|
rev_amount = param:find("^([+-]?)([^%s]+)%s+(%d+)%s*(%d*)$")
|
||||||
if find == nil then
|
if find == nil or not VALID_DIR[direction] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -184,24 +164,10 @@ worldedit.register_command("contract", {
|
|||||||
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
return true, sign, direction, tonumber(amount), tonumber(rev_amount)
|
||||||
end,
|
end,
|
||||||
func = function(name, sign, direction, amount, rev_amount)
|
func = function(name, sign, direction, amount, rev_amount)
|
||||||
local absolute = direction:find("[xyz?]")
|
local axis, dir = worldedit.player_direction(name, direction)
|
||||||
local dir, axis
|
if axis == nil or dir == nil then
|
||||||
|
return false, S("Invalid if looking straight up or down")
|
||||||
if absolute == nil then
|
|
||||||
axis, dir = worldedit.translate_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
|
end
|
||||||
|
|
||||||
if sign == "-" then
|
if sign == "-" then
|
||||||
dir = -dir
|
dir = -dir
|
||||||
end
|
end
|
||||||
@@ -238,7 +204,7 @@ worldedit.register_command("cubeapply", {
|
|||||||
local cmddef = worldedit.registered_commands[cmd]
|
local cmddef = worldedit.registered_commands[cmd]
|
||||||
if cmddef == nil or cmddef.require_pos ~= 2 then
|
if cmddef == nil or cmddef.require_pos ~= 2 then
|
||||||
return false, S("invalid usage: @1 cannot be used with cubeapply",
|
return false, S("invalid usage: @1 cannot be used with cubeapply",
|
||||||
minetest.colorize("#00ffff", "//"..cmd))
|
minetest.colorize("#0ff", "//"..cmd))
|
||||||
end
|
end
|
||||||
-- run parsing of target command
|
-- run parsing of target command
|
||||||
local parsed = {cmddef.parse(args)}
|
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
|
||||||
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 function chatcommand_handler(cmd_name, name, param)
|
||||||
local def = assert(worldedit.registered_commands[cmd_name])
|
local def = assert(worldedit.registered_commands[cmd_name])
|
||||||
|
|
||||||
@@ -42,6 +51,7 @@ local function chatcommand_handler(cmd_name, name, param)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
param = param:trim()
|
||||||
local parsed = {def.parse(param)}
|
local parsed = {def.parse(param)}
|
||||||
local success = table.remove(parsed, 1)
|
local success = table.remove(parsed, 1)
|
||||||
if not success then
|
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)
|
local old_state = copy_state(def.require_pos, name)
|
||||||
safe_region(name, count, function()
|
safe_region(name, count, function()
|
||||||
local state = copy_state(def.require_pos, name)
|
local state = copy_state(def.require_pos, name)
|
||||||
local ok = true
|
if not compare_state(state, old_state) then
|
||||||
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
|
|
||||||
worldedit.player_notify(name, S("ERROR: the operation was cancelled because the region has changed."), "error")
|
worldedit.player_notify(name, S("ERROR: the operation was cancelled because the region has changed."), "error")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -111,7 +117,9 @@ function worldedit.register_command(name, def)
|
|||||||
def.require_pos = def.require_pos or 0
|
def.require_pos = def.require_pos or 0
|
||||||
assert(def.require_pos >= 0 and def.require_pos < 3)
|
assert(def.require_pos >= 0 and def.require_pos < 3)
|
||||||
if def.params == "" and not def.parse then
|
if def.params == "" and not def.parse then
|
||||||
def.parse = function(param) return true end
|
def.parse = function(param)
|
||||||
|
return param == ""
|
||||||
|
end
|
||||||
else
|
else
|
||||||
assert(def.parse)
|
assert(def.parse)
|
||||||
end
|
end
|
||||||
@@ -124,7 +132,7 @@ function worldedit.register_command(name, def)
|
|||||||
end--]]
|
end--]]
|
||||||
|
|
||||||
-- disable further modification
|
-- disable further modification
|
||||||
setmetatable(def, {__newindex = {}})
|
setmetatable(def, {__newindex = function() end})
|
||||||
|
|
||||||
minetest.register_chatcommand("/" .. name, {
|
minetest.register_chatcommand("/" .. name, {
|
||||||
privs = def.privs,
|
privs = def.privs,
|
||||||
@@ -137,18 +145,6 @@ function worldedit.register_command(name, def)
|
|||||||
worldedit.registered_commands[name] = def
|
worldedit.registered_commands[name] = def
|
||||||
end
|
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.
|
-- Notifies a player of something related to WorldEdit.
|
||||||
-- Message types:
|
-- Message types:
|
||||||
-- "error" = An operation did not work as expected.
|
-- "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, " "))
|
minetest.chat_send_player(name, table.concat(t, " "))
|
||||||
end
|
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)
|
function worldedit.player_axis(name)
|
||||||
local player = minetest.get_player_by_name(name)
|
local player = minetest.get_player_by_name(name)
|
||||||
if not player then
|
if not player then
|
||||||
@@ -191,6 +189,79 @@ function worldedit.player_axis(name)
|
|||||||
return "z", dir.z > 0 and 1 or -1
|
return "z", dir.z > 0 and 1 or -1
|
||||||
end
|
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", {
|
worldedit.register_command("about", {
|
||||||
privs = {},
|
privs = {},
|
||||||
@@ -200,7 +271,7 @@ worldedit.register_command("about", {
|
|||||||
worldedit.player_notify(name, S("WorldEdit @1"..
|
worldedit.player_notify(name, S("WorldEdit @1"..
|
||||||
" is available on this server. Type @2 to get a list of "..
|
" is available on this server. Type @2 to get a list of "..
|
||||||
"commands, or find more information at @3",
|
"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"
|
"https://github.com/Uberi/Minetest-WorldEdit"
|
||||||
), "info")
|
), "info")
|
||||||
end,
|
end,
|
||||||
@@ -209,10 +280,10 @@ worldedit.register_command("about", {
|
|||||||
-- initially copied from builtin/chatcommands.lua
|
-- initially copied from builtin/chatcommands.lua
|
||||||
local function help_command(name, param)
|
local function help_command(name, param)
|
||||||
local function format_help_line(cmd, def, follow_alias)
|
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
|
if def.name ~= cmd then
|
||||||
msg = msg .. ": " .. S("alias to @1",
|
msg = msg .. ": " .. S("alias to @1",
|
||||||
minetest.colorize("#00ffff", "//"..def.name))
|
minetest.colorize("#0ff", "//"..def.name))
|
||||||
if follow_alias then
|
if follow_alias then
|
||||||
msg = msg .. "\n" .. format_help_line(def.name, def)
|
msg = msg .. "\n" .. format_help_line(def.name, def)
|
||||||
end
|
end
|
||||||
@@ -255,7 +326,7 @@ local function help_command(name, param)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(list)
|
table.sort(list)
|
||||||
local help = minetest.colorize("#00ffff", "//help")
|
local help = minetest.colorize("#0ff", "//help")
|
||||||
return true, S("Available commands: @1@n"
|
return true, S("Available commands: @1@n"
|
||||||
.. "Use '@2' to get more information,"
|
.. "Use '@2' to get more information,"
|
||||||
.. " or '@3' to list everything.",
|
.. " or '@3' to list everything.",
|
||||||
@@ -320,3 +391,17 @@ worldedit.register_command("reset", {
|
|||||||
end,
|
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: @2=
|
||||||
position @1 not set=
|
position @1 not set=
|
||||||
Set a WorldEdit region position to the position at (<x>, <y>, <z>)=
|
Set a WorldEdit region position to the position at (<x>, <y>, <z>)=
|
||||||
|
invalid position=
|
||||||
Display the volume of the current WorldEdit region=
|
Display the volume of the current WorldEdit region=
|
||||||
current region has a volume of @1 nodes (@2*@3*@4)=
|
current region has a volume of @1 nodes (@2*@3*@4)=
|
||||||
Remove all MapBlocks (16x16x16) containing the selected area from the map=
|
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=
|
Confirm a pending operation=
|
||||||
no operation pending=
|
no operation pending=
|
||||||
Abort a pending operation=
|
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: @2=Position @1: @2
|
||||||
position @1 not set=Position @1 ist nicht gesetzt
|
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
|
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
|
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)
|
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
|
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
|
Confirm a pending operation=Einen ausstehenden Vorgang bestätigen
|
||||||
no operation pending=Kein Vorgang ausstehend
|
no operation pending=Kein Vorgang ausstehend
|
||||||
Abort a pending operation=Einen ausstehenden Vorgang abbrechen
|
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 нод(а/ы)
|
@1 nodes stacked=размножено @1 нод(а/ы)
|
||||||
Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>=Размножить текущий WorldEdit-регион <count> раз с шагом <x>, <y>, <z> по соответствующим осям
|
Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>=Размножить текущий WorldEdit-регион <count> раз с шагом <x>, <y>, <z> по соответствующим осям
|
||||||
invalid count: @1=неверное количество: @1
|
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 в качестве точки отсчёта
|
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
|
invalid scaling factors: @1=неверные коэффициенты масштабирования: @1
|
||||||
@1 nodes stretched=масштабировано @1 нод(а/ы)
|
@1 nodes stretched=масштабировано @1 нод(а/ы)
|
||||||
@@ -152,4 +152,5 @@ invalid usage: @1 cannot be used with cubeapply=недопустимое исп
|
|||||||
Missing privileges: @1=Отсутствуют привилегии: @1
|
Missing privileges: @1=Отсутствуют привилегии: @1
|
||||||
|
|
||||||
### wand.lua ###
|
### 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
|
local strip_escapes = minetest.strip_escapes or function(input)
|
||||||
-- https://github.com/minetest/minetest/blob/53dd7819277c53954d1298dfffa5287c306db8d0/src/util/string.cpp#L777
|
|
||||||
local function strip_escapes(input)
|
|
||||||
local s = function(idx) return input:sub(idx, idx) end
|
local s = function(idx) return input:sub(idx, idx) end
|
||||||
local out = ""
|
local out = ""
|
||||||
local i = 1
|
local i = 1
|
||||||
@@ -22,42 +20,63 @@ local function strip_escapes(input)
|
|||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
--print(("%q -> %q"):format(input, out))
|
|
||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
local function string_endswith(full, part)
|
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
|
end
|
||||||
|
|
||||||
local description_cache = nil
|
local description_cache = nil
|
||||||
|
|
||||||
-- normalizes node "description" `nodename`, returning a string (or nil)
|
-- normalizes node "description" `nodename`, returning a string (or nil)
|
||||||
worldedit.normalize_nodename = function(nodename)
|
worldedit.normalize_nodename = function(nodename)
|
||||||
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
|
nodename = nodename:trim()
|
||||||
if nodename == "" then return nil end
|
if nodename == "" then
|
||||||
|
return nil
|
||||||
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
|
|
||||||
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
|
|
||||||
return fullname
|
|
||||||
end
|
end
|
||||||
nodename = nodename:lower()
|
|
||||||
|
|
||||||
|
if nodename:find(" ", 1, true) == nil then
|
||||||
|
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
|
||||||
|
if minetest.registered_nodes[fullname] then -- full name
|
||||||
|
return fullname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local match
|
||||||
for key, _ in pairs(minetest.registered_nodes) do
|
for key, _ in pairs(minetest.registered_nodes) do
|
||||||
if string_endswith(key:lower(), ":" .. nodename) then -- matches name (w/o mod part)
|
if string_endswith(key, ":" .. nodename) then
|
||||||
return key
|
if match then
|
||||||
|
match = nil
|
||||||
|
break
|
||||||
|
end
|
||||||
|
match = key -- matches name w/o mod part (only if unique)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if match then
|
||||||
|
return match
|
||||||
|
end
|
||||||
|
|
||||||
|
nodename = nodename:lower()
|
||||||
if description_cache == nil then
|
if description_cache == nil then
|
||||||
-- cache stripped descriptions
|
-- Note: since we don't handle translations this will work only in the original
|
||||||
description_cache = {}
|
-- language of the description (English)
|
||||||
for key, value in pairs(minetest.registered_nodes) do
|
description_cache = make_description_cache()
|
||||||
local desc = strip_escapes(value.description):gsub("\n.*", "", 1):lower()
|
|
||||||
if desc ~= "" then
|
|
||||||
description_cache[key] = desc
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for key, desc in pairs(description_cache) do
|
for key, desc in pairs(description_cache) do
|
||||||
@@ -72,14 +91,16 @@ worldedit.normalize_nodename = function(nodename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local match = nil
|
match = nil
|
||||||
for key, value in pairs(description_cache) do
|
for key, value in pairs(description_cache) do
|
||||||
if value:find(nodename, 1, true) ~= nil then
|
if value:find(nodename, 1, true) ~= nil then
|
||||||
if match ~= nil then
|
if match then
|
||||||
return nil
|
match = nil
|
||||||
|
break
|
||||||
end
|
end
|
||||||
match = key -- substring description match (only if no ambiguities)
|
match = key -- substring description match (only if unique)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return match
|
return match
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ worldedit.register_command("unmark", {
|
|||||||
|
|
||||||
local function set_pos1(name, pos)
|
local function set_pos1(name, pos)
|
||||||
assert(pos)
|
assert(pos)
|
||||||
|
pos = vector.round(pos)
|
||||||
worldedit.pos1[name] = pos
|
worldedit.pos1[name] = pos
|
||||||
worldedit.mark_pos1(name)
|
worldedit.mark_pos1(name)
|
||||||
worldedit.player_notify(name, S("position @1 set to @2", 1, minetest.pos_to_string(pos)), "ok")
|
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)
|
local function set_pos2(name, pos)
|
||||||
assert(pos)
|
assert(pos)
|
||||||
|
pos = vector.round(pos)
|
||||||
worldedit.pos2[name] = pos
|
worldedit.pos2[name] = pos
|
||||||
worldedit.mark_pos2(name)
|
worldedit.mark_pos2(name)
|
||||||
worldedit.player_notify(name, S("position @1 set to @2", 2, minetest.pos_to_string(pos)), "ok")
|
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)
|
func = function(name)
|
||||||
local player = minetest.get_player_by_name(name)
|
local player = minetest.get_player_by_name(name)
|
||||||
if not player then return end
|
if not player then return end
|
||||||
set_pos1(name, vector.round(player:get_pos()))
|
set_pos1(name, player:get_pos())
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -127,7 +129,7 @@ worldedit.register_command("pos2", {
|
|||||||
func = function(name)
|
func = function(name)
|
||||||
local player = minetest.get_player_by_name(name)
|
local player = minetest.get_player_by_name(name)
|
||||||
if not player then return end
|
if not player then return end
|
||||||
set_pos2(name, vector.round(player:get_pos()))
|
set_pos2(name, player:get_pos())
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -178,13 +180,18 @@ worldedit.register_command("fixedpos", {
|
|||||||
category = S("Region operations"),
|
category = S("Region operations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
local found, _, flag, x, y, z = param:find("^(set[12])%s+([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)$")
|
local found, _, flag, x, y, z = param:find("^(set[12])%s+(~?[+-]?%d+)%s+(~?[+-]?%d+)%s+(~?[+-]?%d+)$")
|
||||||
if found == nil then
|
if not found then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true, flag, vector.new(tonumber(x), tonumber(y), tonumber(z))
|
return true, flag, x, y, z
|
||||||
end,
|
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
|
if flag == "set1" then
|
||||||
set_pos1(name, pos)
|
set_pos1(name, pos)
|
||||||
else --flag == "set2"
|
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)
|
count_str = minetest.colorize("#f33", count_str:sub(1, -7)) .. count_str:sub(-6, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
local yes_cmd = minetest.colorize("#00ffff", "//y")
|
local yes_cmd = minetest.colorize("#0ff", "//y")
|
||||||
local no_cmd = minetest.colorize("#00ffff", "//n")
|
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",
|
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)
|
count_str, yes_cmd, no_cmd)
|
||||||
worldedit.player_notify(name, msg, "info")
|
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 S = minetest.get_translator("worldedit_commands")
|
||||||
|
|
||||||
|
local VALID_DIR = worldedit.valid_directions
|
||||||
|
|
||||||
local function check_region(name)
|
local function check_region(name)
|
||||||
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||||
end
|
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", {
|
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"),
|
description = S("Copy the current WorldEdit region along the given axis by <amount> nodes"),
|
||||||
category = S("Transformations"),
|
category = S("Transformations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = parse_copylike,
|
||||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
nodes_needed = function(name, direction, amount)
|
||||||
if found == nil then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true, axis, tonumber(amount)
|
|
||||||
end,
|
|
||||||
nodes_needed = function(name, axis, amount)
|
|
||||||
return check_region(name) * 2
|
return check_region(name) * 2
|
||||||
end,
|
end,
|
||||||
func = function(name, axis, amount)
|
func = function(name, direction, amount)
|
||||||
if axis == "?" then
|
local axis, sign = worldedit.player_direction(name, direction)
|
||||||
local sign
|
if not axis or not sign then
|
||||||
axis, sign = worldedit.player_axis(name)
|
return false, S("Invalid if looking straight up or down")
|
||||||
amount = amount * sign
|
|
||||||
end
|
end
|
||||||
|
amount = amount * sign
|
||||||
|
|
||||||
local count = worldedit.copy(worldedit.pos1[name], worldedit.pos2[name], axis, amount)
|
local count = worldedit.copy(worldedit.pos1[name], worldedit.pos2[name], axis, amount)
|
||||||
return true, S("@1 nodes copied", count)
|
return true, S("@1 nodes copied", count)
|
||||||
@@ -34,27 +40,21 @@ worldedit.register_command("copy", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
worldedit.register_command("move", {
|
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"),
|
description = S("Move the current WorldEdit region along the given axis by <amount> nodes"),
|
||||||
category = S("Transformations"),
|
category = S("Transformations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = parse_copylike,
|
||||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
nodes_needed = function(name, direction, amount)
|
||||||
if found == nil then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true, axis, tonumber(amount)
|
|
||||||
end,
|
|
||||||
nodes_needed = function(name, axis, amount)
|
|
||||||
return check_region(name) * 2
|
return check_region(name) * 2
|
||||||
end,
|
end,
|
||||||
func = function(name, axis, amount)
|
func = function(name, direction, amount)
|
||||||
if axis == "?" then
|
local axis, sign = worldedit.player_direction(name, direction)
|
||||||
local sign
|
if not axis or not sign then
|
||||||
axis, sign = worldedit.player_axis(name)
|
return false, S("Invalid if looking straight up or down")
|
||||||
amount = amount * sign
|
|
||||||
end
|
end
|
||||||
|
amount = amount * sign
|
||||||
|
|
||||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
local count = worldedit.move(pos1, pos2, axis, amount)
|
local count = worldedit.move(pos1, pos2, axis, amount)
|
||||||
@@ -67,27 +67,21 @@ worldedit.register_command("move", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
worldedit.register_command("stack", {
|
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"),
|
description = S("Stack the current WorldEdit region along the given axis <count> times"),
|
||||||
category = S("Transformations"),
|
category = S("Transformations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = parse_copylike,
|
||||||
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
nodes_needed = function(name, direction, repetitions)
|
||||||
if found == nil then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true, axis, tonumber(repetitions)
|
|
||||||
end,
|
|
||||||
nodes_needed = function(name, axis, repetitions)
|
|
||||||
return check_region(name) * math.abs(repetitions)
|
return check_region(name) * math.abs(repetitions)
|
||||||
end,
|
end,
|
||||||
func = function(name, axis, repetitions)
|
func = function(name, direction, repetitions)
|
||||||
if axis == "?" then
|
local axis, sign = worldedit.player_direction(name, direction)
|
||||||
local sign
|
if not axis or not sign then
|
||||||
axis, sign = worldedit.player_axis(name)
|
return false, S("Invalid if looking straight up or down")
|
||||||
repetitions = repetitions * sign
|
|
||||||
end
|
end
|
||||||
|
repetitions = repetitions * sign
|
||||||
|
|
||||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
local count = worldedit.volume(pos1, pos2) * math.abs(repetitions)
|
local count = worldedit.volume(pos1, pos2) * math.abs(repetitions)
|
||||||
@@ -149,9 +143,10 @@ worldedit.register_command("stretch", {
|
|||||||
end,
|
end,
|
||||||
func = function(name, stretchx, stretchy, stretchz)
|
func = function(name, stretchx, stretchy, stretchz)
|
||||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
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
|
-- reset markers to scaled positions
|
||||||
worldedit.pos1[name] = pos1
|
worldedit.pos1[name] = pos1
|
||||||
worldedit.pos2[name] = pos2
|
worldedit.pos2[name] = pos2
|
||||||
worldedit.marker_update(name)
|
worldedit.marker_update(name)
|
||||||
@@ -180,9 +175,10 @@ worldedit.register_command("transpose", {
|
|||||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
if axis1 == "?" then axis1 = worldedit.player_axis(name) end
|
if axis1 == "?" then axis1 = worldedit.player_axis(name) end
|
||||||
if axis2 == "?" then axis2 = 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
|
-- reset markers to transposed positions
|
||||||
worldedit.pos1[name] = pos1
|
worldedit.pos1[name] = pos1
|
||||||
worldedit.pos2[name] = pos2
|
worldedit.pos2[name] = pos2
|
||||||
worldedit.marker_update(name)
|
worldedit.marker_update(name)
|
||||||
@@ -192,49 +188,58 @@ worldedit.register_command("transpose", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
worldedit.register_command("flip", {
|
worldedit.register_command("flip", {
|
||||||
params = "x/y/z/?",
|
params = tostring(VALID_DIR),
|
||||||
description = S("Flip the current WorldEdit region along the given axis"),
|
description = S("Flip the current WorldEdit region along the given axis"),
|
||||||
category = S("Transformations"),
|
category = S("Transformations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then
|
if not VALID_DIR[param] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true, param
|
return true, param
|
||||||
end,
|
end,
|
||||||
nodes_needed = check_region,
|
nodes_needed = check_region,
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if param == "?" then param = worldedit.player_axis(name) end
|
local axis = worldedit.player_direction(name, param)
|
||||||
local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[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)
|
return true, S("@1 nodes flipped", count)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
worldedit.register_command("rotate", {
|
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)"),
|
description = S("Rotate the current WorldEdit region around the given axis by angle <angle> (90 degree increment)"),
|
||||||
category = S("Transformations"),
|
category = S("Transformations"),
|
||||||
privs = {worldedit=true},
|
privs = {worldedit=true},
|
||||||
require_pos = 2,
|
require_pos = 2,
|
||||||
parse = function(param)
|
parse = function(param)
|
||||||
local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
local found, _, direction, angle = param:find("^([^%s]+)%s+([+-]?%d+)$")
|
||||||
if found == nil then
|
if found == nil or not VALID_DIR[direction] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
angle = tonumber(angle)
|
angle = tonumber(angle)
|
||||||
if angle % 90 ~= 0 or angle % 360 == 0 then
|
if angle % 90 ~= 0 or angle % 360 == 0 then
|
||||||
return false, S("invalid usage: angle must be multiple of 90")
|
return false, S("invalid usage: angle must be multiple of 90")
|
||||||
end
|
end
|
||||||
return true, axis, angle
|
return true, direction, angle
|
||||||
end,
|
end,
|
||||||
nodes_needed = check_region,
|
nodes_needed = check_region,
|
||||||
func = function(name, axis, angle)
|
func = function(name, direction, angle)
|
||||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
local axis = worldedit.player_direction(name, direction)
|
||||||
if axis == "?" then axis = worldedit.player_axis(name) end
|
if axis == nil then
|
||||||
local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)
|
return false, S("Invalid if looking straight up or down")
|
||||||
|
end
|
||||||
|
|
||||||
--reset markers to rotated positions
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
|
local count
|
||||||
|
count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)
|
||||||
|
|
||||||
|
-- reset markers to rotated positions
|
||||||
worldedit.pos1[name] = pos1
|
worldedit.pos1[name] = pos1
|
||||||
worldedit.pos2[name] = pos2
|
worldedit.pos2[name] = pos2
|
||||||
worldedit.marker_update(name)
|
worldedit.marker_update(name)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ end
|
|||||||
local punched_air_time = {}
|
local punched_air_time = {}
|
||||||
|
|
||||||
minetest.register_tool(":worldedit:wand", {
|
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",
|
inventory_image = "worldedit_wand.png",
|
||||||
stack_max = 1, -- there is no need to have more than one
|
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
|
liquids_pointable = true, -- ground with only water on can be selected as well
|
||||||
|
|||||||
Reference in New Issue
Block a user