117 Commits

Author SHA1 Message Date
40b49ee9bc Make placeholders not pointable 2019-07-17 01:22:12 +02:00
4f2c7b18cc Fix //allocate with 0 nodes 2019-07-17 01:20:40 +02:00
b2e086f9ec Fix //load with 0 nodes (#177) 2019-06-15 16:46:12 +02:00
d1cbd420bb serialize: Fix detecting empty metadata (#176) 2019-04-24 22:51:18 +02:00
0aeee79af6 Implement full facedir and color* in //orient
Thanks to entuland for the Rhotator facedir to matrix and matrix to facedir code, which helped creating the tables.
2019-04-05 00:12:02 +02:00
f242f2f722 Change description for //about, fix #170 2018-12-08 21:52:36 +01:00
f8e57559ec replace deprecated function call 2018-11-25 13:46:27 +01:00
b2b2b9364d Warn about invalid //stretch usage 2018-11-15 20:49:19 +01:00
b37605943b //mix: Add node weighting support 2018-10-29 00:36:33 +01:00
f7256633c0 Wand: select node under or above depending on pressed sneak key. 2018-08-06 17:43:08 +02:00
99fa0ebd75 Document //stretch, remove old documentation for //scale
scale was replaced with stretch in 674d647
2018-07-26 11:52:10 +02:00
a97cccd2a1 Disable worldedit_brush mod instead of throwing error (#156) 2018-04-10 09:25:08 +02:00
3322ef90c4 Fix negative height pyramids (fixes #152) 2018-01-04 01:03:51 +01:00
b259906fd0 Add support for smart_inventory 2017-11-13 09:58:42 +01:00
12270dc094 Correct spelling of Minetest 2017-11-07 14:20:50 +01:00
415000e797 Fix a few assignments to undeclared globals 2017-11-07 14:19:57 +01:00
7b1deb1b61 Add configurable brush item
texture was supposed to be a brush, i suck at this :(
2017-09-17 23:47:29 +02:00
4605596215 Fix assignment to undeclared global "sign" @ worldedit_commands/init.lua:791 2017-09-12 14:58:26 +02:00
59dc2d34d9 WorldEdit 1.2 2017-09-12 14:56:01 +02:00
283f47f10d Fix invalid node error message of //set and //mix 2017-09-12 14:56:01 +02:00
35ad2f031d Remove work in progress/unused components
infinity: unused and not public, superseded by minetest.raycast()
limited: wip and disabled entirely anyway
2017-09-12 14:13:18 +02:00
d572d769ce Optimize gui icon texture 2017-09-12 13:30:11 +02:00
5bbb6b3909 Support //cube in the GUI 2017-09-12 13:25:33 +02:00
d6a9b517b5 Remove Lua functions from WorldEdit GUI 2017-09-12 13:04:25 +02:00
3c61759bae Allow to bulk-set param2 of regions (#144) 2017-09-05 14:40:46 +02:00
2f4eb19a3a Fix one-node high cylinders
closes #146
2017-09-03 20:12:38 +02:00
2cb3fcde66 Improve node name normalization 2017-08-31 20:38:38 +02:00
e680d8087e Fix small logic error in worldedit.cylinder 2017-08-31 20:10:08 +02:00
870873ad15 Add //hollowcube and //cube
closes #143
2017-08-31 19:08:10 +02:00
e356f4521c WorldEdit GUI support for new //cylinder functionality 2017-08-31 16:46:57 +02:00
bf8e2a8233 Dual-based cylinder 2017-08-31 16:25:22 +02:00
6ceb56c3dc Disable worldedit_gui fallback code (closes #141) 2017-08-20 12:21:41 +02:00
1fabe60d77 Make sfinv gui code compatible with sfinv as included in MTG 0.4.15
fixes #142
2017-08-20 12:13:56 +02:00
acc9188828 Add logging for //lua and //luatransform 2017-05-21 17:31:59 +02:00
3240167b13 Forgot this one during refactor (a31f955fb1) 2017-05-13 11:53:52 +02:00
66b1fa032d Remove formspec tester from worldedit_gui 2017-05-13 11:52:45 +02:00
a31f955fb1 Refactor priv determination in worldedit_gui 2017-05-13 11:51:36 +02:00
38e9b42caf Do not allow any worldedit_gui commands without privs 2017-05-13 11:51:36 +02:00
ea465f8fe4 Remove useless privilege checks
This is covered by the privs = {...},
2017-05-13 11:51:36 +02:00
0ce45a5900 Fix worldedit_gui_lua privs
This fixes the worldedit_gui_lua feature so that it requires certain privs to run.
2017-05-13 11:17:45 +02:00
56f77a2f27 Remove unused toolcaps of the wand tool 2017-03-11 12:50:27 +01:00
610cd9981d Use sfinv if possible, fixes #124 with recent minetest versions 2017-03-11 12:47:30 +01:00
c0f3bb6958 GUI: Use nicer picture to indicate unknown nodes (-> no search results) 2017-03-11 12:24:47 +01:00
e49f717000 GUI: Always pass normalized node names to commands 2017-03-11 12:03:06 +01:00
6e7b9a60be Update wand definition (#129)
Fixes "maxwear" deprecated warning
2017-02-11 00:04:04 +01:00
bcac45a476 Fix "safe region" functionality errornously rejecting pos1-only commands (e.g. //sphere) 2017-01-31 19:52:54 +01:00
426f3b949f Show light level a node receives with //inspect, fixes #128 2017-01-26 22:27:30 +01:00
78e4ba828e Show light level with //inspect 2017-01-03 17:11:38 +01:00
92fe95fab7 Make //fixlight work again
The dig-air-nodes method seems to have stopped working a few Minetest version ago
2017-01-02 19:03:21 +01:00
3a7fb5bf1e Add //help command (fixes #123) 2017-01-01 22:27:22 +01:00
aa0e46d4e2 Handle failure of minetest.add_entity()
(see minetest/minetest#4923)
2016-12-21 14:26:24 +01:00
83288c969e Don't mark or load areas into memory when they are over a certain size, fixes #97 2016-12-10 22:02:40 +01:00
f9311b2b15 Move wand.lua to worldedit_commands 2016-12-10 21:54:51 +01:00
15f0cea72e Disable wand tool on entities 2016-12-10 21:39:44 +01:00
6e2e2385e9 Merge remote-tracking branch 'tmp/hollowpyramid' 2016-10-13 17:51:01 +02:00
152707a322 Fix 'Run Lua' button in WorldEdit GUI (fixes #121) 2016-10-12 20:10:36 +02:00
d040d324e8 Fix //spiral requiring a selected region despite using only pos1 2016-10-12 19:45:38 +02:00
df6b54d2f5 Fix blowing up TNT near worldedit markers 2016-10-12 19:38:41 +02:00
5abe1cee3d Fix exiting mtschemprob entry dialog with ESC 2016-08-05 16:41:37 +02:00
5afea424ba Move cuboidapi.lua to correct place 2016-07-04 19:57:48 +02:00
2aed498849 Add completion chat message to //expand and //contract 2016-07-04 19:53:12 +02:00
0b68b2aec6 Fix //shift with absolute axis (x/y/z) 2016-07-04 19:51:28 +02:00
f72abdb766 Merge remote-tracking branch 'tmp/cuboidmanip' 2016-07-04 19:49:23 +02:00
e18525d8c9 Modify outset and inset to accept both hv and vh combinations. Update documentation accordingly. 2016-07-03 21:44:02 -05:00
78890dde07 Clean some documentation issues 2016-07-03 21:44:02 -05:00
b922097e7a Update command documentation 2016-07-03 21:44:02 -05:00
48f3f59fc3 Implement some safety mechanisms 2016-07-03 21:44:02 -05:00
f8f1f3b9cc Reimplement /expand and /contract to conform to WE standards 2016-07-03 21:44:02 -05:00
d5e004be67 Fix /outset and /inset to conform to WE standards 2016-07-03 21:44:02 -05:00
fad021d0ba Remove some debug code 2016-07-03 21:44:02 -05:00
f1fe0c6bba Fix /shift command to conform to worldedit command standard 2016-07-03 21:44:02 -05:00
40cee99700 Fix a crash that happened when trying to shift the cuboid using relative direction while looking straight up or down 2016-07-03 21:44:02 -05:00
04d20de4cd Fix several typos 2016-07-03 21:44:02 -05:00
859c6bd12a Implement /expand and /contract 2016-07-03 21:44:02 -05:00
240380ff16 Implement /inset and /shift 2016-07-03 21:44:02 -05:00
8d213d32a0 refactor code for mantainability and reusability. Start of chat command refactor. Implement /outset. 2016-07-03 21:44:02 -05:00
ae29a9f064 Reimplement inset/outset to make use of new marker functions 2016-07-03 21:44:02 -05:00
6cf8b92434 Reimplement /shift to make use of new marker functions 2016-07-03 21:44:02 -05:00
0b97a7c740 Finish /expand implementation. Add /contract command. 2016-07-03 21:44:02 -05:00
900b2f25aa Fix faulty regex in expand. Add relative direction decoding. 2016-07-03 21:44:02 -05:00
f49663902c Major progress and simplification in /expand function 2016-07-03 21:44:02 -05:00
d475682d8f Add common functions to move and update the markers 2016-07-03 21:44:02 -05:00
9e087ff995 Add outset, inset, shift and initial draft of expand 2016-07-03 21:44:02 -05:00
b23e92921c fix gui bug with back button (#116)
Fixed the Worldedit GUI problem where BACK button wouldn't return back to inventory plus menu.
2016-06-20 18:05:47 +02:00
61ab240cea Add //drain 2016-03-23 22:09:55 +01:00
b06e004d80 Merge pull request #108 from kilbith/master
Fix unability to browse inv. items on creative inventory
2016-02-22 15:54:25 +01:00
6dddc93ed7 Fix unability to browse inv. items on creative inventory 2016-02-22 12:29:06 +01:00
b99a51f468 Merge pull request #107 from kilbith/master
Re-adapt WorldEdit's GUI button position to new creative inventory
2016-02-22 10:33:04 +01:00
91c5053e67 Re-adapt WorldEdit's GUI button position to creative inventory 2016-02-22 10:29:53 +01:00
f2f714c19e Fix crash when loading version 3 schematics 2016-01-23 16:57:27 -05:00
47712844a3 Added a WorldEdit wand item that can be used to select areas with worldedit. 2016-01-22 22:24:17 +01:00
2bd4d6fa8f Merge pull request #101 from kilbith/master
Adapt WorldEdit GUI button to the new creative inventory
2016-01-17 15:29:06 +01:00
e9e8de385c Adapt WorldEdit GUI button to the new creative inventory 2016-01-17 15:26:47 +01:00
2e2fcfdfa2 Fixed Issue #83 : upsidedown pyramid not working well 2016-01-05 14:11:04 +01:00
e0a2661700 Fix //stack2 not working (closes #94) 2016-01-05 13:57:48 +01:00
Rui
7a19c5303b Fix undeclared global variable 2016-01-05 13:33:12 +01:00
35b68c481b Fixed dropdown menus in the WorldEdit GUI (closes #78, thanks to @sponce) 2016-01-05 13:14:47 +01:00
51158eca9f Fix Save/Load from WorldEdit GUI, fixes #90 2016-01-05 12:42:01 +01:00
3aa315f134 Fix Orient in WorldEdit GUI 2016-01-05 12:24:06 +01:00
3d30588a68 Clarify //deleteblocks 2015-12-18 17:33:29 -05:00
48f9c6c23f Fix #93 (thanks @za267!) 2015-11-01 16:50:36 -05:00
5f9efb1205 Added hollow pyramids 2015-09-13 22:08:04 +02:00
fc037e9c82 Fix formspec typo causing crashing upon using /orient in the GUI. 2015-06-18 18:14:45 -04:00
90d6b3d237 Allow more characters in file names 2015-06-01 17:08:43 -04:00
4bd5d56909 Localize mkdir helper 2015-06-01 16:53:03 -04:00
163dffccb3 Fix leaking {safe,check}_region 2015-05-16 19:52:48 -04:00
6b2fe397e6 Use minetest.mkdir when available 2015-05-16 19:46:33 -04:00
5c115e282c Fix existence check trying to open files for writing 2015-05-16 19:27:27 -04:00
ab47385f7b Fix crash (worldedit/manipulations.lua:526: attempt to call global 'set_node' (a nil value)) 2015-05-04 18:48:27 +02:00
78915d4a54 Merge pull request #76 from est31/fixserialisation
Load first node too with LuaJIT
2015-03-11 22:08:32 -04:00
09de34aabf Load first node too with LuaJIT
Before, the first node would have had the version number prepended (e.g. "5:"), and therefore wouldn't be loaded.
2015-03-12 02:40:19 +01:00
c1bd4986b0 Merge pull request #74 from est31/deleteblocks
Add //deleteblocks command
2015-02-21 00:42:05 -05:00
bea38a116a Add //deleteblocks command 2015-02-20 22:30:34 +01:00
4336e7ca14 Merge pull request #73 from est31/hidebutton
Make inventory++ hide button for players without worldedit priv
2015-02-16 19:58:59 -05:00
eca54f0851 Make inventory++ hide button for players without worldedit priv 2015-02-16 23:05:18 +01:00
b0fbcf197f Merge pull request #72 from HybridDog/globalfix
fix an error message
2015-02-14 23:25:20 -05:00
b468e24a20 fix an error message 2015-02-14 23:10:21 +01:00
32 changed files with 686 additions and 458 deletions

View File

@ -17,6 +17,7 @@ Many commands also have shorter names that can be typed faster. For example, if
| `//s` | `//set` |
| `//r` | `//replace` |
| `//ri` | `//replaceinverse` |
| `//hcube` | `//hollowcube` |
| `//hspr` | `//hollowsphere` |
| `//spr` | `//sphere` |
| `//hdo` | `//hollowdome` |
@ -116,14 +117,20 @@ Set the current WorldEdit region to `<node>`.
//set Blue Lightstone
//set dirt with grass
### `//mix <node1> ...`
### `//param2 <param2>`
Fill the current WorldEdit region with a random mix of `<node1>`, `...`.
Set the param2 value of all nodes in the current WorldEdit region to `<param2>`.
### `//mix <node1> [<count1>] <node2> [<count2>]...`
Fill the current WorldEdit region with a random mix of `<node1>`, `<node2>`, `...`. Weightings can be optionally specified via a number after a node name.
//mix air
//mix cactus stone glass sandstone
//mix Bronze
//mix default:cobble air
//mix stone 3 dirt 2
//mix cobblestone 8 stoneblock 2 stonebrick
### `//replace <search node> <replace node>`
@ -143,6 +150,19 @@ Replace all nodes other than `<search node>` with `<replace node>` in the curren
//replaceinverse dirt Bronze Block
//replaceinverse mesecons:wire_00000000_off flowers:flower_tulip
### `//hollowcube <width> <height> <length> <node>`
Adds a hollow cube with its ground level centered at WorldEdit position 1 with dimensions `<width>` x `<height>` x `<length>`, composed of `<node>`.
//hollowcube 6 5 6 Diamond Block
### `//cube <width> <height> <length> <node>`
Adds a cube with its ground level centered at WorldEdit position 1 with dimensions `<width>` x `<height>` x `<length>`, composed of `<node>`.
//cube 6 5 6 Diamond Block
//cube 7 2 1 default:cobble
### `//hollowsphere <radius> <node>`
Add hollow sphere centered at WorldEdit position 1 with radius `<radius>`, composed of `<node>`.
@ -175,23 +195,35 @@ Add dome centered at WorldEdit position 1 with radius `<radius>`, composed of `<
//dome -12 glass
//dome 17 mesecons:wire_00000000_off
### `//hollowcylinder x/y/z/? <length> <radius> <node>`
### `//hollowcylinder x/y/z/? <length> <radius1> [radius2] <node>`
Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<node>`.
Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>`, base radius `<radius1>` (and top radius `[radius2]`), composed of `<node>`.
Despite its name this command allows you to create cones (`radius2` = 0) as well as any shapes inbetween (0 < `radius2` < `radius1`).
Swapping `radius1` and `radius2` will create the same object but upside-down.
//hollowcylinder x +5 8 Bronze Block
//hollowcylinder y 28 10 glass
//hollowcylinder z -12 3 mesecons:wire_00000000_off
//hollowcylinder ? 2 4 default:stone
### `//cylinder x/y/z/? <length> <radius> <node>`
//hollowcylinder y 10 10 0 walls:cobble
//hollowcylinder x 6 0 5 Dirt
//hollowcylinder z 20 10 20 default:desert_stone
Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>` and radius `<radius>`, composed of `<node>`.
### `//cylinder x/y/z/? <length> <radius1> [radius2] <node>`
Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length `<length>`, base radius `<radius1>` (and top radius `[radius2]`), composed of `<node>`.
Can also create shapes other than cylinders, e.g. cones (see documentation above).
//cylinder x +5 8 Bronze Block
//cylinder y 28 10 glass
//cylinder z -12 3 mesecons:wire_00000000_off
//cylinder ? 2 4 default:stone
//cylinder y 10 10 0 walls:cobble
//cylinder x 6 0 5 Dirt
//cylinder z 20 10 20 default:desert_stone
### `//hollowpyramid x/y/z? <height> <node>`
@ -253,13 +285,13 @@ Stack the current WorldEdit region `<count>` times by offset `<x>`, `<y>`, `<z>`
//stack2 5 3 8 2
//stack2 1 -1 -1 -1
### `//scale <factor>`
### `//stretch <stretchx> <stretchy> <stretchz>`
Scale the current WorldEdit positions and region by a factor of positive integer `<factor>` with position 1 as the origin.
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.
//scale 2
//scale 1
//scale 10
//stretch 2 2 2
//stretch 1 2 1
//stretch 10 20 1
### `//transpose x/y/z/? x/y/z/?`
@ -432,4 +464,15 @@ or vertically in the y axis `[v]`.
Contracts the selection in all directions by `<amount>`. If specified, the selection can be contracted horizontally in the x and z axes `[h]`
or vertically in the y axis `[v]`.
//outset v 5
//outset v 5
### `//brush none/<command> [parameters]`
Assigns the given `<command>` to the currently held brush item, it will be ran with the first pointed solid node (as determined via raycast) as
WorldEdit position 1 when using that specific brush item.
Passing `none` instead clears the command assigned to the currently held brush item.
Note that this functionality requires the `worldedit_brush` mod enabled.
//brush cube 8 8 8 Cobblestone
//brush spr 12 glass
//brush none

0
LICENSE.txt Executable file → Normal file
View File

21
README.md Executable file → Normal file
View File

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

0
Tutorial.md Executable file → Normal file
View File

View File

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

0
config.ld Executable file → Normal file
View File

0
modpack.txt Executable file → Normal file
View File

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

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

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

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

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

View File

@ -38,6 +38,29 @@ function worldedit.set(pos1, pos2, node_names)
return worldedit.volume(pos1, pos2)
end
--- Sets param2 of a region.
-- @param pos1
-- @param pos2
-- @param param2 Value of param2 to set
-- @return The number of nodes set.
function worldedit.set_param2(pos1, pos2, param2)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local manip, area = mh.init(pos1, pos2)
local param2_data = manip:get_param2_data()
-- Set param2 for every node
for i in area:iterp(pos1, pos2) do
param2_data[i] = param2
end
-- Update map
manip:set_param2_data(param2_data)
manip:write_to_map()
manip:update_map()
return worldedit.volume(pos1, pos2)
end
--- Replaces all instances of `search_node` with `replace_node` in a region.
-- When `inverse` is `true`, replaces all instances that are NOT `search_node`.
@ -278,7 +301,7 @@ function worldedit.stack(pos1, pos2, axis, count)
local amount = 0
local copy = worldedit.copy
local i = 1
function next_one()
local function next_one()
if i <= count then
i = i + 1
amount = amount + length
@ -506,20 +529,22 @@ end
-- @param pos2
-- @param angle Angle in degrees (90 degree increments only).
-- @return The number of nodes oriented.
-- TODO: Support 6D facedir rotation along arbitrary axis.
function worldedit.orient(pos1, pos2, angle)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local registered_nodes = minetest.registered_nodes
local wallmounted = {
[90] = {[0]=0, 1, 5, 4, 2, 3},
[180] = {[0]=0, 1, 3, 2, 5, 4},
[270] = {[0]=0, 1, 4, 5, 3, 2}
[90] = {0, 1, 5, 4, 2, 3, 0, 0},
[180] = {0, 1, 3, 2, 5, 4, 0, 0},
[270] = {0, 1, 4, 5, 3, 2, 0, 0}
}
local facedir = {
[90] = {[0]=1, 2, 3, 0},
[180] = {[0]=2, 3, 0, 1},
[270] = {[0]=3, 0, 1, 2}
[90] = { 1, 2, 3, 0, 13, 14, 15, 12, 17, 18, 19, 16,
9, 10, 11, 8, 5, 6, 7, 4, 23, 20, 21, 22},
[180] = { 2, 3, 0, 1, 10, 11, 8, 9, 6, 7, 4, 5,
18, 19, 16, 17, 14, 15, 12, 13, 22, 23, 20, 21},
[270] = { 3, 0, 1, 2, 19, 16, 17, 18, 15, 12, 13, 14,
7, 4, 5, 6, 11, 8, 9, 10, 21, 22, 23, 20}
}
angle = angle % 360
@ -535,8 +560,7 @@ function worldedit.orient(pos1, pos2, angle)
worldedit.keep_loaded(pos1, pos2)
local count = 0
local set_node, get_node, get_meta, swap_node = minetest.set_node,
minetest.get_node, minetest.get_meta, minetest.swap_node
local get_node, swap_node = minetest.get_node, minetest.swap_node
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
pos.y = pos1.y
@ -546,17 +570,20 @@ function worldedit.orient(pos1, pos2, angle)
local node = get_node(pos)
local def = registered_nodes[node.name]
if def then
if def.paramtype2 == "wallmounted" then
node.param2 = wallmounted_substitution[node.param2]
local meta = get_meta(pos):to_table()
set_node(pos, node)
get_meta(pos):from_table(meta)
local paramtype2 = def.paramtype2
if paramtype2 == "wallmounted" or
paramtype2 == "colorwallmounted" then
local orient = node.param2 % 8
node.param2 = node.param2 - orient +
wallmounted_substitution[orient + 1]
swap_node(pos, node)
count = count + 1
elseif def.paramtype2 == "facedir" then
node.param2 = facedir_substitution[node.param2]
local meta = get_meta(pos):to_table()
set_node(pos, node)
get_meta(pos):from_table(meta)
elseif paramtype2 == "facedir" or
paramtype2 == "colorfacedir" then
local orient = node.param2 % 32
node.param2 = node.param2 - orient +
facedir_substitution[orient + 1]
swap_node(pos, node)
count = count + 1
end
end

View File

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

View File

@ -56,10 +56,19 @@ function worldedit.serialize(pos1, pos2)
worldedit.keep_loaded(pos1, pos2)
local get_node, get_meta, hash_node_position =
minetest.get_node, minetest.get_meta, minetest.hash_node_position
-- Find the positions which have metadata
local has_meta = {}
local meta_positions = minetest.find_nodes_with_meta(pos1, pos2)
for i = 1, #meta_positions do
has_meta[hash_node_position(meta_positions[i])] = true
end
local pos = {x=pos1.x, y=0, z=0}
local count = 0
local result = {}
local get_node, get_meta = minetest.get_node, minetest.get_meta
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
@ -68,20 +77,19 @@ function worldedit.serialize(pos1, pos2)
local node = get_node(pos)
if node.name ~= "air" and node.name ~= "ignore" then
count = count + 1
local meta = get_meta(pos):to_table()
local meta_empty = true
-- Convert metadata item stacks to item strings
for name, inventory in pairs(meta.inventory) do
for index, stack in ipairs(inventory) do
meta_empty = false
inventory[index] = stack.to_string and stack:to_string() or stack
end
end
for k in pairs(meta) do
if k ~= "inventory" then
meta_empty = false
break
local meta
if has_meta[hash_node_position(pos)] then
meta = get_meta(pos):to_table()
-- Convert metadata item stacks to item strings
for _, invlist in pairs(meta.inventory) do
for index = 1, #invlist do
local itemstack = invlist[index]
if itemstack.to_string then
invlist[index] = itemstack:to_string()
end
end
end
end
@ -92,7 +100,7 @@ function worldedit.serialize(pos1, pos2)
name = node.name,
param1 = node.param1 ~= 0 and node.param1 or nil,
param2 = node.param2 ~= 0 and node.param2 or nil,
meta = not meta_empty and meta or nil,
meta = meta,
}
end
pos.z = pos.z + 1
@ -188,7 +196,7 @@ end
-- @return The number of nodes.
function worldedit.allocate(origin_pos, value)
local nodes = load_schematic(value)
if not nodes then return nil end
if not nodes or #nodes == 0 then return nil end
return worldedit.allocate_with_nodes(origin_pos, nodes)
end
@ -219,6 +227,7 @@ end
function worldedit.deserialize(origin_pos, value)
local nodes = load_schematic(value)
if not nodes then return nil end
if #nodes == 0 then return #nodes end
local pos1, pos2 = worldedit.allocate_with_nodes(origin_pos, nodes)
worldedit.keep_loaded(pos1, pos2)

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

@ -6,6 +6,7 @@ minetest.register_node("worldedit:placeholder", {
paramtype = "light",
sunlight_propagates = true,
diggable = false,
pointable = false,
walkable = false,
groups = {not_in_creative_inventory=1},
})

View File

@ -0,0 +1,2 @@
worldedit
worldedit_commands

161
worldedit_brush/init.lua Normal file
View File

@ -0,0 +1,161 @@
local modname = minetest.get_current_modname()
-- check compatibility
if minetest.raycast == nil then
function log_unavailable_error()
minetest.log("error",
"[MOD] " .. modname .. " is not compatible with current game version, " ..
"you can disable it in the game settings!"
)
minetest.log("verbose",
"[MOD] " .. modname .. " requires a suitable version of 0.4.16-dev or higher, " ..
"that includes support for minetest.raycast() [since 7th July 2017]"
)
end
if minetest.is_singleplayer() then
-- delay message until player is connected
minetest.register_on_joinplayer(log_unavailable_error)
else
log_unavailable_error()
end
-- exit here / do not load this mod
return
end
local BRUSH_MAX_DIST = 150
local BRUSH_ALLOWED_COMMANDS = {
-- basically everything that only needs pos1
"cube",
"cylinder",
"dome",
"hollowcube",
"hollowcylinder",
"hollowdome",
"hollowpyramid",
"hollowsphere",
"load",
"pyramid",
"sphere",
"spiral",
"cyl",
"do",
"hcube",
"hcyl",
"hdo",
"hpyr",
"hspr",
"l",
"pyr",
"spr",
"spl",
}
local brush_on_use = function(itemstack, placer)
local meta = itemstack:get_meta()
local name = placer:get_player_name()
local cmd = meta:get_string("command")
if cmd == "" then
worldedit.player_notify(name,
"This brush is not bound, use //brush to bind a command to it.")
return false
end
local cmddef = minetest.registered_chatcommands["/" .. cmd]
if cmddef == nil then return false end -- shouldn't happen as //brush checks this
local has_privs, missing_privs = minetest.check_player_privs(name, cmddef.privs)
if not has_privs then
worldedit.player_notify(name,
"Missing privileges: " .. table.concat(missing_privs, ", "))
return false
end
local raybegin = vector.add(placer:get_pos(), {x=0, y=2, z=0}) -- player head
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()
if pointed_thing == nil then
worldedit.player_notify(name, "Too far away.")
return false
end
assert(pointed_thing.type == "node")
worldedit.pos1[name] = pointed_thing.under
worldedit.pos2[name] = nil
worldedit.mark_region(name)
-- is this a horrible hack? oh yes.
worldedit._override_safe_regions = true
local player_notify_old = worldedit.player_notify
worldedit.player_notify = function(name, msg)
if string.match(msg, "^%d") then return end -- discard "1234 nodes added."
return player_notify_old(name, msg)
end
minetest.log("action", string.format("%s uses WorldEdit brush (//%s) at %s",
name, cmd, minetest.pos_to_string(pointed_thing.under)))
cmddef.func(name, meta:get_string("params"))
worldedit._override_safe_regions = false
worldedit.player_notify = player_notify_old
return true
end
minetest.register_tool(":worldedit:brush", {
description = "WorldEdit Brush",
inventory_image = "worldedit_brush.png",
stack_max = 1, -- no need to stack these (metadata prevents this anyway)
range = 0,
on_use = function(itemstack, placer, pointed_thing)
brush_on_use(itemstack, placer)
return itemstack -- nothing consumed, nothing changed
end,
})
minetest.register_chatcommand("/brush", {
privs = {worldedit=true},
params = "none/<cmd> [parameters]",
description = "Assign command to WorldEdit brush item",
func = function(name, param)
local found, _, cmd, params = param:find("^([^%s]+)%s+(.+)$")
if not found then
params = ""
found, _, cmd = param:find("^(.+)$")
end
if not found then
worldedit.player_notify(name, "Invalid usage.")
return
end
local itemstack = minetest.get_player_by_name(name):get_wielded_item()
if itemstack == nil or itemstack:get_name() ~= "worldedit:brush" then
worldedit.player_notify(name, "Not holding brush item.")
return
end
cmd = cmd:lower()
local meta = itemstack:get_meta()
if cmd == "none" then
meta:from_table(nil)
worldedit.player_notify(name, "Brush assignment cleared.")
else
local cmddef
if table.indexof(BRUSH_ALLOWED_COMMANDS, cmd) ~= -1 then
cmddef = minetest.registered_chatcommands["/" .. cmd]
else
cmddef = nil
end
if cmddef == nil then
worldedit.player_notify(name, "Invalid command for brush use: //" .. cmd)
return
end
meta:set_string("command", cmd)
meta:set_string("params", params)
local fullcmd = "//" .. cmd .. " " .. params
meta:set_string("description",
minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
worldedit.player_notify(name, "Brush assigned to command: " .. fullcmd)
end
minetest.get_player_by_name(name):set_wielded_item(itemstack)
end,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

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

View File

@ -23,6 +23,7 @@ local function get_position(name) --position 1 retrieval function for when not u
return pos1
end
-- normalize_nodename wrapper for convenience purposes
local function get_node(name, nodename)
local node = worldedit.normalize_nodename(nodename)
if not node then
@ -36,26 +37,46 @@ function worldedit.player_notify(name, message)
minetest.chat_send_player(name, "WorldEdit -!- " .. message, false)
end
--determines whether `nodename` is a valid node name, returning a boolean
local function string_endswith(full, part)
return full:find(part, 1, true) == #full - #part + 1
end
-- normalizes node "description" `nodename`, returning a string (or nil)
worldedit.normalize_nodename = function(nodename)
nodename = nodename:gsub("^%s*(.-)%s*$", "%1")
nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
if nodename == "" then return nil end
local fullname = ItemStack({name=nodename}):get_name() --resolve aliases of node names to full names
if minetest.registered_nodes[fullname] or fullname == "air" then --directly found node name or alias of nodename
local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
return fullname
end
for key, value in pairs(minetest.registered_nodes) do
if key:find(":" .. nodename, 1, true) then --found in mod
if string_endswith(key, ":" .. nodename) then -- matches name (w/o mod part)
return key
end
end
nodename = nodename:lower() --lowercase both for case insensitive comparison
nodename = nodename:lower() -- lowercase both for case insensitive comparison
for key, value in pairs(minetest.registered_nodes) do
if value.description:lower() == nodename then --found in description
local desc = value.description:lower()
if desc == nodename then -- matches description
return key
end
if string_endswith(desc, " block") and desc == nodename.." block" then
-- fuzzy description match (e.g. "Steel" == "Steel Block")
return key
end
end
return nil
local match = nil
for key, value in pairs(minetest.registered_nodes) do
if value.description:lower():find(nodename, 1, true) ~= nil then
if match ~= nil then
return nil
end
match = key -- substring description match (only if no ambiguities)
end
end
return match
end
-- Determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
@ -87,9 +108,9 @@ end
minetest.register_chatcommand("/about", {
params = "",
description = "Get information about the mod",
description = "Get information about the WorldEdit mod",
func = function(name, param)
worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/MineTest-WorldEdit/")
worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/Minetest-WorldEdit/")
end,
})
@ -182,7 +203,7 @@ minetest.register_on_punchnode(function(pos, node, puncher)
local name = puncher:get_player_name()
if worldedit.inspect[name] then
local axis, sign = worldedit.player_axis(name)
message = string.format("inspector: %s at %s (param1=%d, param2=%d, received light=%d) punched facing the %s axis",
local message = string.format("inspector: %s at %s (param1=%d, param2=%d, received light=%d) punched facing the %s axis",
node.name, minetest.pos_to_string(pos), node.param1, node.param2, get_node_rlight(pos), axis .. (sign > 0 and "+" or "-"))
worldedit.player_notify(name, message)
end
@ -377,29 +398,49 @@ minetest.register_chatcommand("/set", {
privs = {worldedit=true},
func = safe_region(function(name, param)
local node = get_node(name, param)
if not node then
worldedit.player_notify(name, "Could not identify node \"" .. param .. "\"")
return
end
if not node then return end
local count = worldedit.set(worldedit.pos1[name], worldedit.pos2[name], node)
worldedit.player_notify(name, count .. " nodes set")
end, check_region),
})
minetest.register_chatcommand("/param2", {
params = "<param2>",
description = "Set param2 of all nodes in the current WorldEdit region to <param2>",
privs = {worldedit=true},
func = safe_region(function(name, param)
local param2 = tonumber(param)
if not param2 then
worldedit.player_notify(name, "Invalid or missing param2 argument")
return
elseif param2 < 0 or param2 > 255 then
worldedit.player_notify(name, "Param2 is out of range (must be between 0 and 255 inclusive)!")
return
end
local count = worldedit.set_param2(worldedit.pos1[name], worldedit.pos2[name], param2)
worldedit.player_notify(name, count .. " nodes altered")
end, check_region),
})
minetest.register_chatcommand("/mix", {
params = "<node1> ...",
params = "<node1> [<weighting1>] [<node2> [<weighting2>]] ...",
description = "Fill the current WorldEdit region with a random mix of <node1>, ...",
privs = {worldedit=true},
func = safe_region(function(name, param)
local nodes = {}
for nodename in param:gmatch("[^%s]+") do
local node = get_node(name, nodename)
if not node then
worldedit.player_notify(name, "Could not identify node \"" .. name .. "\"")
return
if tonumber(nodename) ~= nil and #nodes > 0 then
local last_node = nodes[#nodes]
for i = 1, tonumber(nodename) do
nodes[#nodes + 1] = last_node
end
else
local node = get_node(name, nodename)
if not node then return end
nodes[#nodes + 1] = node
end
nodes[#nodes + 1] = node
end
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
@ -455,6 +496,45 @@ minetest.register_chatcommand("/replaceinverse", {
end, check_replace),
})
local check_cube = function(name, param)
if worldedit.pos1[name] == nil then
worldedit.player_notify(name, "no position 1 selected")
return nil
end
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
worldedit.player_notify(name, "invalid usage: " .. param)
return nil
end
local node = get_node(name, nodename)
if not node then return nil end
return tonumber(w) * tonumber(h) * tonumber(l)
end
minetest.register_chatcommand("/hollowcube", {
params = "<width> <height> <length> <node>",
description = "Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
local node = get_node(name, nodename)
local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node, true)
worldedit.player_notify(name, count .. " nodes added")
end, check_cube),
})
minetest.register_chatcommand("/cube", {
params = "<width> <height> <length> <node>",
description = "Add a cube with its ground level centered at WorldEdit position 1 with dimensions <width> x <height> x <length>, composed of <node>.",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
local node = get_node(name, nodename)
local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node)
worldedit.player_notify(name, count .. " nodes added")
end, check_cube),
})
local check_sphere = function(name, param)
if worldedit.pos1[name] == nil then
worldedit.player_notify(name, "no position 1 selected")
@ -538,46 +618,67 @@ local check_cylinder = function(name, param)
worldedit.player_notify(name, "no position 1 selected")
return nil
end
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
if found == nil then
worldedit.player_notify(name, "invalid usage: " .. param)
return nil
end
local node = get_node(name, nodename)
if not node then return nil end
return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length))
local radius = math.max(tonumber(radius1), tonumber(radius2))
return math.ceil(math.pi * (radius ^ 2) * tonumber(length))
end
minetest.register_chatcommand("/hollowcylinder", {
params = "x/y/z/? <length> <radius> <node>",
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
params = "x/y/z/? <length> <radius1> [radius2] <node>",
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
length = tonumber(length)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
length = length * sign
end
local node = get_node(name, nodename)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node, true)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node, true)
worldedit.player_notify(name, count .. " nodes added")
end, check_cylinder),
})
minetest.register_chatcommand("/cylinder", {
params = "x/y/z/? <length> <radius> <node>",
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
params = "x/y/z/? <length> <radius1> [radius2] <node>",
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length>, base radius <radius1> (and top radius [radius2]), composed of <node>",
privs = {worldedit=true},
func = safe_region(function(name, param)
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
-- two radii
local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
-- single radius
found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
radius2 = radius1
end
length = tonumber(length)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
length = length * sign
end
local node = get_node(name, nodename)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node)
local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node)
worldedit.player_notify(name, count .. " nodes added")
end, check_cylinder),
})
@ -606,6 +707,7 @@ minetest.register_chatcommand("/hollowpyramid", {
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
height = tonumber(height)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
height = height * sign
end
@ -623,6 +725,7 @@ minetest.register_chatcommand("/pyramid", {
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
height = tonumber(height)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
height = height * sign
end
@ -670,6 +773,7 @@ minetest.register_chatcommand("/copy", {
end
amount = tonumber(amount)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
amount = amount * sign
end
@ -696,6 +800,7 @@ minetest.register_chatcommand("/move", {
end
amount = tonumber(amount)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
amount = amount * sign
end
@ -718,6 +823,7 @@ minetest.register_chatcommand("/stack", {
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
repetitions = tonumber(repetitions)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
repetitions = repetitions * sign
end
@ -799,9 +905,12 @@ minetest.register_chatcommand("/stretch", {
stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)
if stretchx == 0 or stretchy == 0 or stretchz == 0 then
worldedit.player_notify(name, "invalid scaling factors: " .. param)
return nil
end
local count = check_region(name, param)
if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end
if count then
return stretchx * stretchy * stretchz * count
end
return nil
end),
})
@ -1054,9 +1163,15 @@ minetest.register_chatcommand("/allocate", {
return
elseif version > worldedit.LATEST_SERIALIZATION_VERSION then
worldedit.player_notify(name, "File was created with newer version of WorldEdit!")
return
end
local nodepos1, nodepos2, count = worldedit.allocate(pos, value)
if not nodepos1 then
worldedit.player_notify(name, "Schematic empty, nothing allocated")
return
end
worldedit.pos1[name] = nodepos1
worldedit.mark_pos1(name)
worldedit.pos2[name] = nodepos2
@ -1126,8 +1241,10 @@ minetest.register_chatcommand("/lua", {
local err = worldedit.lua(param)
if err then
worldedit.player_notify(name, "code error: " .. err)
minetest.log("action", name.." tried to execute "..param)
else
worldedit.player_notify(name, "code successfully executed", false)
minetest.log("action", name.." executed "..param)
end
end,
})
@ -1140,8 +1257,10 @@ minetest.register_chatcommand("/luatransform", {
local err = worldedit.luatransform(worldedit.pos1[name], worldedit.pos2[name], param)
if err then
worldedit.player_notify(name, "code error: " .. err, false)
minetest.log("action", name.." tried to execute luatransform "..param)
else
worldedit.player_notify(name, "code successfully executed", false)
minetest.log("action", name.." executed luatransform "..param)
end
end),
})

View File

@ -1,6 +1,8 @@
local safe_region_callback = {}
local safe_region_param = {}
worldedit._override_safe_regions = false -- internal use ONLY!
local function check_region(name, param)
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] --obtain positions
if pos1 == nil or pos2 == nil then
@ -20,7 +22,7 @@ local function safe_region(callback, nodes_needed)
--check if the operation applies to a safe number of nodes
local count = nodes_needed(name, param)
if count == nil then return end --invalid command
if count < 10000 then
if worldedit._override_safe_regions or count < 10000 then
return callback(name, param)
end
@ -44,20 +46,21 @@ minetest.register_chatcommand("/y", {
return
end
safe_region_callback[name], safe_region_param[name] = nil, nil --reset pending operation
reset_pending(name)
callback(name, param)
end,
})
minetest.register_chatcommand("/n", {
params = "",
description = "Confirm a pending operation",
description = "Abort a pending operation",
func = function(name)
if not safe_region_callback[name] then
worldedit.player_notify(name, "no operation pending")
return
end
safe_region_callback[name], safe_region_param[name] = nil, nil
reset_pending(name)
end,
})

View File

@ -1,3 +1,11 @@
local function above_or_under(placer, pointed_thing)
if placer:get_player_control().sneak then
return pointed_thing.above
else
return pointed_thing.under
end
end
minetest.register_tool(":worldedit:wand", {
description = "WorldEdit Wand tool, Left-click to set 1st position, right-click to set 2nd",
inventory_image = "worldedit_wand.png",
@ -7,7 +15,7 @@ minetest.register_tool(":worldedit:wand", {
on_use = function(itemstack, placer, pointed_thing)
if placer ~= nil and pointed_thing ~= nil and pointed_thing.type == "node" then
local name = placer:get_player_name()
worldedit.pos1[name] = pointed_thing.under
worldedit.pos1[name] = above_or_under(placer, pointed_thing)
worldedit.mark_pos1(name)
end
return itemstack -- nothing consumed, nothing changed
@ -16,7 +24,7 @@ minetest.register_tool(":worldedit:wand", {
on_place = function(itemstack, placer, pointed_thing) -- Left Click
if placer ~= nil and pointed_thing ~= nil and pointed_thing.type == "node" then
local name = placer:get_player_name()
worldedit.pos2[name] = pointed_thing.under
worldedit.pos2[name] = above_or_under(placer, pointed_thing)
worldedit.mark_pos2(name)
end
return itemstack -- nothing consumed, nothing changed

View File

@ -4,3 +4,4 @@ unified_inventory?
inventory_plus?
sfinv?
creative?
smart_inventory?

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

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

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

@ -80,8 +80,6 @@ if rawget(_G, "unified_inventory") then --unified inventory installed
unified_inventory.register_button("worldedit_gui", {
type = "image",
image = "inventory_plus_worldedit_gui.png",
tooltip = "Worldedit GUI",
show_with = "worldedit", --Modiff MFF (Crabman 30/06/2015)
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
@ -136,6 +134,55 @@ elseif rawget(_G, "inventory_plus") then --inventory++ installed
inventory_plus.set_inventory_formspec(player, get_formspec(name, page))
end
end
elseif rawget(_G, "smart_inventory") then -- smart_inventory installed
-- redefinition: Update the code element on inventory page to show the we-page
function worldedit.show_page(name, page)
local state = smart_inventory.get_page_state("worldedit_gui", name)
if state then
state:get("code"):set_we_formspec(page)
state.location.rootState:show() -- update inventory page
end
end
-- smart_inventory page callback. Contains just a "custom code" element
local function smart_worldedit_gui_callback(state)
local codebox = state:element("code", { name = "code", code = "" })
function codebox:set_we_formspec(we_page)
local new_formspec = get_formspec(state.location.rootState.location.player, we_page)
new_formspec = new_formspec:gsub('button_exit','button') --no inventory closing
self.data.code = "container[1,1]".. new_formspec .. "container_end[]"
end
codebox:set_we_formspec("worldedit_gui")
-- process input (the back button)
state:onInput(function(state, fields, player)
if fields.worldedit_gui then --main page
state:get("code"):set_we_formspec("worldedit_gui")
elseif fields.worldedit_gui_exit then --return to original page
state:get("code"):set_we_formspec("worldedit_gui")
state.location.parentState:get("crafting_button"):submit() -- switch to the crafting tab
end
end)
end
-- all handler should return false to force inventory UI update
local orig_register_gui_handler = worldedit.register_gui_handler
worldedit.register_gui_handler = function(identifier, handler)
local wrapper = function(...)
handler(...)
return false
end
orig_register_gui_handler(identifier, wrapper)
end
-- register the inventory button
smart_inventory.register_page({
name = "worldedit_gui",
tooltip = "Edit your World!",
icon = "inventory_plus_worldedit_gui.png",
smartfs_callback = smart_worldedit_gui_callback,
sequence = 99
})
elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0.4.15)
assert(sfinv.enabled)
local orig_get = sfinv.pages["sfinv:crafting"].get
@ -147,13 +194,21 @@ elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0
end
})
--compatibility with pre-0.4.16 sfinv
local set_page = sfinv.set_page or function(player, name)
--assumptions: src pg has no leave callback, dst pg has no enter callback
local ctx = {page=name}
sfinv.contexts[player:get_player_name()] = ctx
sfinv.set_player_inventory_formspec(player, ctx)
end
--show the form when the button is pressed and hide it when done
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.worldedit_gui then --main page
worldedit.show_page(player:get_player_name(), "worldedit_gui")
return true
elseif fields.worldedit_gui_exit then --return to original page
sfinv.set_page(player, "sfinv:crafting")
set_page(player, "sfinv:crafting")
return true
end
return false
@ -165,82 +220,14 @@ elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0
player:set_inventory_formspec(get_formspec(name, page))
end
end
else --fallback button
-- FIXME: this is a huge clusterfuck and the back button is broken
local player_formspecs = {}
local update_main_formspec = function(name)
local formspec = player_formspecs[name]
if not formspec then
return
end
local player = minetest.get_player_by_name(name)
if not player then --this is in case the player signs off while the media is loading
return
end
if (minetest.check_player_privs(name, {creative=true}) or
minetest.setting_getbool("creative_mode")) and
creative then --creative is active, add button to modified formspec
local creative_formspec = player:get_inventory_formspec()
local tab_id = tonumber(creative_formspec:match("tabheader%[.-;(%d+)%;"))
if tab_id == 1 then
formspec = creative_formspec ..
"image_button[0,1;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
elseif not tab_id then
formspec = creative_formspec ..
"image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
else
return
end
else
formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
end
player:set_inventory_formspec(formspec)
end
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
minetest.after(1, function()
if minetest.get_player_by_name(name) then --ensure the player is still signed in
player_formspecs[name] = player:get_inventory_formspec()
minetest.after(0.01, function()
update_main_formspec(name)
end)
end
end)
end)
minetest.register_on_leaveplayer(function(player)
player_formspecs[player:get_player_name()] = nil
end)
local gui_player_formspecs = {}
minetest.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
if fields.worldedit_gui then --main page
gui_player_formspecs[name] = player:get_inventory_formspec()
worldedit.show_page(name, "worldedit_gui")
return true
elseif fields.worldedit_gui_exit then --return to original page
if gui_player_formspecs[name] then
player:set_inventory_formspec(gui_player_formspecs[name])
end
return true
else --deal with creative_inventory setting the formspec on every single message
minetest.after(0.01,function()
update_main_formspec(name)
end)
return false --continue processing in creative inventory
end
end)
worldedit.show_page = function(name, page)
local player = minetest.get_player_by_name(name)
if player then
player:set_inventory_formspec(get_formspec(name, page))
end
end
else
error(
"worldedit_gui requires a supported \"gui management\" mod to be installed\n"..
"To use the GUI you need to either\n"..
"* Use minetest_game (at least 0.4.15) or a subgame with compatible sfinv\n"..
"* Install Unified Inventory or Inventory++\n"..
"If you do not want to use worldedit_gui, disable it by editing world.mt or from the Main Menu"
)
end
worldedit.register_gui_function("worldedit_gui", {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1 +0,0 @@
worldedit?

View File

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

View File

@ -1 +0,0 @@
worldedit

View File

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

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

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

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