Compare commits
27 Commits
new_schems
...
341014f94a
Author | SHA1 | Date | |
---|---|---|---|
341014f94a | |||
b84aa8508a | |||
17df0bbf71 | |||
36b14413e0 | |||
1fc6d93112 | |||
ccfb6b4d61 | |||
8f60e6f729 | |||
8f86a2120c | |||
b4202ea779 | |||
689ff90a78 | |||
bf55f52197 | |||
79e5e64c44 | |||
375fbf3c68 | |||
cc3aab00bc | |||
eff01bc8e7 | |||
099d5047bd | |||
7f7e928dd9 | |||
1a9f66f091 | |||
7a5d76a9bc | |||
5260f595c6 | |||
7a645eba05 | |||
9417f2bbf1 | |||
abc9efeeb8 | |||
c223ca4cec | |||
c8afa95542 | |||
670e421f57 | |||
770601dd5d |
15
.github/workflows/check.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: "Check"
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: "Luacheck"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: apt
|
||||
run: sudo apt-get install -y luarocks
|
||||
- name: luacheck install
|
||||
run: luarocks install --local luacheck
|
||||
- name: luacheck run
|
||||
run: $HOME/.luarocks/bin/luacheck ./
|
11
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
name: "Test"
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "Unittests"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run tests
|
||||
run: MINETEST_VER=latest ./.util/run_tests.sh
|
7
.luacheckrc
Normal file
@ -0,0 +1,7 @@
|
||||
read_globals = {"minetest", "vector", "VoxelArea", "ItemStack",
|
||||
"table",
|
||||
"unified_inventory", "sfinv", "smart_inventory", "inventory_plus"
|
||||
}
|
||||
globals = {"worldedit"}
|
||||
-- Ignore these errors until someone decides to fix them
|
||||
ignore = {"212", "213", "411", "412", "421", "422", "431", "432", "631"}
|
30
.util/run_tests.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
tempdir=/tmp/mt
|
||||
confpath=$tempdir/minetest.conf
|
||||
worldpath=$tempdir/world
|
||||
|
||||
use_docker=y
|
||||
[ -x ../../bin/minetestserver ] && use_docker=
|
||||
|
||||
rm -rf $tempdir
|
||||
mkdir -p $worldpath
|
||||
# the docker image doesn't have devtest
|
||||
[ -n "$use_docker" ] || printf '%s\n' gameid=devtest >$worldpath/world.mt
|
||||
printf '%s\n' mg_name=singlenode '[end_of_params]' >$worldpath/map_meta.txt
|
||||
printf '%s\n' worldedit_run_tests=true max_forceloaded_blocks=9999 >$confpath
|
||||
|
||||
if [ -n "$use_docker" ]; then
|
||||
chmod -R 777 $tempdir
|
||||
docker run --rm -i \
|
||||
-v $confpath:/etc/minetest/minetest.conf \
|
||||
-v $tempdir:/var/lib/minetest/.minetest \
|
||||
-v "$PWD/worldedit":/var/lib/minetest/.minetest/world/worldmods/worldedit \
|
||||
registry.gitlab.com/minetest/minetest/server:${MINETEST_VER}
|
||||
else
|
||||
mkdir $worldpath/worldmods
|
||||
ln -s "$PWD/worldedit" $worldpath/worldmods/worldedit
|
||||
../../bin/minetestserver --config $confpath --world $worldpath --logfile /dev/null
|
||||
fi
|
||||
|
||||
test -f $worldpath/tests_ok || exit 1
|
||||
exit 0
|
@ -23,7 +23,7 @@ There is a nice installation guide over at the [Minetest Wiki](http://wiki.minet
|
||||
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://webchat.freenode.net/?channels=#minetest) (faster but may not always have helpers online)
|
||||
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).
|
||||
|
||||
Usage
|
||||
|
@ -1,2 +1,3 @@
|
||||
name = Minetest-WorldEdit
|
||||
description = WorldEdit is an in-game world editor. Use it to repair griefing, or just create awesome buildings in seconds.
|
||||
min_minetest_version = 5.0
|
||||
|
@ -31,7 +31,7 @@ function worldedit.luatransform(pos1, pos2, code)
|
||||
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
|
@ -5,8 +5,8 @@
|
||||
-- `pos1` is less than or equal to the corresponding component of `pos2`.
|
||||
-- Returns the new positions.
|
||||
function worldedit.sort_pos(pos1, pos2)
|
||||
pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||
pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
pos1 = vector.new(pos1.x, pos1.y, pos1.z)
|
||||
pos2 = vector.new(pos2.x, pos2.y, pos2.z)
|
||||
if pos1.x > pos2.x then
|
||||
pos2.x, pos1.x = pos1.x, pos2.x
|
||||
end
|
||||
|
@ -24,11 +24,14 @@ function worldedit.metasave(pos1, pos2, filename)
|
||||
return count
|
||||
end
|
||||
|
||||
function worldedit.metaload(originpos, filename)
|
||||
function worldedit.metaload(originpos, file_name)
|
||||
deprecated("load")
|
||||
filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err then return 0 end
|
||||
local file_path = minetest.get_worldpath() ..
|
||||
"/schems/" .. file_name .. ".wem"
|
||||
local file, err = io.open(file_path, "wb")
|
||||
if err then
|
||||
return 0
|
||||
end
|
||||
local data = file:read("*a")
|
||||
return worldedit.deserialize(originpos, data)
|
||||
end
|
||||
|
@ -2,16 +2,16 @@
|
||||
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)
|
||||
@ -19,7 +19,7 @@ worldedit.cuboid_volumetric_expand = function(name, amount)
|
||||
delta2 = vector.multiply(delta2, delta_dir2)
|
||||
worldedit.pos1[name] = vector.add(pos1, delta1)
|
||||
worldedit.pos2[name] = vector.add(pos2, delta2)
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -28,18 +28,18 @@ end
|
||||
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
|
||||
@ -49,7 +49,7 @@ worldedit.cuboid_linear_expand = function(name, axis, direction, amount)
|
||||
else
|
||||
return false, "invalid axis"
|
||||
end
|
||||
|
||||
|
||||
worldedit.marker_move(name, marker, deltavect)
|
||||
return true
|
||||
end
|
||||
@ -59,11 +59,11 @@ end
|
||||
worldedit.cuboid_shift = function(name, axis, amount)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
|
||||
if pos1 == nil or pos2 == nil then
|
||||
return false, "undefined cuboid"
|
||||
end
|
||||
|
||||
|
||||
if axis == 'x' then
|
||||
worldedit.pos1[name].x = pos1.x + amount
|
||||
worldedit.pos2[name].x = pos2.x + amount
|
||||
@ -76,7 +76,7 @@ worldedit.cuboid_shift = function(name, axis, amount)
|
||||
else
|
||||
return false, "invalid axis"
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -86,7 +86,7 @@ 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)
|
||||
@ -94,7 +94,7 @@ worldedit.marker_move = function(name, marker, deltavector)
|
||||
local pos = worldedit.pos2[name]
|
||||
worldedit.pos2[name] = vector.add(deltavector, pos)
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -137,7 +137,7 @@ worldedit.marker_get_closest_to_player = function(name)
|
||||
local playerpos = minetest.get_player_by_name(name):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
|
||||
@ -150,7 +150,7 @@ end
|
||||
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
|
||||
@ -185,20 +185,20 @@ worldedit.marker_get_closest_to_axis = function(name, axis, direction)
|
||||
end
|
||||
|
||||
|
||||
-- Translates up, down, left, right, front, back to their corresponding axes and
|
||||
-- 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
|
||||
@ -208,7 +208,7 @@ worldedit.translate_direction = function(name, direction)
|
||||
resdir = dir
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if direction == "back" then
|
||||
if axis == "y" then
|
||||
resaxis = nil
|
||||
@ -218,7 +218,7 @@ worldedit.translate_direction = function(name, direction)
|
||||
resdir = -dir
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if direction == "left" then
|
||||
if axis == 'x' then
|
||||
resaxis = 'z'
|
||||
@ -228,7 +228,7 @@ worldedit.translate_direction = function(name, direction)
|
||||
resdir = -dir
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if direction == "right" then
|
||||
if axis == 'x' then
|
||||
resaxis = 'z'
|
||||
@ -238,6 +238,6 @@ worldedit.translate_direction = function(name, direction)
|
||||
resdir = dir
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return resaxis, resdir
|
||||
end
|
||||
|
@ -38,3 +38,7 @@ if minetest.settings:get_bool("log_mods") then
|
||||
print("[WorldEdit] Loaded!")
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("worldedit_run_tests") then
|
||||
dofile(path .. "/test.lua")
|
||||
minetest.after(0, worldedit.run_tests)
|
||||
end
|
||||
|
@ -101,7 +101,7 @@ end
|
||||
local function deferred_execution(next_one, finished)
|
||||
-- Allocate 100% of server step for execution (might lag a little)
|
||||
local allocated_usecs =
|
||||
tonumber(minetest.settings:get("dedicated_server_step")) * 1000000
|
||||
tonumber(minetest.settings:get("dedicated_server_step"):split(" ")[1]) * 1000000
|
||||
local function f()
|
||||
local deadline = minetest.get_us_time() + allocated_usecs
|
||||
repeat
|
||||
@ -128,7 +128,7 @@ function worldedit.stack2(pos1, pos2, direction, amount, finished)
|
||||
direction = table.copy(direction)
|
||||
|
||||
local i = 0
|
||||
local translated = {x=0, y=0, z=0}
|
||||
local translated = vector.new()
|
||||
local function step()
|
||||
translated.x = translated.x + direction.x
|
||||
translated.y = translated.y + direction.y
|
||||
@ -155,7 +155,7 @@ function worldedit.copy(pos1, pos2, axis, amount)
|
||||
-- Decide if we need to copy stuff backwards (only applies to metadata)
|
||||
local backwards = amount > 0 and amount < (pos2[axis] - pos1[axis] + 1)
|
||||
|
||||
local off = {x=0, y=0, z=0}
|
||||
local off = vector.new()
|
||||
off[axis] = amount
|
||||
return worldedit.copy2(pos1, pos2, off, backwards)
|
||||
end
|
||||
@ -170,7 +170,7 @@ function worldedit.copy2(pos1, pos2, off, meta_backwards)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local src_manip, src_area = mh.init(pos1, pos2)
|
||||
local src_stride = {x=1, y=src_area.ystride, z=src_area.zstride}
|
||||
local src_stride = vector.new(1, src_area.ystride, src_area.zstride)
|
||||
local src_offset = vector.subtract(pos1, src_area.MinEdge)
|
||||
|
||||
local dpos1 = vector.add(pos1, off)
|
||||
@ -178,7 +178,7 @@ function worldedit.copy2(pos1, pos2, off, meta_backwards)
|
||||
local dim = vector.add(vector.subtract(pos2, pos1), 1)
|
||||
|
||||
local dst_manip, dst_area = mh.init(dpos1, dpos2)
|
||||
local dst_stride = {x=1, y=dst_area.ystride, z=dst_area.zstride}
|
||||
local dst_stride = vector.new(1, dst_area.ystride, dst_area.zstride)
|
||||
local dst_offset = vector.subtract(dpos1, dst_area.MinEdge)
|
||||
|
||||
local function do_copy(src_data, dst_data)
|
||||
@ -217,8 +217,6 @@ function worldedit.copy2(pos1, pos2, off, meta_backwards)
|
||||
dst_manip:set_param2_data(dst_data)
|
||||
|
||||
mh.finish(dst_manip)
|
||||
src_data = nil
|
||||
dst_data = nil
|
||||
|
||||
-- Copy metadata
|
||||
local get_meta = minetest.get_meta
|
||||
@ -226,7 +224,7 @@ function worldedit.copy2(pos1, pos2, off, meta_backwards)
|
||||
for z = dim.z-1, 0, -1 do
|
||||
for y = dim.y-1, 0, -1 do
|
||||
for x = dim.x-1, 0, -1 do
|
||||
local pos = {x=pos1.x+x, y=pos1.y+y, z=pos1.z+z}
|
||||
local pos = vector.new(pos1.x+x, pos1.y+y, pos1.z+z)
|
||||
local meta = get_meta(pos):to_table()
|
||||
pos = vector.add(pos, off)
|
||||
get_meta(pos):from_table(meta)
|
||||
@ -237,7 +235,7 @@ function worldedit.copy2(pos1, pos2, off, meta_backwards)
|
||||
for z = 0, dim.z-1 do
|
||||
for y = 0, dim.y-1 do
|
||||
for x = 0, dim.x-1 do
|
||||
local pos = {x=pos1.x+x, y=pos1.y+y, z=pos1.z+z}
|
||||
local pos = vector.new(pos1.x+x, pos1.y+y, pos1.z+z)
|
||||
local meta = get_meta(pos):to_table()
|
||||
pos = vector.add(pos, off)
|
||||
get_meta(pos):from_table(meta)
|
||||
@ -286,21 +284,21 @@ function worldedit.move(pos1, pos2, axis, amount)
|
||||
end
|
||||
|
||||
-- Copy stuff to new location
|
||||
local off = {x=0, y=0, z=0}
|
||||
local off = vector.new()
|
||||
off[axis] = amount
|
||||
worldedit.copy2(pos1, pos2, off, backwards)
|
||||
-- Nuke old area
|
||||
if not overlap then
|
||||
nuke_area({x=0, y=0, z=0}, dim)
|
||||
nuke_area(vector.new(), dim)
|
||||
else
|
||||
-- Source and destination region are overlapping, which means we can't
|
||||
-- blindly delete the [pos1, pos2] area
|
||||
local leftover = vector.new(dim) -- size of the leftover slice
|
||||
leftover[axis] = math.abs(amount)
|
||||
if amount > 0 then
|
||||
nuke_area({x=0, y=0, z=0}, leftover)
|
||||
nuke_area(vector.new(), leftover)
|
||||
else
|
||||
local top = {x=0, y=0, z=0} -- offset of the leftover slice from pos1
|
||||
local top = vector.new() -- offset of the leftover slice from pos1
|
||||
top[axis] = dim[axis] - math.abs(amount)
|
||||
nuke_area(top, leftover)
|
||||
end
|
||||
@ -358,7 +356,7 @@ function worldedit.stretch(pos1, pos2, stretch_x, stretch_y, stretch_z)
|
||||
for i = 1, stretch_x * stretch_y * stretch_z do
|
||||
nodes[i] = placeholder_node
|
||||
end
|
||||
local schematic = {size={x=stretch_x, y=stretch_y, z=stretch_z}, data=nodes}
|
||||
local schematic = {size=vector.new(stretch_x, stretch_y, stretch_z), data=nodes}
|
||||
|
||||
local size_x, size_y, size_z = stretch_x - 1, stretch_y - 1, stretch_z - 1
|
||||
|
||||
@ -369,8 +367,8 @@ function worldedit.stretch(pos1, pos2, stretch_x, stretch_y, stretch_z)
|
||||
}
|
||||
worldedit.keep_loaded(pos1, new_pos2)
|
||||
|
||||
local pos = {x=pos2.x, y=0, z=0}
|
||||
local big_pos = {x=0, y=0, z=0}
|
||||
local pos = vector.new(pos2.x, 0, 0)
|
||||
local big_pos = vector.new()
|
||||
while pos.x >= pos1.x do
|
||||
pos.y = pos2.y
|
||||
while pos.y >= pos1.y do
|
||||
@ -436,16 +434,16 @@ function worldedit.transpose(pos1, pos2, axis1, axis2)
|
||||
end
|
||||
|
||||
-- Calculate the new position 2 after transposition
|
||||
local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
local new_pos2 = vector.new(pos2)
|
||||
new_pos2[axis1] = pos1[axis1] + extent2
|
||||
new_pos2[axis2] = pos1[axis2] + extent1
|
||||
|
||||
local upper_bound = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
local upper_bound = vector.new(pos2)
|
||||
if upper_bound[axis1] < new_pos2[axis1] then upper_bound[axis1] = new_pos2[axis1] end
|
||||
if upper_bound[axis2] < new_pos2[axis2] then upper_bound[axis2] = new_pos2[axis2] end
|
||||
worldedit.keep_loaded(pos1, upper_bound)
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
local get_node, get_meta, set_node = minetest.get_node,
|
||||
minetest.get_meta, minetest.set_node
|
||||
while pos.x <= pos2.x do
|
||||
@ -485,7 +483,7 @@ function worldedit.flip(pos1, pos2, axis)
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
--- TODO: Flip the region slice by slice along the flip axis using schematic method.
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
local start = pos1[axis] + pos2[axis]
|
||||
pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)
|
||||
local get_node, get_meta, set_node = minetest.get_node,
|
||||
@ -584,7 +582,7 @@ function worldedit.orient(pos1, pos2, angle)
|
||||
|
||||
local count = 0
|
||||
local get_node, swap_node = minetest.get_node, minetest.swap_node
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
@ -650,13 +648,12 @@ function worldedit.clear_objects(pos1, pos2)
|
||||
end
|
||||
|
||||
-- Offset positions to include full nodes (positions are in the center of nodes)
|
||||
local pos1x, pos1y, pos1z = pos1.x - 0.5, pos1.y - 0.5, pos1.z - 0.5
|
||||
local pos2x, pos2y, pos2z = pos2.x + 0.5, pos2.y + 0.5, pos2.z + 0.5
|
||||
pos1 = vector.add(pos1, -0.5)
|
||||
pos2 = vector.add(pos2, 0.5)
|
||||
|
||||
local count = 0
|
||||
if minetest.get_objects_in_area then
|
||||
local objects = minetest.get_objects_in_area({x=pos1x, y=pos1y, z=pos1z},
|
||||
{x=pos2x, y=pos2y, z=pos2z})
|
||||
local objects = minetest.get_objects_in_area(pos1, pos2)
|
||||
|
||||
for _, obj in pairs(objects) do
|
||||
if should_delete(obj) then
|
||||
@ -670,21 +667,22 @@ function worldedit.clear_objects(pos1, pos2)
|
||||
-- Fallback implementation via get_objects_inside_radius
|
||||
-- Center of region
|
||||
local center = {
|
||||
x = pos1x + ((pos2x - pos1x) / 2),
|
||||
y = pos1y + ((pos2y - pos1y) / 2),
|
||||
z = pos1z + ((pos2z - pos1z) / 2)
|
||||
x = pos1.x + ((pos2.x - pos1.x) / 2),
|
||||
y = pos1.y + ((pos2.y - pos1.y) / 2),
|
||||
z = pos1.z + ((pos2.z - pos1.z) / 2)
|
||||
}
|
||||
-- Bounding sphere radius
|
||||
local radius = math.sqrt(
|
||||
(center.x - pos1x) ^ 2 +
|
||||
(center.y - pos1y) ^ 2 +
|
||||
(center.z - pos1z) ^ 2)
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(center, radius)) do
|
||||
(center.x - pos1.x) ^ 2 +
|
||||
(center.y - pos1.y) ^ 2 +
|
||||
(center.z - pos1.z) ^ 2)
|
||||
local objects = minetest.get_objects_inside_radius(center, radius)
|
||||
for _, obj in pairs(objects) do
|
||||
if should_delete(obj) then
|
||||
local pos = obj:get_pos()
|
||||
if pos.x >= pos1x and pos.x <= pos2x and
|
||||
pos.y >= pos1y and pos.y <= pos2y and
|
||||
pos.z >= pos1z and pos.z <= pos2z then
|
||||
if pos.x >= pos1.x and pos.x <= pos2.x and
|
||||
pos.y >= pos1.y and pos.y <= pos2.y and
|
||||
pos.z >= pos1.z and pos.z <= pos2.z then
|
||||
-- Inside region
|
||||
obj:remove()
|
||||
count = count + 1
|
||||
|
@ -20,7 +20,7 @@ function worldedit.cube(pos, width, height, length, node_name, hollow)
|
||||
|
||||
-- Add cube
|
||||
local node_id = minetest.get_content_id(node_name)
|
||||
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||
local stride = vector.new(1, area.ystride, area.zstride)
|
||||
local offset = vector.subtract(basepos, area.MinEdge)
|
||||
local count = 0
|
||||
|
||||
@ -149,7 +149,7 @@ function worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, holl
|
||||
end
|
||||
|
||||
-- Handle negative lengths
|
||||
local current_pos = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local current_pos = vector.new(pos)
|
||||
if length < 0 then
|
||||
length = -length
|
||||
current_pos[axis] = current_pos[axis] - length
|
||||
@ -162,7 +162,7 @@ function worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, holl
|
||||
|
||||
-- Add desired shape (anything inbetween cylinder & cone)
|
||||
local node_id = minetest.get_content_id(node_name)
|
||||
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||
local stride = vector.new(1, area.ystride, area.zstride)
|
||||
local offset = {
|
||||
x = current_pos.x - area.MinEdge.x,
|
||||
y = current_pos.y - area.MinEdge.y,
|
||||
@ -225,7 +225,7 @@ function worldedit.pyramid(pos, axis, height, node_name, hollow)
|
||||
|
||||
-- Add pyramid
|
||||
local node_id = minetest.get_content_id(node_name)
|
||||
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||
local stride = vector.new(1, area.ystride, area.zstride)
|
||||
local offset = {
|
||||
x = pos.x - area.MinEdge.x,
|
||||
y = pos.y - area.MinEdge.y,
|
||||
@ -242,8 +242,8 @@ function worldedit.pyramid(pos, axis, height, node_name, hollow)
|
||||
for index3 = -size, size do
|
||||
local i = new_index2 + (index3 + offset[other2]) * stride[other2]
|
||||
if (not hollow or size - math.abs(index2) < 2 or size - math.abs(index3) < 2) then
|
||||
data[i] = node_id
|
||||
count = count + 1
|
||||
data[i] = node_id
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -271,7 +271,7 @@ function worldedit.spiral(pos, length, height, spacer, node_name)
|
||||
|
||||
-- Set up variables
|
||||
local node_id = minetest.get_content_id(node_name)
|
||||
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||
local stride = vector.new(1, area.ystride, area.zstride)
|
||||
local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
|
||||
local i = offset_z * stride.z + offset_y * stride.y + offset_x + 1
|
||||
|
||||
|
@ -66,7 +66,7 @@ function worldedit.serialize(pos1, pos2)
|
||||
has_meta[hash_node_position(meta_positions[i])] = true
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
local count = 0
|
||||
local result = {}
|
||||
while pos.x <= pos2.x do
|
||||
@ -114,12 +114,15 @@ function worldedit.serialize(pos1, pos2)
|
||||
return LATEST_SERIALIZATION_HEADER .. result, count
|
||||
end
|
||||
|
||||
-- Contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile)
|
||||
-- by ChillCode, available under the MIT license.
|
||||
local function deserialize_workaround(content)
|
||||
local nodes
|
||||
local nodes, err
|
||||
if not minetest.global_exists("jit") then
|
||||
nodes = minetest.deserialize(content, true)
|
||||
nodes, err = minetest.deserialize(content, true)
|
||||
elseif not content:match("^%s*return%s*{") then
|
||||
-- The data doesn't look like we expect it to so we can't apply the workaround.
|
||||
-- hope for the best
|
||||
minetest.log("warning", "WorldEdit: deserializing data but can't apply LuaJIT workaround")
|
||||
nodes, err = minetest.deserialize(content, true)
|
||||
else
|
||||
-- XXX: This is a filthy hack that works surprisingly well
|
||||
-- in LuaJIT, `minetest.deserialize` will fail due to the register limit
|
||||
@ -129,18 +132,27 @@ local function deserialize_workaround(content)
|
||||
local escaped = content:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
|
||||
local startpos, startpos1 = 1, 1
|
||||
local endpos
|
||||
local entry
|
||||
while true do -- go through each individual node entry (except the last)
|
||||
startpos, endpos = escaped:find("},%s*{", startpos)
|
||||
startpos, endpos = escaped:find("}%s*,%s*{", startpos)
|
||||
if not startpos then
|
||||
break
|
||||
end
|
||||
local current = content:sub(startpos1, startpos)
|
||||
local entry = minetest.deserialize("return " .. current, true)
|
||||
entry, err = minetest.deserialize("return " .. current, true)
|
||||
if not entry then
|
||||
break
|
||||
end
|
||||
table.insert(nodes, entry)
|
||||
startpos, startpos1 = endpos, endpos
|
||||
end
|
||||
local entry = minetest.deserialize("return " .. content:sub(startpos1), true) -- process the last entry
|
||||
table.insert(nodes, entry)
|
||||
if not err then
|
||||
entry = minetest.deserialize("return " .. content:sub(startpos1), true) -- process the last entry
|
||||
table.insert(nodes, entry)
|
||||
end
|
||||
end
|
||||
if err then
|
||||
minetest.log("warning", "WorldEdit: deserialize: " .. err)
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
@ -148,7 +160,7 @@ end
|
||||
--- Loads the schematic in `value` into a node list in the latest format.
|
||||
-- @return A node list in the latest format, or nil on failure.
|
||||
local function load_schematic(value)
|
||||
local version, header, content = worldedit.read_header(value)
|
||||
local version, _, content = worldedit.read_header(value)
|
||||
local nodes = {}
|
||||
if version == 1 or version == 2 then -- Original flat table format
|
||||
local tables = minetest.deserialize(content, true)
|
||||
@ -223,9 +235,7 @@ function worldedit.allocate_with_nodes(origin_pos, nodes)
|
||||
if y > pos2y then pos2y = y end
|
||||
if z > pos2z then pos2z = z end
|
||||
end
|
||||
local pos1 = {x=pos1x, y=pos1y, z=pos1z}
|
||||
local pos2 = {x=pos2x, y=pos2y, z=pos2z}
|
||||
return pos1, pos2, #nodes
|
||||
return vector.new(pos1x, pos1y, pos1z), vector.new(pos2x, pos2y, pos2z), #nodes
|
||||
end
|
||||
|
||||
|
||||
@ -240,7 +250,6 @@ function worldedit.deserialize(origin_pos, value)
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
local origin_x, origin_y, origin_z = origin_pos.x, origin_pos.y, origin_pos.z
|
||||
local count = 0
|
||||
local add_node, get_meta = minetest.add_node, minetest.get_meta
|
||||
for i, entry in ipairs(nodes) do
|
||||
entry.x, entry.y, entry.z = origin_x + entry.x, origin_y + entry.y, origin_z + entry.z
|
||||
|
602
worldedit/test.lua
Normal file
@ -0,0 +1,602 @@
|
||||
---------------------
|
||||
-- Helpers
|
||||
---------------------
|
||||
|
||||
local vec = vector.new
|
||||
local vecw = function(axis, n, base)
|
||||
local ret = vec(base)
|
||||
ret[axis] = n
|
||||
return ret
|
||||
end
|
||||
local pos2str = minetest.pos_to_string
|
||||
local get_node = minetest.get_node
|
||||
local set_node = minetest.set_node
|
||||
|
||||
---------------------
|
||||
-- Nodes
|
||||
---------------------
|
||||
local air = "air"
|
||||
local testnode1
|
||||
local testnode2
|
||||
local testnode3
|
||||
-- Loads nodenames to use for tests
|
||||
local function init_nodes()
|
||||
testnode1 = minetest.registered_aliases["mapgen_stone"]
|
||||
testnode2 = minetest.registered_aliases["mapgen_dirt"]
|
||||
testnode3 = minetest.registered_aliases["mapgen_cobble"] or minetest.registered_aliases["mapgen_dirt_with_grass"]
|
||||
assert(testnode1 and testnode2 and testnode3)
|
||||
end
|
||||
-- Writes repeating pattern into given area
|
||||
local function place_pattern(pos1, pos2, pattern)
|
||||
local pos = vec()
|
||||
local node = {name=""}
|
||||
local i = 1
|
||||
for z = pos1.z, pos2.z do
|
||||
pos.z = z
|
||||
for y = pos1.y, pos2.y do
|
||||
pos.y = y
|
||||
for x = pos1.x, pos2.x do
|
||||
pos.x = x
|
||||
node.name = pattern[i]
|
||||
set_node(pos, node)
|
||||
i = i % #pattern + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------
|
||||
-- Area management
|
||||
---------------------
|
||||
assert(minetest.get_mapgen_setting("mg_name") == "singlenode")
|
||||
local area = {}
|
||||
do
|
||||
local areamin, areamax
|
||||
local off
|
||||
local c_air = minetest.get_content_id(air)
|
||||
local vbuffer = {}
|
||||
-- Assign a new area for use, will emerge and then call ready()
|
||||
area.assign = function(min, max, ready)
|
||||
areamin = min
|
||||
areamax = max
|
||||
minetest.emerge_area(min, max, function(bpos, action, remaining)
|
||||
assert(action ~= minetest.EMERGE_ERRORED)
|
||||
if remaining > 0 then return end
|
||||
minetest.after(0, function()
|
||||
area.clear()
|
||||
ready()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
-- Reset area contents and state
|
||||
area.clear = function()
|
||||
local vmanip = minetest.get_voxel_manip(areamin, areamax)
|
||||
local vpos1, vpos2 = vmanip:get_emerged_area()
|
||||
local vcount = (vpos2.x - vpos1.x + 1) * (vpos2.y - vpos1.y + 1) * (vpos2.z - vpos1.z + 1)
|
||||
if #vbuffer ~= vcount then
|
||||
vbuffer = {}
|
||||
for i = 1, vcount do
|
||||
vbuffer[i] = c_air
|
||||
end
|
||||
end
|
||||
vmanip:set_data(vbuffer)
|
||||
vmanip:write_to_map()
|
||||
off = vec(0, 0, 0)
|
||||
end
|
||||
-- Returns an usable area [pos1, pos2] that does not overlap previous ones
|
||||
area.get = function(sizex, sizey, sizez)
|
||||
local size
|
||||
if sizey == nil and sizez == nil then
|
||||
size = vector.new(sizex, sizex, sizex)
|
||||
else
|
||||
size = vector.new(sizex, sizey, sizez)
|
||||
end
|
||||
local pos1 = vector.add(areamin, off)
|
||||
local pos2 = vector.subtract(vector.add(pos1, size), 1)
|
||||
if pos2.x > areamax.x or pos2.y > areamax.y or pos2.z > areamax.z then
|
||||
error("Internal failure: out of space")
|
||||
end
|
||||
off = vector.add(off, size)
|
||||
return pos1, pos2
|
||||
end
|
||||
-- Returns an axis and count (= n) relative to the last-requested area that is unoccupied
|
||||
area.dir = function(n)
|
||||
local pos1 = vector.add(areamin, off)
|
||||
if pos1.x + n <= areamax.x then
|
||||
off.x = off.x + n
|
||||
return "x", n
|
||||
elseif pos1.x + n <= areamax.y then
|
||||
off.y = off.y + n
|
||||
return "y", n
|
||||
elseif pos1.z + n <= areamax.z then
|
||||
off.z = off.z + n
|
||||
return "z", n
|
||||
end
|
||||
error("Internal failure: out of space")
|
||||
end
|
||||
-- Returns [XYZ] margin (list of pos pairs) of n around last-requested area
|
||||
-- (may actually be larger but doesn't matter)
|
||||
area.margin = function(n)
|
||||
local pos1, pos2 = area.get(n)
|
||||
return {
|
||||
{ vec(areamin.x, areamin.y, pos1.z), pos2 }, -- X/Y
|
||||
{ vec(areamin.x, pos1.y, areamin.z), pos2 }, -- X/Z
|
||||
{ vec(pos1.x, areamin.y, areamin.z), pos2 }, -- Y/Z
|
||||
}
|
||||
end
|
||||
end
|
||||
-- Split an existing area into two non-overlapping [pos1, half1], [half2, pos2] parts; returns half1, half2
|
||||
area.split = function(pos1, pos2)
|
||||
local axis
|
||||
if pos2.x - pos1.x >= 1 then
|
||||
axis = "x"
|
||||
elseif pos2.y - pos1.y >= 1 then
|
||||
axis = "y"
|
||||
elseif pos2.z - pos1.z >= 1 then
|
||||
axis = "z"
|
||||
else
|
||||
error("Internal failure: area too small to split")
|
||||
end
|
||||
local hspan = math.floor((pos2[axis] - pos1[axis] + 1) / 2)
|
||||
local half1 = vecw(axis, pos1[axis] + hspan - 1, pos2)
|
||||
local half2 = vecw(axis, pos1[axis] + hspan, pos2)
|
||||
return half1, half2
|
||||
end
|
||||
|
||||
|
||||
---------------------
|
||||
-- Checks
|
||||
---------------------
|
||||
local check = {}
|
||||
-- Check that all nodes in [pos1, pos2] are the node(s) specified
|
||||
check.filled = function(pos1, pos2, nodes)
|
||||
if type(nodes) == "string" then
|
||||
nodes = { nodes }
|
||||
end
|
||||
local _, counts = minetest.find_nodes_in_area(pos1, pos2, nodes)
|
||||
local total = worldedit.volume(pos1, pos2)
|
||||
local sum = 0
|
||||
for _, n in pairs(counts) do
|
||||
sum = sum + n
|
||||
end
|
||||
if sum ~= total then
|
||||
error((total - sum) .. " " .. table.concat(nodes, ",") .. " nodes missing in " ..
|
||||
pos2str(pos1) .. " -> " .. pos2str(pos2))
|
||||
end
|
||||
end
|
||||
-- Check that none of the nodes in [pos1, pos2] are the node(s) specified
|
||||
check.not_filled = function(pos1, pos2, nodes)
|
||||
if type(nodes) == "string" then
|
||||
nodes = { nodes }
|
||||
end
|
||||
local _, counts = minetest.find_nodes_in_area(pos1, pos2, nodes)
|
||||
for nodename, n in pairs(counts) do
|
||||
if n ~= 0 then
|
||||
error(counts[nodename] .. " " .. nodename .. " nodes found in " ..
|
||||
pos2str(pos1) .. " -> " .. pos2str(pos2))
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Check that all of the areas are only made of node(s) specified
|
||||
check.filled2 = function(list, nodes)
|
||||
for _, pos in ipairs(list) do
|
||||
check.filled(pos[1], pos[2], nodes)
|
||||
end
|
||||
end
|
||||
-- Check that none of the areas contain the node(s) specified
|
||||
check.not_filled2 = function(list, nodes)
|
||||
for _, pos in ipairs(list) do
|
||||
check.not_filled(pos[1], pos[2], nodes)
|
||||
end
|
||||
end
|
||||
-- Checks presence of a repeating pattern in [pos1, po2] (cf. place_pattern)
|
||||
check.pattern = function(pos1, pos2, pattern)
|
||||
local pos = vec()
|
||||
local i = 1
|
||||
for z = pos1.z, pos2.z do
|
||||
pos.z = z
|
||||
for y = pos1.y, pos2.y do
|
||||
pos.y = y
|
||||
for x = pos1.x, pos2.x do
|
||||
pos.x = x
|
||||
local node = get_node(pos)
|
||||
if node.name ~= pattern[i] then
|
||||
error(pattern[i] .. " not found at " .. pos2str(pos) .. " (i=" .. i .. ")")
|
||||
end
|
||||
i = i % #pattern + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------
|
||||
-- The actual tests
|
||||
---------------------
|
||||
local tests = {}
|
||||
local function register_test(name, func, opts)
|
||||
assert(type(name) == "string")
|
||||
assert(func == nil or type(func) == "function")
|
||||
if not opts then
|
||||
opts = {}
|
||||
else
|
||||
opts = table.copy(opts)
|
||||
end
|
||||
opts.name = name
|
||||
opts.func = func
|
||||
table.insert(tests, opts)
|
||||
end
|
||||
-- How this works:
|
||||
-- register_test registers a test with a name and function
|
||||
-- The function should return if the test passes or otherwise cause a Lua error
|
||||
-- The basic structure is: get areas + do operations + check results
|
||||
-- Helpers:
|
||||
-- area.get must be used to retrieve areas that can be operated on (these will be cleared before each test)
|
||||
-- check.filled / check.not_filled can be used to check the result
|
||||
-- area.margin + check.filled2 is useful to make sure nodes weren't placed too far
|
||||
-- place_pattern + check.pattern is useful to test ops that operate on existing data
|
||||
|
||||
|
||||
register_test("Internal self-test")
|
||||
register_test("is area loaded?", function()
|
||||
local pos1, _ = area.get(1)
|
||||
assert(get_node(pos1).name == "air")
|
||||
end, {dry=true})
|
||||
|
||||
register_test("area.split", function()
|
||||
for i = 2, 6 do
|
||||
local pos1, pos2 = area.get(1, 1, i)
|
||||
local half1, half2 = area.split(pos1, pos2)
|
||||
assert(pos1.x == half1.x and pos1.y == half1.y)
|
||||
assert(half1.x == half2.x and half1.y == half2.y)
|
||||
assert(half1.z + 1 == half2.z)
|
||||
if i % 2 == 0 then
|
||||
assert((half1.z - pos1.z) == (pos2.z - half2.z)) -- divided equally
|
||||
end
|
||||
end
|
||||
end, {dry=true})
|
||||
|
||||
register_test("check.filled", function()
|
||||
local pos1, pos2 = area.get(1, 2, 1)
|
||||
set_node(pos1, {name=testnode1})
|
||||
set_node(pos2, {name=testnode2})
|
||||
check.filled(pos1, pos1, testnode1)
|
||||
check.filled(pos1, pos2, {testnode1, testnode2})
|
||||
check.not_filled(pos1, pos1, air)
|
||||
check.not_filled(pos1, pos2, {air, testnode3})
|
||||
end)
|
||||
|
||||
register_test("pattern", function()
|
||||
local pos1, pos2 = area.get(3, 2, 1)
|
||||
local pattern = {testnode1, testnode3}
|
||||
place_pattern(pos1, pos2, pattern)
|
||||
assert(get_node(pos1).name == testnode1)
|
||||
check.pattern(pos1, pos2, pattern)
|
||||
end)
|
||||
|
||||
|
||||
register_test("Generic node manipulations")
|
||||
register_test("worldedit.set", function()
|
||||
local pos1, pos2 = area.get(10)
|
||||
local m = area.margin(1)
|
||||
|
||||
worldedit.set(pos1, pos2, testnode1)
|
||||
|
||||
check.filled(pos1, pos2, testnode1)
|
||||
check.filled2(m, air)
|
||||
end)
|
||||
|
||||
register_test("worldedit.set mix", function()
|
||||
local pos1, pos2 = area.get(10)
|
||||
local m = area.margin(1)
|
||||
|
||||
worldedit.set(pos1, pos2, {testnode1, testnode2})
|
||||
|
||||
check.filled(pos1, pos2, {testnode1, testnode2})
|
||||
check.filled2(m, air)
|
||||
end)
|
||||
|
||||
register_test("worldedit.replace", function()
|
||||
local pos1, pos2 = area.get(10)
|
||||
local half1, half2 = area.split(pos1, pos2)
|
||||
|
||||
worldedit.set(pos1, half1, testnode1)
|
||||
worldedit.set(half2, pos2, testnode2)
|
||||
worldedit.replace(pos1, pos2, testnode1, testnode3)
|
||||
|
||||
check.not_filled(pos1, pos2, testnode1)
|
||||
check.filled(pos1, half1, testnode3)
|
||||
check.filled(half2, pos2, testnode2)
|
||||
end)
|
||||
|
||||
register_test("worldedit.replace inverse", function()
|
||||
local pos1, pos2 = area.get(10)
|
||||
local half1, half2 = area.split(pos1, pos2)
|
||||
|
||||
worldedit.set(pos1, half1, testnode1)
|
||||
worldedit.set(half2, pos2, testnode2)
|
||||
worldedit.replace(pos1, pos2, testnode1, testnode3, true)
|
||||
|
||||
check.filled(pos1, half1, testnode1)
|
||||
check.filled(half2, pos2, testnode3)
|
||||
end)
|
||||
|
||||
-- FIXME?: this one looks overcomplicated
|
||||
register_test("worldedit.copy", function()
|
||||
local pos1, pos2 = area.get(4)
|
||||
local axis, n = area.dir(2)
|
||||
local m = area.margin(1)
|
||||
local b = pos1[axis]
|
||||
|
||||
-- create one slice with testnode1, one with testnode2
|
||||
worldedit.set(pos1, vecw(axis, b + 1, pos2), testnode1)
|
||||
worldedit.set(vecw(axis, b + 2, pos1), pos2, testnode2)
|
||||
worldedit.copy(pos1, pos2, axis, n)
|
||||
|
||||
-- should have three slices now
|
||||
check.filled(pos1, vecw(axis, b + 1, pos2), testnode1)
|
||||
check.filled(vecw(axis, b + 2, pos1), pos2, testnode1)
|
||||
check.filled(vecw(axis, b + 4, pos1), vector.add(pos2, vecw(axis, n)), testnode2)
|
||||
check.filled2(m, "air")
|
||||
end)
|
||||
|
||||
register_test("worldedit.copy2", function()
|
||||
local pos1, pos2 = area.get(6)
|
||||
local m1 = area.margin(1)
|
||||
local pos1_, pos2_ = area.get(6)
|
||||
local m2 = area.margin(1)
|
||||
|
||||
local pattern = {testnode1, testnode2, testnode3, testnode1, testnode2}
|
||||
place_pattern(pos1, pos2, pattern)
|
||||
worldedit.copy2(pos1, pos2, vector.subtract(pos1_, pos1))
|
||||
|
||||
check.pattern(pos1, pos2, pattern)
|
||||
check.pattern(pos1_, pos2_, pattern)
|
||||
check.filled2(m1, "air")
|
||||
check.filled2(m2, "air")
|
||||
end)
|
||||
|
||||
register_test("worldedit.move (overlap)", function()
|
||||
local pos1, pos2 = area.get(7)
|
||||
local axis, n = area.dir(2)
|
||||
local m = area.margin(1)
|
||||
|
||||
local pattern = {testnode2, testnode1, testnode2, testnode3, testnode3}
|
||||
place_pattern(pos1, pos2, pattern)
|
||||
worldedit.move(pos1, pos2, axis, n)
|
||||
|
||||
check.filled(pos1, vecw(axis, pos1[axis] + n - 1, pos2), "air")
|
||||
check.pattern(vecw(axis, pos1[axis] + n, pos1), vecw(axis, pos2[axis] + n, pos2), pattern)
|
||||
check.filled2(m, "air")
|
||||
end)
|
||||
|
||||
register_test("worldedit.move", function()
|
||||
local pos1, pos2 = area.get(10)
|
||||
local axis, n = area.dir(10)
|
||||
local m = area.margin(1)
|
||||
|
||||
local pattern = {testnode1, testnode3, testnode3, testnode2}
|
||||
place_pattern(pos1, pos2, pattern)
|
||||
worldedit.move(pos1, pos2, axis, n)
|
||||
|
||||
check.filled(pos1, pos2, "air")
|
||||
check.pattern(vecw(axis, pos1[axis] + n, pos1), vecw(axis, pos2[axis] + n, pos2), pattern)
|
||||
check.filled2(m, "air")
|
||||
end)
|
||||
|
||||
-- TODO: the rest (also testing param2 + metadata)
|
||||
|
||||
register_test("Schematics")
|
||||
register_test("worldedit.read_header", function()
|
||||
local value = '5,foo,BAR,-1,234:the content'
|
||||
local version, header, content = worldedit.read_header(value)
|
||||
assert(version == 5)
|
||||
assert(#header == 4)
|
||||
assert(header[1] == "foo" and header[2] == "BAR")
|
||||
assert(header[3] == "-1" and header[4] == "234")
|
||||
assert(content == "the content")
|
||||
end)
|
||||
|
||||
register_test("worldedit.allocate", function()
|
||||
local value = '3:-1 0 0 dummy 0 0\n0 0 4 dummy 0 0\n0 1 0 dummy 0 0'
|
||||
local pos1, pos2, count = worldedit.allocate(vec(1, 1, 1), value)
|
||||
assert(vector.equals(pos1, vec(0, 1, 1)))
|
||||
assert(vector.equals(pos2, vec(1, 2, 5)))
|
||||
assert(count == 3)
|
||||
end)
|
||||
|
||||
do
|
||||
local function output_weird(numbers, body)
|
||||
local s = {"return {"}
|
||||
for _, parts in ipairs(numbers) do
|
||||
s[#s+1] = "{"
|
||||
for _, n in ipairs(parts) do
|
||||
s[#s+1] = string.format(" {%d},", n)
|
||||
end
|
||||
s[#s+1] = "},"
|
||||
end
|
||||
return table.concat(s, "\n") .. table.concat(body, "\n") .. "}"
|
||||
end
|
||||
local fmt1p = '{\n ["x"]=%d,\n ["y"]=%d,\n ["z"]=%d,\n},'
|
||||
local fmt1n = '{\n ["name"]="%s",\n},'
|
||||
local fmt4 = '{ ["x"] = %d, ["y"] = %d, ["z"] = %d, ["meta"] = { ["fields"] = { }, ["inventory"] = { } }, ["param2"] = 0, ["param1"] = 0, ["name"] = "%s" }'
|
||||
local fmt5 = '{ ["x"] = %d, ["y"] = %d, ["z"] = %d, ["name"] = "%s" }'
|
||||
local fmt51 = '{[r2]=0,x=%d,y=%d,z=%d,name=r%d}'
|
||||
local fmt52 = '{x=%d,y=%d,z=%d,name=_[%d]}'
|
||||
local test_data = {
|
||||
-- used by WorldEdit 0.2 (first public release)
|
||||
{
|
||||
name = "v1", ver = 1,
|
||||
gen = function(pat)
|
||||
local numbers = {
|
||||
{2, 3, 4, 5, 6},
|
||||
{7, 8}, {9, 10}, {11, 12},
|
||||
{13, 14}, {15, 16}
|
||||
}
|
||||
return output_weird(numbers, {
|
||||
fmt1p:format(0, 0, 0),
|
||||
fmt1n:format(pat[1]),
|
||||
fmt1p:format(0, 1, 0),
|
||||
fmt1n:format(pat[3]),
|
||||
fmt1p:format(1, 1, 0),
|
||||
fmt1n:format(pat[1]),
|
||||
fmt1p:format(1, 0, 1),
|
||||
fmt1n:format(pat[3]),
|
||||
fmt1p:format(0, 1, 1),
|
||||
fmt1n:format(pat[1]),
|
||||
})
|
||||
end
|
||||
},
|
||||
|
||||
-- v2: missing because I couldn't find any code in my archives that actually wrote this format
|
||||
|
||||
{
|
||||
name = "v3", ver = 3,
|
||||
gen = function(pat)
|
||||
assert(pat[2] == "air")
|
||||
return table.concat({
|
||||
"0 0 0 " .. pat[1] .. " 0 0",
|
||||
"0 1 0 " .. pat[3] .. " 0 0",
|
||||
"1 1 0 " .. pat[1] .. " 0 0",
|
||||
"1 0 1 " .. pat[3] .. " 0 0",
|
||||
"0 1 1 " .. pat[1] .. " 0 0",
|
||||
}, "\n")
|
||||
end
|
||||
},
|
||||
|
||||
{
|
||||
name = "v4", ver = 4,
|
||||
gen = function(pat)
|
||||
return table.concat({
|
||||
"return { " .. fmt4:format(0, 0, 0, pat[1]),
|
||||
fmt4:format(0, 1, 0, pat[3]),
|
||||
fmt4:format(1, 1, 0, pat[1]),
|
||||
fmt4:format(1, 0, 1, pat[3]),
|
||||
fmt4:format(0, 1, 1, pat[1]) .. " }",
|
||||
}, ", ")
|
||||
end
|
||||
},
|
||||
|
||||
-- like v4 but no meta and param (if empty)
|
||||
{
|
||||
name = "v5 (pre-5.6)", ver = 5,
|
||||
gen = function(pat)
|
||||
return table.concat({
|
||||
"5:return { " .. fmt5:format(0, 0, 0, pat[1]),
|
||||
fmt5:format(0, 1, 0, pat[3]),
|
||||
fmt5:format(1, 1, 0, pat[1]),
|
||||
fmt5:format(1, 0, 1, pat[3]),
|
||||
fmt5:format(0, 1, 1, pat[1]) .. " }",
|
||||
}, ", ")
|
||||
end
|
||||
},
|
||||
|
||||
-- reworked engine serialization in 5.6
|
||||
{
|
||||
name = "v5 (5.6)", ver = 5,
|
||||
gen = function(pat)
|
||||
return table.concat({
|
||||
'5:r1="' .. pat[1] .. '";r2="param1";r3="' .. pat[3] .. '";return {'
|
||||
.. fmt51:format(0, 0, 0, 1),
|
||||
fmt51:format(0, 1, 0, 3),
|
||||
fmt51:format(1, 1, 0, 1),
|
||||
fmt51:format(1, 0, 1, 3),
|
||||
fmt51:format(0, 1, 1, 1) .. "}",
|
||||
}, ",")
|
||||
end
|
||||
},
|
||||
|
||||
-- small changes on engine side again
|
||||
{
|
||||
name = "v5 (post-5.7)", ver = 5,
|
||||
gen = function(pat)
|
||||
return table.concat({
|
||||
'5:local _={};_[1]="' .. pat[1] .. '";_[3]="' .. pat[3] .. '";return {'
|
||||
.. fmt52:format(0, 0, 0, 1),
|
||||
fmt52:format(0, 1, 0, 3),
|
||||
fmt52:format(1, 1, 0, 1),
|
||||
fmt52:format(1, 0, 1, 3),
|
||||
fmt52:format(0, 1, 1, 1) .. "}",
|
||||
}, ",")
|
||||
end
|
||||
},
|
||||
}
|
||||
for _, e in ipairs(test_data) do
|
||||
register_test("worldedit.deserialize " .. e.name, function()
|
||||
local pos1, pos2 = area.get(2)
|
||||
local m = area.margin(1)
|
||||
|
||||
local pat = {testnode3, "air", testnode2}
|
||||
local value = e.gen(pat)
|
||||
assert(type(value) == "string")
|
||||
|
||||
local version = worldedit.read_header(value)
|
||||
assert(version == e.ver, "version: got " .. tostring(version) .. " expected " .. e.ver)
|
||||
local count = worldedit.deserialize(pos1, value)
|
||||
assert(count ~= nil and count > 0)
|
||||
|
||||
check.pattern(pos1, pos2, pat)
|
||||
check.filled2(m, "air")
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---------------------
|
||||
-- Main function
|
||||
---------------------
|
||||
worldedit.run_tests = function()
|
||||
do
|
||||
local v = minetest.get_version()
|
||||
print("Running " .. #tests .. " tests for WorldEdit " ..
|
||||
worldedit.version_string .. " on " .. v.project .. " " .. (v.hash or v.string))
|
||||
end
|
||||
|
||||
init_nodes()
|
||||
|
||||
-- emerge area from (0,0,0) ~ (56,56,56) and keep it loaded
|
||||
-- Note: making this area smaller speeds up tests
|
||||
local wanted = vec(56, 56, 56)
|
||||
for x = 0, math.floor(wanted.x/16) do
|
||||
for y = 0, math.floor(wanted.y/16) do
|
||||
for z = 0, math.floor(wanted.z/16) do
|
||||
assert(minetest.forceload_block(vector.new(x*16, y*16, z*16), true))
|
||||
end
|
||||
end
|
||||
end
|
||||
area.assign(vec(0, 0, 0), wanted, function()
|
||||
|
||||
local failed = 0
|
||||
for _, test in ipairs(tests) do
|
||||
if not test.func then
|
||||
local s = "---- " .. test.name .. " "
|
||||
print(s .. string.rep("-", 60 - #s))
|
||||
else
|
||||
if not test.dry then
|
||||
area.clear()
|
||||
end
|
||||
local ok, err = pcall(test.func)
|
||||
print(string.format("%-60s %s", test.name, ok and "pass" or "FAIL"))
|
||||
if not ok then
|
||||
print(" " .. err)
|
||||
failed = failed + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("Done, " .. failed .. " tests failed.")
|
||||
if failed == 0 then
|
||||
io.close(io.open(minetest.get_worldpath() .. "/tests_ok", "w"))
|
||||
end
|
||||
minetest.request_shutdown()
|
||||
end)
|
||||
end
|
||||
|
||||
-- for debug purposes
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
minetest.set_player_privs(player:get_player_name(),
|
||||
minetest.string_to_privs("fly,fast,noclip,basic_debug,debug,interact"))
|
||||
end)
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
minetest.chat_send_player(puncher:get_player_name(), pos2str(pos))
|
||||
end)
|
Before Width: | Height: | Size: 442 B |
@ -19,7 +19,7 @@ function worldedit.hide(pos1, pos2)
|
||||
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
local get_node, get_meta, swap_node = minetest.get_node,
|
||||
minetest.get_meta, minetest.swap_node
|
||||
while pos.x <= pos2.x do
|
||||
@ -79,7 +79,7 @@ function worldedit.highlight(pos1, pos2, node_name)
|
||||
|
||||
worldedit.keep_loaded(pos1, pos2)
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local pos = vector.new(pos1.x, 0, 0)
|
||||
local get_node, get_meta, swap_node = minetest.get_node,
|
||||
minetest.get_meta, minetest.swap_node
|
||||
local count = 0
|
||||
|
@ -27,7 +27,7 @@ local brush_on_use = function(itemstack, placer)
|
||||
end
|
||||
|
||||
local raybegin = vector.add(placer:get_pos(),
|
||||
{x=0, y=placer:get_properties().eye_height, z=0})
|
||||
vector.new(0, placer:get_properties().eye_height, 0))
|
||||
local rayend = vector.add(raybegin, vector.multiply(placer:get_look_dir(), BRUSH_MAX_DIST))
|
||||
local ray = minetest.raycast(raybegin, rayend, false, true)
|
||||
local pointed_thing = ray:next()
|
||||
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 301 B |
@ -1,6 +1,8 @@
|
||||
local S = minetest.get_translator("worldedit_commands")
|
||||
|
||||
worldedit.register_command("outset", {
|
||||
params = "[h/v] <amount>",
|
||||
description = "Outset the selected region.",
|
||||
description = S("Outset the selected region."),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
@ -11,7 +13,7 @@ worldedit.register_command("outset", {
|
||||
|
||||
local hv_test = dir:find("[^hv]+")
|
||||
if hv_test ~= nil then
|
||||
return false, "Invalid direction."
|
||||
return false, S("Invalid direction: @1", dir)
|
||||
end
|
||||
|
||||
return true, dir, tonumber(amount)
|
||||
@ -28,18 +30,18 @@ worldedit.register_command("outset", {
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', 1, amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', -1, amount))
|
||||
else
|
||||
return false, "Invalid number of arguments"
|
||||
return false, S("Invalid number of arguments")
|
||||
end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region outset by " .. amount .. " blocks"
|
||||
return true, S("Region outset by @1 nodes", amount)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
worldedit.register_command("inset", {
|
||||
params = "[h/v] <amount>",
|
||||
description = "Inset the selected region.",
|
||||
description = S("Inset the selected region."),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
@ -48,7 +50,7 @@ worldedit.register_command("inset", {
|
||||
return false
|
||||
end
|
||||
if dir:find("[^hv]") ~= nil then
|
||||
return false, "Invalid direction."
|
||||
return false, S("Invalid direction: @1", dir)
|
||||
end
|
||||
|
||||
return true, dir, tonumber(amount)
|
||||
@ -65,18 +67,18 @@ worldedit.register_command("inset", {
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', 1, -amount))
|
||||
assert(worldedit.cuboid_linear_expand(name, 'y', -1, -amount))
|
||||
else
|
||||
return false, "Invalid number of arguments"
|
||||
return false, S("Invalid number of arguments")
|
||||
end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region inset by " .. amount .. " blocks"
|
||||
return true, S("Region inset by @1 nodes", amount)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
worldedit.register_command("shift", {
|
||||
params = "x/y/z/?/up/down/left/right/front/back [+/-]<amount>",
|
||||
description = "Shifts the selection area without moving its contents",
|
||||
description = S("Shifts the selection area without moving its contents"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
@ -98,20 +100,20 @@ worldedit.register_command("shift", {
|
||||
end
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
|
||||
assert(worldedit.cuboid_shift(name, axis, amount * dir))
|
||||
worldedit.marker_update(name)
|
||||
|
||||
return true, "Region shifted by " .. amount .. " nodes"
|
||||
return true, S("Region shifted by @1 nodes", amount)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
worldedit.register_command("expand", {
|
||||
params = "[+/-]x/y/z/?/up/down/left/right/front/back <amount> [reverse amount]",
|
||||
description = "Expands the selection in the selected absolute or relative axis",
|
||||
description = S("Expands the selection in the selected absolute or relative axis"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
@ -135,7 +137,7 @@ worldedit.register_command("expand", {
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
else
|
||||
if direction == "?" then
|
||||
@ -153,14 +155,14 @@ worldedit.register_command("expand", {
|
||||
worldedit.cuboid_linear_expand(name, axis, dir, amount)
|
||||
worldedit.cuboid_linear_expand(name, axis, -dir, rev_amount)
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region expanded by " .. (amount + rev_amount) .. " nodes"
|
||||
return true, S("Region expanded by @1 nodes", amount + rev_amount)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
worldedit.register_command("contract", {
|
||||
params = "[+/-]x/y/z/?/up/down/left/right/front/back <amount> [reverse amount]",
|
||||
description = "Contracts the selection in the selected absolute or relative axis",
|
||||
description = S("Contracts the selection in the selected absolute or relative axis"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(param)
|
||||
@ -184,7 +186,7 @@ worldedit.register_command("contract", {
|
||||
axis, dir = worldedit.translate_direction(name, direction)
|
||||
|
||||
if axis == nil or dir == nil then
|
||||
return false, "Invalid if looking straight up or down"
|
||||
return false, S("Invalid if looking straight up or down")
|
||||
end
|
||||
else
|
||||
if direction == "?" then
|
||||
@ -202,13 +204,13 @@ worldedit.register_command("contract", {
|
||||
worldedit.cuboid_linear_expand(name, axis, dir, -amount)
|
||||
worldedit.cuboid_linear_expand(name, axis, -dir, -rev_amount)
|
||||
worldedit.marker_update(name)
|
||||
return true, "Region contracted by " .. (amount + rev_amount) .. " nodes"
|
||||
return true, S("Region contracted by @1 nodes", amount + rev_amount)
|
||||
end,
|
||||
})
|
||||
|
||||
worldedit.register_command("cubeapply", {
|
||||
params = "<size>/(<sizex> <sizey> <sizez>) <command> [parameters]",
|
||||
description = "Select a cube with side length <size> around position 1 and run <command> on region",
|
||||
description = S("Select a cube with side length <size> around position 1 and run <command> on region"),
|
||||
privs = {worldedit=true},
|
||||
require_pos = 1,
|
||||
parse = function(param)
|
||||
@ -230,7 +232,7 @@ worldedit.register_command("cubeapply", {
|
||||
end
|
||||
local cmddef = worldedit.registered_commands[cmd]
|
||||
if cmddef == nil or cmddef.require_pos ~= 2 then
|
||||
return false, "invalid usage: //" .. cmd .. " cannot be used with cubeapply"
|
||||
return false, S("invalid usage: //@1 cannot be used with cubeapply", cmd)
|
||||
end
|
||||
-- run parsing of target command
|
||||
local parsed = {cmddef.parse(args)}
|
||||
@ -247,8 +249,7 @@ worldedit.register_command("cubeapply", {
|
||||
local cmddef = assert(worldedit.registered_commands[cmd])
|
||||
local success, missing_privs = minetest.check_player_privs(name, cmddef.privs)
|
||||
if not success then
|
||||
worldedit.player_notify(name, "Missing privileges: " ..
|
||||
table.concat(missing_privs, ", "))
|
||||
worldedit.player_notify(name, S("Missing privileges: @1", table.concat(missing_privs, ", ")))
|
||||
return
|
||||
end
|
||||
|
||||
|
145
worldedit_commands/locale/template.txt
Normal file
@ -0,0 +1,145 @@
|
||||
# textdomain: worldedit_commands
|
||||
Outset the selected region.=
|
||||
Invalid direction: @1=
|
||||
Invalid number of arguments=
|
||||
Region outset by @1 nodes=
|
||||
Inset the selected region.=
|
||||
Region inset by @1 nodes=
|
||||
Shifts the selection area without moving its contents=
|
||||
Invalid if looking straight up or down=
|
||||
Region shifted by @1 nodes=
|
||||
Expands the selection in the selected absolute or relative axis=
|
||||
Region expanded by @1 nodes=
|
||||
Contracts the selection in the selected absolute or relative axis=
|
||||
Region contracted by @1 nodes=
|
||||
Select a cube with side length <size> around position 1 and run <command> on region=
|
||||
invalid usage: //@1 cannot be used with cubeapply=
|
||||
Missing privileges: @1=
|
||||
Can use WorldEdit commands=
|
||||
no region selected=
|
||||
no position 1 selected=
|
||||
invalid usage=
|
||||
Could not open file "@1"=
|
||||
Invalid file format!=
|
||||
Schematic was created with a newer version of WorldEdit.=
|
||||
Get information about the WorldEdit mod=
|
||||
WorldEdit @1 is available on this server. Type //help to get a list of commands, or get more information at @2=
|
||||
Get help for WorldEdit commands=
|
||||
You are not allowed to use any WorldEdit commands.=
|
||||
Available commands: @1@nUse '//help <cmd>' to get more information, or '//help all' to list everything.=
|
||||
Available commands:@n=
|
||||
Command not available: =
|
||||
Enable or disable node inspection=
|
||||
inspector: inspection enabled for @1, currently facing the @2 axis=
|
||||
inspector: inspection disabled=
|
||||
inspector: @1 at @2 (param1@=@3, param2@=@4, received light@=@5) punched facing the @6 axis=
|
||||
Reset the region so that it is empty=
|
||||
region reset=
|
||||
Show markers at the region positions=
|
||||
region marked=
|
||||
Hide markers if currently shown=
|
||||
region unmarked=
|
||||
Set WorldEdit region position @1 to the player's location=
|
||||
position @1 set to @2=
|
||||
Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region=
|
||||
unknown subcommand: @1=
|
||||
select positions by punching two nodes=
|
||||
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>)=
|
||||
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=
|
||||
Area deleted.=
|
||||
There was an error during deletion of the area.=
|
||||
Set the current WorldEdit region to <node>=
|
||||
invalid node name: @1=
|
||||
@1 nodes set=
|
||||
Set param2 of all nodes in the current WorldEdit region to <param2>=
|
||||
Param2 is out of range (must be between 0 and 255 inclusive!)=
|
||||
@1 nodes altered=
|
||||
Fill the current WorldEdit region with a random mix of <node1>, ...=
|
||||
invalid search node name: @1=
|
||||
invalid replace node name: @1=
|
||||
Replace all instances of <search node> with <replace node> in the current WorldEdit region=
|
||||
@1 nodes replaced=
|
||||
Replace all nodes other than <search node> with <replace node> in the current WorldEdit region=
|
||||
Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=
|
||||
@1 nodes added=
|
||||
Add a cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=
|
||||
Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add hollow cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=
|
||||
Add cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=
|
||||
Add hollow pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=
|
||||
Add pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=
|
||||
Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>=
|
||||
Copy the current WorldEdit region along the given axis by <amount> nodes=
|
||||
@1 nodes copied=
|
||||
Move the current WorldEdit region along the given axis by <amount> nodes=
|
||||
@1 nodes moved=
|
||||
Stack the current WorldEdit region along the given axis <count> times=
|
||||
@1 nodes stacked=
|
||||
Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>=
|
||||
invalid count: @1=
|
||||
invalid increments: @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=
|
||||
invalid scaling factors: @1=
|
||||
@1 nodes stretched=
|
||||
Transpose the current WorldEdit region along the given axes=
|
||||
invalid usage: axes must be different=
|
||||
@1 nodes transposed=
|
||||
Flip the current WorldEdit region along the given axis=
|
||||
@1 nodes flipped=
|
||||
Rotate the current WorldEdit region around the given axis by angle <angle> (90 degree increment)=
|
||||
invalid usage: angle must be multiple of 90=
|
||||
@1 nodes rotated=
|
||||
Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)=
|
||||
@1 nodes oriented=
|
||||
Fix the lighting in the current WorldEdit region=
|
||||
@1 nodes updated=
|
||||
Remove any fluid node within the current WorldEdit region=
|
||||
Remove any plant, tree or foliage-like nodes in the selected region=
|
||||
@1 nodes removed=
|
||||
Hide all nodes in the current WorldEdit region non-destructively=
|
||||
@1 nodes hidden=
|
||||
Suppress all <node> in the current WorldEdit region non-destructively=
|
||||
@1 nodes suppressed=
|
||||
Highlight <node> in the current WorldEdit region by hiding everything else non-destructively=
|
||||
@1 nodes highlighted=
|
||||
Restores nodes hidden with WorldEdit in the current WorldEdit region=
|
||||
@1 nodes restored=
|
||||
Warning: The schematic contains excessive free space and WILL be misaligned when allocated or loaded. To avoid this, shrink your area to cover exactly the nodes to be saved.=
|
||||
Save the current WorldEdit region to "(world folder)/schems/<file>.we"=
|
||||
Disallowed file name: @1=
|
||||
Could not save file to "@1"=
|
||||
@1 nodes saved=
|
||||
Set the region defined by nodes from "(world folder)/schems/<file>.we" as the current WorldEdit region=
|
||||
Schematic empty, nothing allocated=
|
||||
@1 nodes allocated=
|
||||
Load nodes from "(world folder)/schems/<file>[.we[m]]" with position 1 of the current WorldEdit region as the origin=
|
||||
Loading failed!=
|
||||
@1 nodes loaded=
|
||||
Executes <code> as a Lua chunk in the global namespace=
|
||||
Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region=
|
||||
Save the current WorldEdit region using the Minetest Schematic format to "(world folder)/schems/<filename>.mts"=
|
||||
Failed to create Minetest schematic=
|
||||
Saved Minetest schematic to @1=
|
||||
Load nodes from "(world folder)/schems/<file>.mts" with position 1 of the current WorldEdit region as the origin=
|
||||
failed to place Minetest schematic=
|
||||
placed Minetest schematic @1 at @2=
|
||||
Begins node probability entry for Minetest schematics, gets the nodes that have probabilities set, or ends node probability entry=
|
||||
select Minetest schematic probability values by punching nodes=
|
||||
finished Minetest schematic probability selection=
|
||||
currently set node probabilities:=
|
||||
invalid node probability given, not saved=
|
||||
Clears all objects within the WorldEdit region=
|
||||
@1 objects cleared=
|
||||
WARNING: this operation could affect up to @1 nodes; type //y to continue or //n to cancel=
|
||||
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=
|
156
worldedit_commands/locale/worldedit_commands.de.tr
Normal file
@ -0,0 +1,156 @@
|
||||
# textdomain: worldedit_commands
|
||||
##
|
||||
# Übersetzungshinweise:
|
||||
# node = Block
|
||||
# command = Befehl
|
||||
# region = Gebiet
|
||||
# position 1/2 = Position 1/2
|
||||
# schematic = Schematic
|
||||
# Der Anwender wird gesiezt.
|
||||
# Diese Datei auf Rechtschreibfehler prüfen (unter Linux):
|
||||
# sed -rne 's|^.*[^@]=(.*)$|\1|gp' worldedit_commands/locale/worldedit_commands.de.tr | sed -re 's/\b(WorldEdit|Schematic|Minetest)\b/Beispiel/g' | LANG=de_DE.UTF-8 hunspell -L
|
||||
##
|
||||
Outset the selected region.=Ausgewähltes Gebiet vergrößern.
|
||||
Invalid direction: @1=Ungültige Richtung: @1
|
||||
Invalid number of arguments=Ungültige Anzahl der Argumente
|
||||
Region outset by @1 nodes=Gebiet um @1 Blöcke vergrößert
|
||||
Inset the selected region.=Ausgewähltes Gebiet verkleinern.
|
||||
Region inset by @1 nodes=Gebiet um @1 Blöcke verkleinert
|
||||
Shifts the selection area without moving its contents=Verschiebt das ausgewählte Gebiet ohne dessen Inhalt
|
||||
Invalid if looking straight up or down=Nicht zulässig bei gerade Blickrichtung nach unten oder oben
|
||||
Region shifted by @1 nodes=Gebiet um @1 Blöcke verschoben
|
||||
Expands the selection in the selected absolute or relative axis=Erweitert das Gebiet in Richtung einer absoluten oder relativen Achse
|
||||
Region expanded by @1 nodes=Gebiet um @1 Blöcke erweitert
|
||||
Contracts the selection in the selected absolute or relative axis=Schrumpft das Gebiet in Richtung einer absoluten oder relativen Achse
|
||||
Region contracted by @1 nodes=Gebiet um @1 Blöcke geschrumpft
|
||||
Select a cube with side length <size> around position 1 and run <command> on region=Wähle einen Würfel mit Seitenlänge <size> um Position 1 und führe <command> auf diesem Gebiet aus
|
||||
invalid usage: //@1 cannot be used with cubeapply=Ungültige Verwendung: //@1 kann nicht mit cubeapply verwendet werden
|
||||
Missing privileges: @1=Fehlende Privilegien: @1
|
||||
Can use WorldEdit commands=Kann WorldEdit-Befehle benutzen
|
||||
no region selected=Kein Gebiet ausgewählt
|
||||
no position 1 selected=Keine Position 1 ausgewählt
|
||||
invalid usage=Ungültige Verwendung
|
||||
Could not open file "@1"=Konnte die Datei „@1“ nicht öffnen
|
||||
Invalid file format!=Ungültiges Dateiformat!
|
||||
Schematic was created with a newer version of WorldEdit.=Schematic wurde mit einer neueren Version von WorldEdit erstellt.
|
||||
Get information about the WorldEdit mod=Informationen über den WorldEdit-Mod erhalten.
|
||||
WorldEdit @1 is available on this server. Type //help to get a list of commands, or get more information at @2=WorldEdit @1 ist auf diesem Server verfügbar. Nutzen Sie //help, um eine Liste der Befehle zu erhalten, oder finden Sie weitere Informationen unter @2
|
||||
Get help for WorldEdit commands=Hilfe für WorldEdit-Befehle erhalten
|
||||
You are not allowed to use any WorldEdit commands.=Ihnen ist nicht erlaubt WorldEdit-Befehle zu nutzen.
|
||||
Available commands: @1@nUse '//help <cmd>' to get more information, or '//help all' to list everything.=Verfügbare Befehle: @1@n„//help <Befehl>“ benutzen, um mehr Informationen zu erhalten, oder „//help all“, um alles aufzulisten.
|
||||
Available commands:@n=Verfügbare Befehle:@n
|
||||
Command not available: =Befehl nicht verfügbar:
|
||||
Enable or disable node inspection=Inspizieren von Blöcken ein- oder ausschalten
|
||||
inspector: inspection enabled for @1, currently facing the @2 axis=Inspektur: für @1 aktiviert, aktuell der @2-Achse zugewandt
|
||||
inspector: inspection disabled=Inspektur: deaktiviert
|
||||
inspector: @1 at @2 (param1@=@3, param2@=@4, received light@=@5) punched facing the @6 axis=Inspektur: @1 bei @2 (param1@=@3, param2@=@4, einfallendes Licht@=@5), der @6-Achse zugewandt, gehauen
|
||||
Reset the region so that it is empty=Gebiet zurücksetzen, sodass es leer ist
|
||||
region reset=Gebiet zurückgesetzt
|
||||
Show markers at the region positions=Markierungen bei den Gebietsposition anzeigen
|
||||
region marked=Gebiet markiert
|
||||
Hide markers if currently shown=Markierungen verstecken falls derzeit sichtbar
|
||||
region unmarked=Gebiet nicht mehr markiert
|
||||
Set WorldEdit region position @1 to the player's location=Position @1 des WorldEdit-Gebiets auf die Position des Spieler setzen
|
||||
position @1 set to @2=Position @1 auf @2 gesetzt
|
||||
Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region=
|
||||
unknown subcommand: @1=Unbekannter Unterbefehl: @1
|
||||
select positions by punching two nodes=Wählen Sie die Position durch Hauen zweier Blöcke
|
||||
select position @1 by punching a node=Wählen Sie Position @1 durch Hauen eines Blocks
|
||||
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>)=Position des WorldEdit-Gebiets auf (<x>, <y>, <z>) setzen
|
||||
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 (16x16x16) entfernen, die das Gebiet enthalten.
|
||||
Area deleted.=Gebiet gelöscht.
|
||||
There was an error during deletion of the area.=Während des Löschens des Gebiets trat ein Fehler aus.
|
||||
Set the current WorldEdit region to <node>=Das aktuelle WorldEdit-Gebiet mit <node> füllen
|
||||
invalid node name: @1=Ungültiger Blockname: @1
|
||||
@1 nodes set=@1 Blöcke gesetzt
|
||||
Set param2 of all nodes in the current WorldEdit region to <param2>=Den param2 aller Blocke im aktuellen WorldEdit-Gebiet auf <param2> setzen
|
||||
Param2 is out of range (must be between 0 and 255 inclusive!)=Param2 muss zwischen 0 und 255 (inklusiv) sein
|
||||
@1 nodes altered=@1 Blöcke verändert
|
||||
Fill the current WorldEdit region with a random mix of <node1>, ...=Das aktuelle WorldEdit-Gebiet mit einer zufälligen Mischung aus <node1>, ... füllen
|
||||
invalid search node name: @1=Ungültiger Blockname für die Suche: @1
|
||||
invalid replace node name: @1=Ungültiger Blockname für das Ersetzen: @1
|
||||
Replace all instances of <search node> with <replace node> in the current WorldEdit region=Alle Vorkommen von <search node> im aktuellen WorldEdit-Gebiet mit <replace node> ersetzen
|
||||
@1 nodes replaced=@1 Blöcke ersetzt
|
||||
Replace all nodes other than <search node> with <replace node> in the current WorldEdit region=Alle Blöcke außer <search node> im aktuellen WorldEdit-Gebiet mit <replace node> ersetzen.
|
||||
Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=
|
||||
@1 nodes added=@1 Blöcke hinzugefügt
|
||||
Add a cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=
|
||||
Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=
|
||||
Add hollow cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=
|
||||
Add cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=
|
||||
Add hollow pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=
|
||||
Add pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=
|
||||
Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>=
|
||||
Copy the current WorldEdit region along the given axis by <amount> nodes=Das aktuelle WorldEdit-Gebiet entlang der gegebenen Achse um <amount> Blöcke kopieren
|
||||
@1 nodes copied=@1 Blöcke kopiert
|
||||
Move the current WorldEdit region along the given axis by <amount> nodes=Das aktuelle WorldEdit-Gebiet entlang der gegebenen Achse um <amount> Blöcke verschieben
|
||||
@1 nodes moved=@1 Blöcke verschoben
|
||||
Stack the current WorldEdit region along the given axis <count> times=Das aktuelle WorldEdit-Gebiet entlang der gegebenen Achse <count>-mal stapeln
|
||||
@1 nodes stacked=@1 Blöcke gestapelt
|
||||
Stack the current WorldEdit region <count> times by offset <x>, <y>, <z>=Das aktuelle WorldEdit-Gebiet <count>-mal um <x>, <y>, <z> versetzt stapeln
|
||||
invalid count: @1=Ungültige Anzahl: @1
|
||||
invalid increments: @1=Ungültige Schrittweite: @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=
|
||||
invalid scaling factors: @1=Ungültige Skalierungsfaktoren: @1
|
||||
@1 nodes stretched=@1 Blöcke gestreckt
|
||||
Transpose the current WorldEdit region along the given axes=
|
||||
invalid usage: axes must be different=Ungültige Verwendung: Achsen müssen verschieden sein
|
||||
@1 nodes transposed=
|
||||
Flip the current WorldEdit region along the given axis=
|
||||
@1 nodes flipped=
|
||||
Rotate the current WorldEdit region around the given axis by angle <angle> (90 degree increment)=
|
||||
invalid usage: angle must be multiple of 90=Ungültige Verwendung: Winkel muss ein Vielfaches von 90 sein
|
||||
@1 nodes rotated=@1 Blöcke gedreht
|
||||
Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)=
|
||||
@1 nodes oriented=
|
||||
Fix the lighting in the current WorldEdit region=Belichtung im aktuellen WorldEdit-Gebiet korrigieren
|
||||
@1 nodes updated=@1 Blöcke verändert
|
||||
Remove any fluid node within the current WorldEdit region=Alle flüssigen Blöcke im WorldEdit-Gebiet entfernen
|
||||
Remove any plant, tree or foliage-like nodes in the selected region=Alle Pflanzen, Baum oder Laub-ähnliche Blöcke im WorldEdit-Gebiet entfernen
|
||||
@1 nodes removed=@1 Blöcke entfernt
|
||||
Hide all nodes in the current WorldEdit region non-destructively=Alle Blöcke im WorldEdit-Gebiet zerstörungsfrei verstecken
|
||||
@1 nodes hidden=@1 Blöcke versteckt
|
||||
Suppress all <node> in the current WorldEdit region non-destructively=
|
||||
@1 nodes suppressed=
|
||||
Highlight <node> in the current WorldEdit region by hiding everything else non-destructively=Alle <node> Blöcke im WorldEdit-Gebiet hervorheben, indem alle anderen zerstörungsfrei versteckt werden
|
||||
@1 nodes highlighted=@1 Blöcke hervorgehoben
|
||||
Restores nodes hidden with WorldEdit in the current WorldEdit region=Versteckte Blöcke im WorldEdit-Gebiet wiederherstellen.
|
||||
@1 nodes restored=@1 Blöcke wiederhergestellt
|
||||
Warning: The schematic contains excessive free space and WILL be misaligned when allocated or loaded. To avoid this, shrink your area to cover exactly the nodes to be saved.=Warnung: Das Schematic hat überschüssigen freien Platz und WIRD nach dem Laden falsch ausgerichtet sein. Um dies zu vermeiden, verkleinern Sie das Gebiet sodass es die zu speichernden Blöcke exakt umfasst.
|
||||
Save the current WorldEdit region to "(world folder)/schems/<file>.we"=Das aktuelle WorldEdit-Gebiet in "(Weltordner)/schems/<file>.we" speichern
|
||||
Disallowed file name: @1=Nicht erlaubter Dateiname: @1
|
||||
Could not save file to "@1"=Konnte die Datei nicht unter "@1" speichern
|
||||
@1 nodes saved=@1 Blöcke gespeichert
|
||||
Set the region defined by nodes from "(world folder)/schems/<file>.we" as the current WorldEdit region=Das aktuelle WorldEdit-Gebiet anhand der Blöcke in "(Weltordner)/schems/<file>.we" setzen
|
||||
Schematic empty, nothing allocated=Schematic leer, nichts reserviert
|
||||
@1 nodes allocated=@1 Blöcke reserviert
|
||||
Load nodes from "(world folder)/schems/<file>[.we[m]]" with position 1 of the current WorldEdit region as the origin=Blöcke aus "(Weltordner)/schems/<file>[.we[m]]" mit Position 1 als Ausgangspunkt laden
|
||||
Loading failed!=Laden fehlgeschlagen!
|
||||
@1 nodes loaded=@1 Blöcke geladen
|
||||
Executes <code> as a Lua chunk in the global namespace=
|
||||
Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region=
|
||||
Save the current WorldEdit region using the Minetest Schematic format to "(world folder)/schems/<filename>.mts"=Das aktuelle WorldEdit-Gebiet als Minetest-Schematic in "(Weltordner)/schems/<filename>.mts" speichern
|
||||
Failed to create Minetest schematic=Konnte Minetest-Schematic nicht erstellen
|
||||
Saved Minetest schematic to @1=Minetest-Schematic in @1 gespeichert
|
||||
Load nodes from "(world folder)/schems/<file>.mts" with position 1 of the current WorldEdit region as the origin=Blöcke aus "(Weltordner)/schems/<file>.mts" mit Position 1 als Ausgangspunkt laden
|
||||
failed to place Minetest schematic=Konnte Minetest-Schematic nicht platzieren
|
||||
placed Minetest schematic @1 at @2=Minetest-Schematic @1 bei @2 platziert
|
||||
Begins node probability entry for Minetest schematics, gets the nodes that have probabilities set, or ends node probability entry=
|
||||
select Minetest schematic probability values by punching nodes=
|
||||
finished Minetest schematic probability selection=
|
||||
currently set node probabilities:=
|
||||
invalid node probability given, not saved=
|
||||
Clears all objects within the WorldEdit region=Löscht alle Objekte innerhalb des WorldEdit-Gebiets
|
||||
@1 objects cleared=@1 Objekte gelöscht
|
||||
WARNING: this operation could affect up to @1 nodes; type //y to continue or //n to cancel=WARNUNG: Dieser Vorgang könnte bis zu @1 Blöcke betreffen; //y zum Fortfahren oder //n zum Abbrechen
|
||||
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
|
155
worldedit_commands/locale/worldedit_commands.ru.tr
Normal file
@ -0,0 +1,155 @@
|
||||
# textdomain: worldedit_commands
|
||||
|
||||
### init.lua ###
|
||||
Can use WorldEdit commands=Возможность редактировать мир с помощью команд WorldEdit
|
||||
|
||||
no region selected=не выделен регион
|
||||
no position 1 selected=не установлена позиция региона 1
|
||||
invalid usage=не верное использование команды
|
||||
Could not open file "@1"=Не удаётся открыть файл "@1"
|
||||
Invalid file format!=Не верный формат файла!
|
||||
Schematic was created with a newer version of WorldEdit.=Схема была создана с использованием более новой версии WorldEdit.
|
||||
|
||||
Get information about the WorldEdit mod=Вывести информацию о WorldEdit
|
||||
WorldEdit @1 is available on this server. Type //help to get a list of commands, or get more information at @2=WorldEdit @1 доступен на этом сервере. Наберите команду //help чтобы увидеть список команд, больше информации по ссылке @2
|
||||
Get help for WorldEdit commands=Вывести информацию об использовании команд WorldEdit
|
||||
You are not allowed to use any WorldEdit commands.=У вас нет привилегий, чтобы использовать команды WorldEdit.
|
||||
Available commands: @1@nUse '//help <cmd>' to get more information, or '//help all' to list everything.=Доступные команды: @1@nИспользуйте '//help <cmd>' для получения информации по команде или '//help all' для вывода подсказок по всем командам.
|
||||
Available commands:@n=Доступные команды:@n
|
||||
Command not available: =Команда не найдена:
|
||||
Enable or disable node inspection=Включить/отключить инспекцию блоков
|
||||
inspector: inspection enabled for @1, currently facing the @2 axis=inspector: инспекция включена для @1, текущий взор в направлении оси @2
|
||||
inspector: inspection disabled=inspector: инспекция отключена
|
||||
inspector: @1 at @2 (param1@=@3, param2@=@4, received light@=@5) punched facing the @6 axis=inspector: @1 в @2 (param1@=@3, param2@=@4, received light@=@5) ударен по поверхности @6
|
||||
Reset the region so that it is empty=Сбросить выделение области
|
||||
region reset=регион сброшен
|
||||
Show markers at the region positions=Отобразить маркеры выделенной области
|
||||
region marked=маркеры отображены
|
||||
Hide markers if currently shown=Скрыть маркеры выделенной области
|
||||
region unmarked=маркеры скрыты
|
||||
Set WorldEdit region position @1 to the player's location=Установить маркер @1 для WorldEdit-региона в месте нахождения игрока
|
||||
Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region=Выделить WorldEdit-регион или установить маркеры для WorldEdit-региона, либо отобразить уже выбранную область
|
||||
unknown subcommand: @1=неизвестная подкоманда: @1
|
||||
select positions by punching two nodes=выберите позиции, ударив по блокам
|
||||
select position @1 by punching a node=выберите позицию @1, ударив по блоку
|
||||
position @1: @2=позиция @1: @2
|
||||
position @1 not set=позиция @1 не установлена
|
||||
Set a WorldEdit region position to the position at (<x>, <y>, <z>)=Установить маркер для WorldEdit в позиции (<x>, <y>, <z>)
|
||||
position @1 set to @2=позиция @1 установлена в @2
|
||||
Display the volume of the current WorldEdit region=Вывести информацию об объёме текущей выделенной области WorldEdit (кол-во нод, размеры)
|
||||
current region has a volume of @1 nodes (@2*@3*@4)=текущий регион имеет объем @1 нод (@2*@3*@4)
|
||||
Remove all MapBlocks (16x16x16) containing the selected area from the map=Удалить MapBlocks (16x16x16), содержащие выбранную область
|
||||
Area deleted.=Область удалена.
|
||||
There was an error during deletion of the area.=Что-то пошло не так при удалении области.
|
||||
Set the current WorldEdit region to <node>=Заполнить выбранный WorldEdit-регион указанным типом блоков
|
||||
invalid node name: @1=неверное название блока: @1
|
||||
@1 nodes set=@1 блок(а/ов) установленно
|
||||
Set param2 of all nodes in the current WorldEdit region to <param2>=Проставить param2 для всех блоков в текущем WorldEdit-регионе
|
||||
Param2 is out of range (must be between 0 and 255 inclusive!)=Значение param2 должно быть от 0 до 255 (включительно!)
|
||||
@1 nodes altered=изменено @1 блок(а/ов)
|
||||
Fill the current WorldEdit region with a random mix of <node1>, ...=Заполнить выбранный WorldEdit-регион смесью указанных типов блоков
|
||||
invalid search node name: @1=неверное название блока-поиска: @1
|
||||
invalid replace node name: @1=неверное название блока-замены: @1
|
||||
Replace all instances of <search node> with <replace node> in the current WorldEdit region=Заменить все блоки <search node> на <replace node> в выбранной WorldEdit-области
|
||||
@1 nodes replaced=заменено @1 нод(а/ы)
|
||||
Replace all nodes other than <search node> with <replace node> in the current WorldEdit region=Заменить все блоки, кроме <search node>, на <replace node> в выбранной WorldEdit-области
|
||||
Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=Установить полый куб с центром нижней грани в позиции 1 и указанными размерами, состоящий из блоков <node>.
|
||||
@1 nodes added=добавлен(о) @1 блок(а/ов)
|
||||
Add a cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.=Установить куб с центром нижней грани в позиции 1 и указанными размерами, состоящий из блоков <node>.
|
||||
Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=Установить полую сферу с центром в WorldEdit-позиции 1 радиусом <radius>, состоящую из блоков <node>
|
||||
Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>=Установить сферу с центром в WorldEdit-позиции 1 радиусом <radius>, состоящую из блоков <node>
|
||||
Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=Установить полый купол с центром в WorldEdit-позиции 1 радиусом <radius>, состоящий из блоков <node>
|
||||
Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>=Установить купол с центром в WorldEdit-позиции 1 радиусом <radius>, состоящий из блоков <node>
|
||||
Add hollow cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=Установить полый цилиндр вдоль указанной оси, с центром в позиции 1, высотой/длинной <length>, с радиусом основания <radius> (и радиусом вершины [radius 2]), состоящий из блоков <node>
|
||||
Add cylinder at WorldEdit position 1 along the given axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>=Установить цилиндр вдоль указанной оси, с центром в позиции 1, высотой/длинной <length>, с радиусом основания <radius> (и радиусом вершины [radius 2]), состоящий из блоков <node>
|
||||
Add hollow pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=Установить полую пирамиду вдоль указанной оси, с центром в WorldEdit-позиции 1 высотой <height>, состоящую из блоков <node>
|
||||
Add pyramid centered at WorldEdit position 1 along the given axis with height <height>, composed of <node>=Установить пирамиду вдоль указанной оси, с центром в WorldEdit-позиции 1 высотой <height>, состоящую из блоков <node>
|
||||
Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>=Установить спираль с центром в WorldEdit-позиции 1 шириной <length>, высотой <height> и с расстоянием между витками <space>, состоящую из блоков <node>
|
||||
Copy the current WorldEdit region along the given axis by <amount> nodes=Копировать текущий WorldEdit-регион со смещением вдоль указанной оси (x/y/z) на <amount> блоков
|
||||
@1 nodes copied=скопировано @1 нод(а/ы)
|
||||
Move the current WorldEdit region along the given axis by <amount> nodes=Переместить текущий WorldEdit-регион вдоль указанной оси (x/y/z) на <amount> блоков
|
||||
@1 nodes moved=перемещено @1 нод(а/ы)
|
||||
Stack the current WorldEdit region along the given axis <count> times=Размножить текущий WorldEdit-регион вдоль указанной оси <count> раз
|
||||
@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=неверные приращения(шаг)
|
||||
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 нод(а/ы)
|
||||
Transpose the current WorldEdit region along the given axes=Транспонировать текущий WorldEdit-регион по заданным осям.
|
||||
invalid usage: axes must be different=недопустимое использование: оси должны быть разными
|
||||
@1 nodes transposed=транспонировано @1 нод(а/ы)
|
||||
Flip the current WorldEdit region along the given axis=Перевернуть/Отразить текущий WorldEdit-регион вдоль указанной оси
|
||||
@1 nodes flipped=отражено @1 нод(а/ы)
|
||||
Rotate the current WorldEdit region around the given axis by angle <angle> (90 degree increment)=Повернуть текущий WorldEdit-регион вокруг оси <axis> на угол <angle> (шаг - 90 градусов)
|
||||
invalid usage: angle must be multiple of 90=недопустимое использование: угол должен быть кратен 90
|
||||
@1 nodes rotated=повёрнуто @1 нод(а/ы)
|
||||
Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)=Повернуть блоки в текущем WorldEdit-регионе вокруг оси Y на угол <angle> (шаг - 90 градусов)
|
||||
@1 nodes oriented=повёрнуто @1 нод(а/ы)
|
||||
Fix the lighting in the current WorldEdit region=Исправить освещение в текущем WorldEdit-регионе
|
||||
@1 nodes updated=обновлено @1 нод(а/ы)
|
||||
Remove any fluid node within the current WorldEdit region=Удалить любые жидкости в текущем WorldEdit-регионе
|
||||
Remove any plant, tree or foliage-like nodes in the selected region=Удалить любые растения, деревья или листье-подобные ноды в текущем WorldEdit-регионе
|
||||
@1 nodes removed=удалено @1 нод(а/ы)
|
||||
Hide all nodes in the current WorldEdit region non-destructively=Скрыть узлы текущего WorldEdit-региона, не удаляя их
|
||||
@1 nodes hidden=скрыто @1 нод(а/ы)
|
||||
Suppress all <node> in the current WorldEdit region non-destructively=Скрыть все блоки <node> в текущем WorldEdit-регионе, не удаляя их
|
||||
@1 nodes suppressed=скрыто @1 нод(а/ы)
|
||||
Highlight <node> in the current WorldEdit region by hiding everything else non-destructively=Скрыть все блоки, кроме <node>, в текущем WorldEdit-регионе, не удаляя их
|
||||
@1 nodes highlighted="подсвечено" @1 нод(а/ы)
|
||||
Restores nodes hidden with WorldEdit in the current WorldEdit region=Восстановить скрытые WorldEdit'ом узлы в текущем WorldEdit-регионе
|
||||
@1 nodes restored=восстановлено @1 нод(а/ы)
|
||||
Warning: The schematic contains excessive free space and WILL be misaligned when allocated or loaded. To avoid this, shrink your area to cover exactly the nodes to be saved.=Предупреждение: Схема содержит слишком много свободного места и будет смещена при размещении или загрузке. Чтобы избежать этого, уменьшите область так, чтобы она охватывала именно те узлы, которые необходимо сохранить.
|
||||
Save the current WorldEdit region to "(world folder)/schems/<file>.we"=Сохранить текущий WorldEdit-регион в файл "(world folder)/schems/<file>.we"
|
||||
Disallowed file name: @1=Недопустимое имя файла: @1
|
||||
Could not save file to "@1"=Не удалось сохранить файл в "@1"
|
||||
@1 nodes saved=сохранено @1 нод(а/ы)
|
||||
Set the region defined by nodes from "(world folder)/schems/<file>.we" as the current WorldEdit region=Выделить область, определённую узлами из "(world folder)/schems/<file>.we", как текущий WorldEdit-регион
|
||||
Schematic empty, nothing allocated=Схема пуста, ничего не выделено
|
||||
@1 nodes allocated=выделено @1 нод(а/ы)
|
||||
Load nodes from "(world folder)/schems/<file>[.we[m]]" with position 1 of the current WorldEdit region as the origin=Загрузить регион из "(world folder)/schems/<file>[.we[m]]" с WorldEdit-позицией 1 в качестве точки отсчёта
|
||||
Loading failed!=Не удалось загрузить!
|
||||
@1 nodes loaded=загружено @1 нод(а/ы)
|
||||
Executes <code> as a Lua chunk in the global namespace=Выполнить <code> как Lua-код в глобальном пространстве имён
|
||||
Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region=Выполнить <code> как Lua-код в глобальном пространстве имён, с доступом к переменным позиций для каждого блока в текущем WordEdit-регионе
|
||||
Save the current WorldEdit region using the Minetest Schematic format to "(world folder)/schems/<filename>.mts"=Сохранить текущий WorldEdit-регион с использованием сжатия в формат Minetest Schematic в файл "(world folder)/schems/<filename>.mts"
|
||||
Failed to create Minetest schematic=Не удалось создать Minetest-схему
|
||||
Saved Minetest schematic to @1=Minetest-схема сохранена в @1
|
||||
Load nodes from "(world folder)/schems/<file>.mts" with position 1 of the current WorldEdit region as the origin=Загрузить блоки из "(world folder)/schems/<file>.mts" с WorldEdit-позицией 1 в качестве точки отсчёта
|
||||
failed to place Minetest schematic=не удалось загрузить Minetest-схему
|
||||
placed Minetest schematic @1 at @2=Minetest-схема @1 загружена в @2
|
||||
Begins node probability entry for Minetest schematics, gets the nodes that have probabilities set, or ends node probability entry=Начать запись вероятностей для Minetest Schematic, ударяя по блокам, закончить запись вероятностей или вывести уже записанные вероятности
|
||||
select Minetest schematic probability values by punching nodes=выберите значения вероятностей для Minetest-схемы, ударя по нодам
|
||||
finished Minetest schematic probability selection=выбор вероятностей для Minetest-схемы завершен
|
||||
currently set node probabilities:=заданные вероятности нод на данный момент:
|
||||
invalid node probability given, not saved=недопустимая вероятность ноды, не сохранена
|
||||
Clears all objects within the WorldEdit region=Очистить все объекты в текущем WorldEdit-регионе
|
||||
@1 objects cleared=очищено @1 объектов
|
||||
|
||||
### safe.lua ###
|
||||
WARNING: this operation could affect up to @1 nodes; type //y to continue or //n to cancel=ПРЕДУПРЕЖДЕНИЕ: эта операция может затронуть до @1 нод; введите //y для продолжения или //n для отмены
|
||||
Confirm a pending operation=Подтвердить отложенную операцию
|
||||
no operation pending=нет ожидающей операции
|
||||
Abort a pending operation=Отклонить отложенную операцию
|
||||
|
||||
### cuboid.lua ###
|
||||
Outset the selected region.=Расширить выделение региона.
|
||||
Invalid direction: @1=Недопустимое направление: @1
|
||||
Invalid number of arguments=Недопустимое количество аргументов
|
||||
Region outset by @1 nodes=Регион расширен на @1 нод(у/ы)
|
||||
Inset the selected region.=Сузить выделение региона.
|
||||
Region inset by @1 nodes=Регион сужен на @1 нод(у/ы)
|
||||
Shifts the selection area without moving its contents=Сдвинуть выделение региона без перемещения его содержимого
|
||||
Invalid if looking straight up or down=Недопустимо, если смотреть прямо вверх или вниз
|
||||
Region shifted by @1 nodes=Регион сдвинут на @1 нод(у/ы)
|
||||
Expands the selection in the selected absolute or relative axis=Увеличить выделение региона по выбранной абсолютной или относительной оси
|
||||
Region expanded by @1 nodes=Регион увеличен на @1 нод(у/ы)
|
||||
Contracts the selection in the selected absolute or relative axis=Уменьшить выделение региона по выбранной абсолютной или относительной оси
|
||||
Region contracted by @1 nodes=Регион уменьшен на @1 нод(у/ы)
|
||||
Select a cube with side length <size> around position 1 and run <command> on region=Выделить куб с длиной стороны <size> вокруг позиции 1 и запустите <команду> в области
|
||||
invalid usage: //@1 cannot be used with cubeapply=недопустимое использование: //@1 не может быть применено в 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-ю
|
@ -6,7 +6,7 @@ local init_sentinel = "new" .. tostring(math.random(99999))
|
||||
|
||||
--marks worldedit region position 1
|
||||
worldedit.mark_pos1 = function(name, region_too)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local pos1 = worldedit.pos1[name]
|
||||
|
||||
if worldedit.marker1[name] ~= nil then --marker already exists
|
||||
worldedit.marker1[name]:remove() --remove marker
|
||||
@ -30,7 +30,7 @@ end
|
||||
|
||||
--marks worldedit region position 2
|
||||
worldedit.mark_pos2 = function(name, region_too)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
local pos2 = worldedit.pos2[name]
|
||||
|
||||
if worldedit.marker2[name] ~= nil then --marker already exists
|
||||
worldedit.marker2[name]:remove() --remove marker
|
||||
|
@ -1,3 +1,5 @@
|
||||
local S = minetest.get_translator("worldedit_commands")
|
||||
|
||||
local safe_region_callback = {}
|
||||
|
||||
--`count` is the number of nodes that would possibly be modified
|
||||
@ -9,7 +11,7 @@ local function safe_region(name, count, callback)
|
||||
|
||||
--save callback to call later
|
||||
safe_region_callback[name] = callback
|
||||
worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel")
|
||||
worldedit.player_notify(name, S("WARNING: this operation could affect up to @1 nodes; type //y to continue or //n to cancel", count))
|
||||
end
|
||||
|
||||
local function reset_pending(name)
|
||||
@ -18,11 +20,11 @@ end
|
||||
|
||||
minetest.register_chatcommand("/y", {
|
||||
params = "",
|
||||
description = "Confirm a pending operation",
|
||||
description = S("Confirm a pending operation"),
|
||||
func = function(name)
|
||||
local callback = safe_region_callback[name]
|
||||
if not callback then
|
||||
worldedit.player_notify(name, "no operation pending")
|
||||
worldedit.player_notify(name, S("no operation pending"))
|
||||
return
|
||||
end
|
||||
|
||||
@ -33,10 +35,10 @@ minetest.register_chatcommand("/y", {
|
||||
|
||||
minetest.register_chatcommand("/n", {
|
||||
params = "",
|
||||
description = "Abort a pending operation",
|
||||
description = S("Abort a pending operation"),
|
||||
func = function(name)
|
||||
if not safe_region_callback[name] then
|
||||
worldedit.player_notify(name, "no operation pending")
|
||||
worldedit.player_notify(name, S("no operation pending"))
|
||||
return
|
||||
end
|
||||
|
||||
|
Before Width: | Height: | Size: 147 B After Width: | Height: | Size: 79 B |
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 100 B |
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 112 B |
BIN
worldedit_commands/textures/worldedit_wand.png
Normal file
After Width: | Height: | Size: 303 B |
@ -1,3 +1,5 @@
|
||||
local S = minetest.get_translator("worldedit_commands")
|
||||
|
||||
local function above_or_under(placer, pointed_thing)
|
||||
if placer:get_player_control().sneak then
|
||||
return pointed_thing.above
|
||||
@ -9,7 +11,7 @@ end
|
||||
local punched_air_time = {}
|
||||
|
||||
minetest.register_tool(":worldedit:wand", {
|
||||
description = "WorldEdit Wand tool\nLeft-click to set 1st position, right-click to set 2nd",
|
||||
description = S("WorldEdit Wand tool\nLeft-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
|
||||
|
@ -140,7 +140,7 @@ local function execute_worldedit_command(command_name, player_name, params)
|
||||
assert(chatcmd, "unknown command: " .. command_name)
|
||||
local _, msg = chatcmd.func(player_name, params)
|
||||
if msg then
|
||||
worldedit.player_notify(player_name, msg)
|
||||
worldedit.player_notify(player_name, msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -4,10 +4,10 @@ worldedit = worldedit or {}
|
||||
Example:
|
||||
|
||||
worldedit.register_gui_function("worldedit_gui_hollow_cylinder", {
|
||||
name = "Make Hollow Cylinder",
|
||||
privs = {worldedit=true},
|
||||
get_formspec = function(name) return "some formspec here" end,
|
||||
on_select = function(name) print(name .. " clicked the button!") end,
|
||||
name = "Make Hollow Cylinder",
|
||||
privs = {worldedit=true},
|
||||
get_formspec = function(name) return "some formspec here" end,
|
||||
on_select = function(name) print(name .. " clicked the button!") end,
|
||||
})
|
||||
|
||||
Use `nil` for the `options` parameter to unregister the function associated with the given identifier.
|
||||
@ -35,14 +35,14 @@ end
|
||||
Example:
|
||||
|
||||
worldedit.register_gui_handler("worldedit_gui_hollow_cylinder", function(name, fields)
|
||||
print(minetest.serialize(fields))
|
||||
print(minetest.serialize(fields))
|
||||
end)
|
||||
]]
|
||||
|
||||
worldedit.register_gui_handler = function(identifier, handler)
|
||||
local enabled = true
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if not enabled then return false end
|
||||
if not enabled or formname ~= "" or fields.worldedit_gui then return false end
|
||||
enabled = false
|
||||
minetest.after(0.2, function() enabled = true end)
|
||||
local name = player:get_player_name()
|
||||
@ -216,7 +216,7 @@ elseif minetest.global_exists("sfinv") then -- sfinv installed
|
||||
end
|
||||
end
|
||||
else
|
||||
error(
|
||||
return minetest.log("error",
|
||||
"worldedit_gui requires a supported gui management mod to be installed.\n"..
|
||||
"To use the it you need to either:\n"..
|
||||
"* use minetest_game or another sfinv-compatible subgame\n"..
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 382 B |