Compare commits

...

299 Commits
v1.13 ... main

Author SHA1 Message Date
Starbeamrainbowlabs e89d61034f
Add GitHub issue templates 2023-12-05 22:54:06 +00:00
Starbeamrainbowlabs 8efceeaa4c
build: switch to deploying the website from dev rather than main 2023-08-02 23:59:52 +01:00
Starbeamrainbowlabs 5ca5d1f1de
add more namespace comments 2023-08-02 00:14:48 +01:00
Starbeamrainbowlabs 2a9dca6926
update changelog 2023-08-01 00:43:04 +01:00
Starbeamrainbowlabs dd6e34bde1
Update changelog, prepare for (another) release 2023-08-01 00:34:35 +01:00
Starbeamrainbowlabs 125638a079
pos_marker, pos_marker_wall: default to 1 hp 2023-08-01 00:27:07 +01:00
Starbeamrainbowlabs 7be2fb125e
add more debug logging 2023-08-01 00:16:36 +01:00
Starbeamrainbowlabs 6231132055
pos_marker: debug logging; set health = 0 2023-08-01 00:14:43 +01:00
Starbeamrainbowlabs abfd76930a
reference: add //listentities 2023-08-01 00:11:49 +01:00
Starbeamrainbowlabs aec204de8e
add //listentities 2023-08-01 00:07:10 +01:00
Starbeamrainbowlabs daae15eb57
EventEmitter: improve debug logging 2023-07-31 22:06:44 +01:00
Starbeamrainbowlabs 200e588c59
README: update title; add discord link 2023-07-31 20:51:09 +01:00
Starbeamrainbowlabs 2840ba4dea
bump version, prepare for release 2023-07-31 18:24:32 +01:00
Starbeamrainbowlabs 564785ddf6
When any segment of the marker wall is punched, unmark the entire wall
Fixes #102
2023-07-31 18:22:00 +01:00
Starbeamrainbowlabs a465a50244
Bump version to 1.14.3 2023-07-18 00:35:19 +01:00
Starbeamrainbowlabs 5505575cf9
Fix regions not remembering their state and being unresettable
This fix means that wwe require minetest 5.2 as a minimum rather than 5.1
ref https://rubenwardy.com/minetest_modding_book/en/quality/common_mistakes.html#be-careful-when-storing-objectrefs-ie-players-or-entities
2023-07-18 00:35:07 +01:00
Starbeamrainbowlabs fd3ee43728
//subdivide: fix crash 2023-07-15 21:59:24 +01:00
Starbeamrainbowlabs ee4b3e09bb
Bump version 2023-07-12 20:30:13 +01:00
Starbeamrainbowlabs 0645bc7b8e
Update changelog 2023-07-12 20:25:38 +01:00
VorTechnix 7766af8a8a pos1-2 better implementation (used round) 2023-07-12 09:18:15 -07:00
VorTechnix d2fb6db3d0 emergency patch for pos1-2 not aligned to node 2023-07-12 08:43:15 -07:00
Starbeamrainbowlabs a6e8753e64
README: Update FAQ 2023-07-11 21:11:12 +01:00
Starbeamrainbowlabs 1a227e3bd8
docs: h5→h4, h4→h3; style subheadings 2023-07-11 20:31:43 +01:00
Starbeamrainbowlabs ffc90ed179
typo 2023-07-11 19:30:43 +01:00
Starbeamrainbowlabs ab3120fe79
Update changelog, README command list 2023-07-11 19:29:50 +01:00
Starbeamrainbowlabs 87a80d2faf
reference: add //metaball
....oops
2023-07-11 19:23:39 +01:00
Starbeamrainbowlabs 83b4b02b40
codium settings: add spelling words 2023-07-11 19:15:14 +01:00
Starbeamrainbowlabs 95a82add86
//metaball: address a number of stability issues 2023-07-11 19:14:59 +01:00
Starbeamrainbowlabs 5baa72cf6f
core/run_command: guard against invalid potential_changes 2023-07-11 19:12:04 +01:00
Starbeamrainbowlabs 177aea02a8
//metaball: fix crash 2023-07-11 18:55:34 +01:00
Starbeamrainbowlabs 7f4798432e
Bump version! 2023-07-11 18:16:02 +01:00
Starbeamrainbowlabs 7236232dc0
docs: fix the 1st command documented not showing up in the site
Rogue .slice(1)
2023-07-11 00:52:04 +01:00
Starbeamrainbowlabs c8e717a6d6
typo 2023-07-11 00:39:48 +01:00
Starbeamrainbowlabs 4745009632
//saplingaliases: update moretrees aliases
Alias to normal rather than *_ongen
2023-07-10 21:33:37 +01:00
Starbeamrainbowlabs f7429fa40e
//move+, //copy+ override //move, //copy by default 2023-07-10 21:12:54 +01:00
Starbeamrainbowlabs 277f3a8155
//move+: respect param2
Also update changelog
2023-07-10 21:08:17 +01:00
Starbeamrainbowlabs d63400e697
//copy+: respect param2 2023-07-10 21:02:03 +01:00
Starbeamrainbowlabs 5c632df658
Override basic selection commands
//mark
//unmark
//pos1 //1
//pos2 //2
//reset
Also add //pos <index>
2023-07-10 20:17:28 +01:00
Starbeamrainbowlabs 693fc145d5
pos: avoid calling worldedit.marker_update unless necessary 2023-07-10 19:25:48 +01:00
Starbeamrainbowlabs 2c30ed8634
Tweak changelog 2023-07-09 23:39:52 +01:00
Starbeamrainbowlabs bf365d2d11
reference: update //maze and //maze3d
Ref https://forum.minetest.net/viewtopic.php?p=414718#p414718
2023-07-09 19:57:02 +01:00
Starbeamrainbowlabs f2214150f2
Update minetest.chatcommands → minetest.registered_chatcommands 2023-07-09 19:49:38 +01:00
Starbeamrainbowlabs 3bfc62be24
Make //unmark WEA-aware
Backwards compatibility with WE is maintained.
2023-07-09 19:44:31 +01:00
Starbeamrainbowlabs e916057133
safe_region: update comment
We need @value
2023-07-07 01:31:06 +01:00
Starbeamrainbowlabs 3194a2c53e
finish updating comments
@module is now banished to the history booked!

Phew, I'm pooped.
2023-07-07 01:25:42 +01:00
Starbeamrainbowlabs 20935d8379
maze2d: add comment 2023-07-07 00:53:02 +01:00
Starbeamrainbowlabs 74cc6669c0
floodfill,line: add proper comments
All @module declarations must go!
2023-07-07 00:42:57 +01:00
Starbeamrainbowlabs 2edc9f6f6c
forest: update comment 2023-07-04 23:14:18 +01:00
Starbeamrainbowlabs a78d385666
Merge branch 'main' of github.com:sbrl/Minetest-WorldEditAdditions 2023-07-04 22:55:15 +01:00
Starbeamrainbowlabs fd9d76353d
fillcaves: update comment 2023-07-04 22:55:12 +01:00
VorTechnix 5cf155772d Merge branch 'main' of https://github.com/sbrl/Minetest-WorldEditAdditions 2023-07-04 14:50:17 -07:00
VorTechnix 55ddc16b2e small fix to file:read error 2023-07-04 14:50:14 -07:00
Starbeamrainbowlabs 6bc1987916
Update and correct a bunch of comments
note that @module is outdated and should not be used
2023-07-04 22:45:02 +01:00
Starbeamrainbowlabs 365b491aa1
contributing guide: update example command 2023-07-04 22:44:28 +01:00
Starbeamrainbowlabs 5d18f6d0db
comment debug 2023-07-04 22:00:28 +01:00
Starbeamrainbowlabs 66c257c146
split_shell: added some more test cases for unclosed quotes 2023-07-04 20:35:01 +01:00
Starbeamrainbowlabs 7bdefc8d42
split_shell: comment out debug 2023-07-04 19:10:05 +01:00
Starbeamrainbowlabs 78c4a67c7b
split_test: even more tests 2023-07-04 19:09:42 +01:00
Starbeamrainbowlabs 02ad40eaae
split_shell: add automated tests, and fix an obscure bug 2023-07-04 19:04:11 +01:00
Starbeamrainbowlabs c988daeda6
update more comments 2023-07-02 20:05:46 +01:00
Starbeamrainbowlabs 047033a6ef
comments: update @class definitions 2023-07-02 19:03:46 +01:00
Starbeamrainbowlabs c6bc6e26e7
add chisel image 2023-07-02 18:22:03 +01:00
Starbeamrainbowlabs 8981bc4baa
weac.pos: update comments 2023-07-02 17:48:43 +01:00
Starbeamrainbowlabs 464ea53465
vector3: fix comments 2023-07-02 17:03:39 +01:00
Starbeamrainbowlabs e9c3d51863
Update changelog, name release 2023-07-02 15:12:25 +01:00
Starbeamrainbowlabs 5a76b3eaa9
art: attempt at a chisel
I'm not happy with it really.
2023-07-02 03:02:26 +01:00
Starbeamrainbowlabs 2e8642b4d7
rearrange and update changelog 2023-07-02 02:42:17 +01:00
Starbeamrainbowlabs 9b4a777a67
//scale, //subdivide, //spop: use new position api 2023-07-02 02:02:42 +01:00
Starbeamrainbowlabs 9be7854297
//move+, //copy+: add integrated airapply
fixes #97
2023-07-02 01:52:25 +01:00
Starbeamrainbowlabs 09ee1ae3fa
airapply: update docbloc comment 2023-07-02 01:38:27 +01:00
Starbeamrainbowlabs f970a8d6bb
reference: update docs for //sculpt 2023-07-02 01:37:48 +01:00
Starbeamrainbowlabs 61403108d6
disable a bunch of debug logging 2023-07-01 02:46:08 +01:00
Starbeamrainbowlabs f5e2ada5bd
//sculpt: put height at the end 2023-07-01 02:38:14 +01:00
Starbeamrainbowlabs 2756eb0eb5
docs: update npm dependencies 2023-07-01 01:15:13 +01:00
Starbeamrainbowlabs 92fd201b42
pos_marker_lua: add last_reset to properly clear huge regions 2023-07-01 01:11:56 +01:00
Starbeamrainbowlabs f800d7e3d7
A (bad) concept art for a //sculpt brush 2023-06-30 02:11:21 +01:00
Starbeamrainbowlabs b3f7ae9d7c
pos_marker_wall: add support for customising sides displayed
...it's not exposed in the UI yet tho.
2023-06-30 02:08:46 +01:00
Starbeamrainbowlabs 46587164bd
//sculpt: tweak the default settings
I got the idea from an MC video about voxelsniper. Surprisingly it works rather well :P
2023-06-29 03:19:30 +01:00
Starbeamrainbowlabs e3dac29a80
README: update inspiration section 2023-06-29 02:18:12 +01:00
Starbeamrainbowlabs 109c69502a
Changelog: add boxing ui WIP 2023-06-29 02:05:42 +01:00
Starbeamrainbowlabs 277da67dda
marker wall: got it! 2023-06-29 01:49:15 +01:00
Starbeamrainbowlabs a173edfbc4
wall markers: it shouldn't work, but it does
....I'll take it!
2023-06-29 01:22:50 +01:00
Starbeamrainbowlabs c622fb554f
Hook in the new marker wall system
it works!
now for the other walls.
2023-06-29 00:39:55 +01:00
Starbeamrainbowlabs 1b0001d88e
README: add an inspiration section
more for my own benefit, but perhaps it'll help people who swing by with energy they want to dedicate to the project.
2023-06-28 21:14:26 +01:00
Starbeamrainbowlabs 5fe84ada79
Update installation instructions for git
we should recommend that everyone checks out the latest release, even when installing via git.
2023-06-27 23:16:23 +01:00
Starbeamrainbowlabs f7530da608
initial pos marker wall for +x only
it's not hooked up yet.
2023-06-27 21:45:48 +01:00
Starbeamrainbowlabs 8cc2c735b1
Reference: I searched for wireframe, but didn't get the command I wanted 2023-06-27 20:57:04 +01:00
Starbeamrainbowlabs 61e04952e0
move pos marker textures. will this help #90? 2023-06-27 20:16:04 +01:00
Starbeamrainbowlabs 141ea2f0a7
For compatibility, ensure that we also clear the legacy worldedit region too 2023-06-27 20:00:07 +01:00
Starbeamrainbowlabs bfecc2da80
Merge branch 'main' of github.com:sbrl/Minetest-WorldEditAdditions 2023-06-27 19:40:12 +01:00
Starbeamrainbowlabs 53bbe14c63
update cloud wand to use new wea_c.pos interface 2023-06-27 19:39:57 +01:00
VorTechnix 8d9f51de35 handler patch
I should have done this in a branch lol
2023-05-28 08:45:39 -07:00
VorTechnix 67baee7465 fixed missing underscore 2023-05-28 08:37:57 -07:00
VorTechnix 8de2892907 added setting_handler 2023-05-24 16:02:51 -07:00
VorTechnix 16afb9eddc Create setting_handler.lua 2023-05-24 14:44:38 -07:00
Starbeamrainbowlabs 1c163186b6
//count: improve formatting of output 2023-05-24 22:20:52 +01:00
Starbeamrainbowlabs daad494c7e
reference //for: add command example from @VorTechnix 2023-05-24 22:09:51 +01:00
Starbeamrainbowlabs b2556934b1
reference: fix incorrect example 2023-05-24 22:01:33 +01:00
Starbeamrainbowlabs 7cb1160e65
//multi: fix luacheck error 2023-05-24 22:00:16 +01:00
VorTechnix b88cec64d4 Fix bad logic in parts check 2023-05-24 13:03:41 -07:00
Starbeamrainbowlabs 8652ad6335
website: add midding mobile meta tag 2023-02-25 02:21:08 +00:00
Starbeamrainbowlabs ebbaed88d8
Update 11ty to 2.0 o/ 2023-02-22 00:46:55 +00:00
Starbeamrainbowlabs 558fc1c04b
//revolve: try :round() instead of :floor()
not sure if ti helps or not tho
2023-02-12 03:32:10 +00:00
Starbeamrainbowlabs 1d53233621
typo 2023-02-12 02:19:53 +00:00
Starbeamrainbowlabs 66aab7ba64
Changelog: add //revolve 2023-02-12 02:18:15 +00:00
Starbeamrainbowlabs fcde8e581c
cloud wand: right clicking now resets all WEA multipoints 2023-02-12 02:18:04 +00:00
Starbeamrainbowlabs cfef411bbd
//revolve: write initial docs 2023-02-12 02:08:57 +00:00
Starbeamrainbowlabs cf8406b80f
//revolve: don't rotate air nodes
this is important because when rotating multiple times it can easily overwrite parts of the structure with pointless air nodes where it shouldn't do
2023-02-12 02:08:44 +00:00
Starbeamrainbowlabs e942e4fb2f
Finish initial implementation of //revolve
it's not quite done yet - got docs to go
2023-02-12 01:40:29 +00:00
Starbeamrainbowlabs d1b9d1c1c1
vector3.round_dp(): todo 2023-01-21 03:27:02 +00:00
Starbeamrainbowlabs 392708b190
initial wea.revolve() implementation
....but it's not tested or hooked up yet.
Next up: a chat command definition so we can test it.
2023-01-21 03:24:44 +00:00
Starbeamrainbowlabs 87812679d9
table_reduce: typo 2023-01-21 02:34:47 +00:00
Starbeamrainbowlabs 2ecc8cb2d7
add implementation of array.reduce() from JS 2023-01-21 02:32:09 +00:00
Starbeamrainbowlabs 66227153d0
add wea_c.range(min, max, step) 2023-01-21 01:32:17 +00:00
Starbeamrainbowlabs 42fb6571da
Vector3.rotate_3d(): write tests 2023-01-20 23:43:20 +00:00
Starbeamrainbowlabs 9c66288827
Vector3: add rotate3d.
Thanks to GitHub Copilot for the implementation, it just needed
improving around the edges to make it work perfectly.
For the record, copilot generated it in JS, and then
I manually ported it to Lua.
If the Copilot code looks sufficiently similar to your own source,
get in touch and I will give you full credit.
2023-01-20 23:43:07 +00:00
Starbeamrainbowlabs cbd2ae7df8
copilot rotate: reapply origin offset 2023-01-20 23:41:31 +00:00
Starbeamrainbowlabs 3e123ddc56
comment 2023-01-19 23:30:43 +00:00
Starbeamrainbowlabs 8372a12f48
initial WIP 3d point rotation algorithm
Thanks to GitHub Copilot for the implementation!
Just need to fully check it actually works, and then we can port it to Lua and Vector3.
2023-01-17 02:13:15 +00:00
Starbeamrainbowlabs 53609ac83e
vector3: .volume() is already implemented
remove todo comment
2023-01-17 00:08:13 +00:00
Starbeamrainbowlabs 2e275e3993
docs: initial pass at a dark theme
some of the colours still suck though
2023-01-11 03:26:49 +00:00
Starbeamrainbowlabs cfc1fe3639
huh, weird. evidently we need all the checks ever
ref #88
2023-01-11 02:32:01 +00:00
Starbeamrainbowlabs 97bb896829
fixup, ref #88 2023-01-11 02:25:41 +00:00
Starbeamrainbowlabs 58dd3ea875
Bugfix new marker system: properly check that the lua entity is a thing
Missing ()
Might fix #88, but needs testing.
2023-01-11 02:18:06 +00:00
Starbeamrainbowlabs 554bc86b3d
reference: tweak //spline 2022-10-23 02:26:05 +01:00
Starbeamrainbowlabs 902d03ca0b
Update changelog 2022-10-23 00:54:29 +01:00
Starbeamrainbowlabs 410841562a
img2brush: allow customising the channel to pull from 2022-09-26 03:27:58 +01:00
Starbeamrainbowlabs dea51cb9a3
typos 2022-09-25 23:02:23 +01:00
Starbeamrainbowlabs 9f2bfb33c7
reference: add //spline 2022-09-25 23:02:18 +01:00
Starbeamrainbowlabs b493c0073a
//spline: add sample image 2022-09-25 22:57:49 +01:00
Starbeamrainbowlabs bc0276875d
//spline: update params description 2022-09-25 22:55:50 +01:00
Starbeamrainbowlabs c319be5840
fix //spline :D 2022-09-25 17:07:37 +01:00
Starbeamrainbowlabs fe30fd5c51
add comment 2022-09-25 16:16:03 +01:00
Starbeamrainbowlabs 2748f4cdfa
//spline: plot chaikin curve 2022-09-25 15:30:16 +01:00
Starbeamrainbowlabs 9a4b4beb76
EventEmitter: add debug printing (disabled by default) 2022-09-25 15:03:16 +01:00
Starbeamrainbowlabs 9806828760
core pos: fix worldedit compat 2022-09-25 15:02:48 +01:00
Starbeamrainbowlabs 888e4b0f78
saferegion: fix missing return 2022-09-25 14:39:57 +01:00
Starbeamrainbowlabs 5d9dee9523
pos: fix warning 2022-09-25 02:03:44 +01:00
Starbeamrainbowlabs 268e123221
run_command require_pos: also check WEA pos subsystem 2022-09-25 02:02:23 +01:00
Starbeamrainbowlabs 363acde496
core pos: make function names actually make sense 2022-09-25 01:59:59 +01:00
Starbeamrainbowlabs 7a14e8a590
comment all the debug prints 2022-09-25 01:57:41 +01:00
Starbeamrainbowlabs f998110303
core pos: Add (complicated) compat w/worldedit 2022-09-25 01:43:30 +01:00
Starbeamrainbowlabs 285572e16b
saferegion: allow nodes_needed to return string 2022-09-25 01:19:36 +01:00
Starbeamrainbowlabs 258a9c1cde
implement initial //spline, but it isn't finished yet 2022-09-25 01:18:40 +01:00
Starbeamrainbowlabs a768378dfd
core: add transparent WorldEdit compatibility to the position subsystem 2022-09-25 01:07:48 +01:00
Starbeamrainbowlabs c2d19105ed
get_pos_all → get_all 2022-09-24 23:50:45 +01:00
Starbeamrainbowlabs 3583de4731
wea_c.pos: add get_bounds
....though tbh, I think this should go elsewhere.
2022-09-24 23:48:36 +01:00
Starbeamrainbowlabs dfb24e679b
table_apply: write tests 2022-09-24 18:47:13 +01:00
Starbeamrainbowlabs da9f578e86
table_contains: write tests 2022-09-24 18:42:54 +01:00
Starbeamrainbowlabs 8f03c6473b
test makeset 2022-09-24 13:45:50 +01:00
Starbeamrainbowlabs bdaedf0e7a
fixup 2022-09-24 13:42:00 +01:00
Starbeamrainbowlabs 38a72468d9
utils: rename folder tables → table to match API 2022-09-24 13:41:44 +01:00
Starbeamrainbowlabs bc5dc6b2b4
write tests for parse.map 2022-09-24 03:15:44 +01:00
Starbeamrainbowlabs c9fd68fac3
fixup 2022-09-24 02:54:36 +01:00
Starbeamrainbowlabs 84226a9909
write tests for parse.chance+seed 2022-09-24 02:51:56 +01:00
Starbeamrainbowlabs 2473c1ce41
Implement Vector3.volume () 2022-09-24 02:33:10 +01:00
Starbeamrainbowlabs 6357d590d9
Merge branch 'main' of github.com:sbrl/Minetest-WorldEditAdditions 2022-09-20 20:03:42 +01:00
Starbeamrainbowlabs 440cdcc504
Fix luacheck
The problem was that we moved bit.lua from worldeditadditions to worldeditadditions_core, but failed to update .luacheckrc
2022-09-20 20:03:36 +01:00
VorTechnix 98a74c63dc fixed colour offset bug and refactored hex values 2022-09-20 08:59:49 -07:00
Starbeamrainbowlabs 7f2be74580
position markers: colourise numbers 2022-09-20 03:21:55 +01:00
Starbeamrainbowlabs 3fa6dbefcf
Update background of positional marker entities 2022-09-20 02:31:04 +01:00
Starbeamrainbowlabs 1473074d4a
Reference: add multi-point selection wand 2022-09-20 02:17:28 +01:00
Starbeamrainbowlabs fd1e3fb20f
fix crash on punching new position marker 2022-09-20 02:17:11 +01:00
Starbeamrainbowlabs f7bd17131a
Update changelog 2022-09-20 01:20:40 +01:00
Starbeamrainbowlabs ea6a7ced2b
update README 2022-09-20 01:06:16 +01:00
Starbeamrainbowlabs 7423bee714
pos: add set_pos1 and set_pos2 convenience functions 2022-09-19 23:40:42 +01:00
Starbeamrainbowlabs e2e235ce6d
pos_marker_manage: listen on clear event 2022-09-19 23:35:49 +01:00
Starbeamrainbowlabs 9910bfad44
pos_marker_manage: listen on the set() event 2022-09-19 23:33:38 +01:00
Starbeamrainbowlabs 47b1c44b38
Upgrade position system, add initial position markers 2022-09-19 23:18:49 +01:00
Starbeamrainbowlabs d9877b8c6c
more crash fixes 2022-09-19 19:42:22 +01:00
Starbeamrainbowlabs 6c8ce90593
Fix crashes in wireframe commands 2022-09-19 18:59:45 +01:00
Starbeamrainbowlabs 44e6ba8e3c
Upgrade more old vector stuff in the corners 2022-09-19 18:54:53 +01:00
Starbeamrainbowlabs c3ae96548e
//floodfill: fix crash 2022-09-19 18:41:27 +01:00
Starbeamrainbowlabs d03e333e35
fixup 2022-09-19 18:33:19 +01:00
Starbeamrainbowlabs c82c83d008
spiral: comment debug 2022-09-19 18:33:10 +01:00
Starbeamrainbowlabs 073d621629
test geometry commands 2022-09-19 18:30:43 +01:00
Starbeamrainbowlabs 4be7bf33d0
//ellipsoid: fix crash 2022-09-19 18:10:06 +01:00
Starbeamrainbowlabs 9dc8165464
fixup 2022-09-19 17:34:53 +01:00
Starbeamrainbowlabs 5ec877f2b7
strip remaining worldeditadditions.vector.tostring calls 2022-09-19 17:33:02 +01:00
Starbeamrainbowlabs 8ec118eed7
remove debug logging 2022-09-19 17:29:12 +01:00
Starbeamrainbowlabs 1024b19629
fix startup crashes; crashes in cloudwand 2022-09-19 17:27:59 +01:00
Starbeamrainbowlabs 7a688969b2
fix tests 2022-09-19 01:31:47 +01:00
Starbeamrainbowlabs 1ae36d3898
Update tests to wea_c 2022-09-19 01:18:48 +01:00
Starbeamrainbowlabs 2af1226b49
port everything else
phew!
2022-09-19 01:16:22 +01:00
Starbeamrainbowlabs 41e3ebc7dd
Upgrade all main commands 2022-09-19 00:18:03 +01:00
Starbeamrainbowlabs a3acf3b16e
Update a bunch of APi methods 2022-09-18 22:58:33 +01:00
Starbeamrainbowlabs 21c5b9d483
Upgrade the last of the commands o/ 2022-09-18 22:46:20 +01:00
Starbeamrainbowlabs 6102a1adf5
Upgrade meta commands 2022-09-18 22:37:26 +01:00
Starbeamrainbowlabs 4a56d45c4b
Upgrade all selection commands 2022-09-18 22:20:04 +01:00
Starbeamrainbowlabs c3e8df3a9e
next batch of upgraded commands 2022-09-18 21:39:48 +01:00
Starbeamrainbowlabs 459e15b5c2
finish upgrading top-level commands 2022-09-18 21:30:28 +01:00
Starbeamrainbowlabs 128dc8f103
Update changelog 2022-09-18 21:05:43 +01:00
Starbeamrainbowlabs 0641a9f55c
Merge branch 'utils-move' of github.com:sbrl/Minetest-WorldEditAdditions into utils-move 2022-09-18 21:05:16 +01:00
Starbeamrainbowlabs 927f2f90f8
//hollow: upgrade; fix nodes_needed 2022-09-18 21:05:13 +01:00
Starbeamrainbowlabs 2f4c333ca0
//layers: upgrade 2022-09-18 21:05:03 +01:00
VorTechnix e2947c4ae2 Create settingtypes.txt 2022-09-18 13:00:36 -07:00
Starbeamrainbowlabs 8d6db6d3f5
upgrade 7 more commands 2022-09-18 20:58:28 +01:00
Starbeamrainbowlabs adfc6d6499
Merge branch 'main' into utils-move 2022-09-18 20:57:49 +01:00
Starbeamrainbowlabs e167fb1536
start working on converting everything to the new utils location
after we've done this, we'll rename utils → lib
2022-09-18 17:59:57 +01:00
Starbeamrainbowlabs 6f3118036d
Update utils 2022-09-18 17:32:13 +01:00
Starbeamrainbowlabs 2625ed1a53
Add positional textures 2022-09-18 16:54:33 +01:00
Starbeamrainbowlabs 58a7629ea1
Initial move of utils wea → wea_c
Here we go...!
2022-09-18 16:45:08 +01:00
Starbeamrainbowlabs 2b88fa867e
fix more warnings 2022-09-18 16:33:37 +01:00
Starbeamrainbowlabs 4a6cb2551c
math.pow → ^ 2022-09-18 16:30:27 +01:00
Starbeamrainbowlabs 52d24a63f3
Update changelog 2022-09-18 16:27:34 +01:00
Starbeamrainbowlabs 0983e09f50
multiwand: fix crash on left clicking background 2022-09-18 16:21:36 +01:00
Starbeamrainbowlabs cf0be6c1fb
EventEmitter: document 2022-09-18 16:19:52 +01:00
Starbeamrainbowlabs 17d92870b3
Add EventEmitter support to wea_c.pos 2022-09-18 16:06:23 +01:00
Starbeamrainbowlabs 817387d7f2
Port EventEmitter from Node.js 2022-09-18 15:57:23 +01:00
Starbeamrainbowlabs fa62864e16
implement multi-point wand 2022-09-18 15:30:53 +01:00
Starbeamrainbowlabs 9932852053
core: add position manager system
it doesn't save them to disk, but that would not be too difficult to add
2022-09-18 03:25:49 +01:00
Starbeamrainbowlabs fd42d96702
create initial texture for a multi-select wand 2022-09-18 02:25:18 +01:00
Starbeamrainbowlabs 08d40c8780
fix warnings 2022-09-17 23:42:46 +01:00
Starbeamrainbowlabs 763ae3db8d
Implement 2D bresenham line drawing for #35
We need it to be 3D though.
We essentially just ported f51f153459/src/index.js to Lua, as https://medium.com/geekculture/bresenhams-line-drawing-algorithm-2e0e953901b3 was WRONG as it didn't handle all edge cases and this one is much more optimised.
2022-09-17 23:27:57 +01:00
Starbeamrainbowlabs 382194321b
fixup 2022-08-06 15:17:16 +01:00
Starbeamrainbowlabs e6a48c8799
fix CI 2022-08-06 15:15:36 +01:00
Starbeamrainbowlabs d3900e2ad9
Update dependencies
also add missing debug dependency
Ref CI job output
2022-08-06 15:03:33 +01:00
Starbeamrainbowlabs 63abd1f539
build.sh: add export NODE_ENV=production 2022-07-06 02:33:37 +01:00
Starbeamrainbowlabs 0e7b292bb1
docs: serve GitHub avatars locally 2022-07-06 01:41:27 +01:00
Starbeamrainbowlabs 8eec6a32f7
Add CSS minification 2022-07-06 00:28:55 +01:00
Starbeamrainbowlabs bd88f93296
Update dependencies 2022-07-05 20:58:19 +01:00
Starbeamrainbowlabs c465d6efb0
Commands that modify the terrain now ignore liquids 2022-06-11 21:56:26 +01:00
Starbeamrainbowlabs 2d989acee5
reference: typo 2022-06-11 18:54:04 +01:00
Starbeamrainbowlabs 6e0779a4e5
//sculpt: Fix undefined `default` brush 2022-06-11 18:53:54 +01:00
Starbeamrainbowlabs 77c634dd7d
reference: fix subheadings disappearing 2022-06-11 16:58:25 +01:00
Starbeamrainbowlabs fc4f64d25a
Merge branch 'main' of github.com:sbrl/Minetest-WorldEditAdditions into main 2022-06-05 17:13:49 +01:00
Starbeamrainbowlabs e294d96efe
//dome+: ensure domes include pos1 2022-06-05 17:10:41 +01:00
VorTechnix dc73e0e1e9 sum param clarification 2022-05-30 08:38:33 -07:00
Starbeamrainbowlabs be0612e6be
Merge pull request #80 from sbrl/VorTechnix
Implement new axis keyword parser system
2022-05-30 16:00:01 +01:00
VorTechnix 74ca84fcee Create axes_parser.test.lua 2022-05-29 17:49:01 -07:00
VorTechnix 53600789d8 added compass directions, fixed tmp.sign bug 2022-05-29 16:23:59 -07:00
VorTechnix 6e3252b471 Merge branch 'main' into VorTechnix 2022-05-24 18:47:41 -07:00
Starbeamrainbowlabs 5ac98cfa22
tests.sh: use $OSTYPE to decide how to call luarocks
this is ridiculous
2022-05-25 02:14:17 +01:00
Starbeamrainbowlabs b94c38bb99
tests.sh: add logging to test github actions 2022-05-25 02:07:16 +01:00
VorTechnix 98e9888897 Merge branch 'main' into VorTechnix 2022-05-24 17:35:33 -07:00
Starbeamrainbowlabs 50b1df57c4
tests.sh: more windows weirdness 2022-05-25 01:33:07 +01:00
VorTechnix d79c187a9d Merge branch 'main' into VorTechnix 2022-05-24 16:47:38 -07:00
Starbeamrainbowlabs cb75776164
tests.sh: fix eval luarocks path on Windows
Annoyingly luarocks generates batch commands on Windows, even when being 
called from Git Bash :-/
2022-05-25 00:45:37 +01:00
VorTechnix 021fdac284 variable refactor 2022-05-23 18:49:24 -07:00
Starbeamrainbowlabs 64ff61a4d2
Fix override aliases 2022-05-24 02:24:43 +01:00
VorTechnix 6ed65074b8 unexposed number parser 2022-05-23 18:04:34 -07:00
VorTechnix a8655373a2 fixed typo 2022-05-23 17:11:26 -07:00
VorTechnix 3196a590f5 changed: functions returned
(and unexposed key_instance class)
2022-05-23 17:08:42 -07:00
VorTechnix 1cef968731 Key Instance type checking 2022-05-23 17:06:23 -07:00
Starbeamrainbowlabs af7d39110b
//spiral2: fix params description 2022-05-24 01:05:09 +01:00
Starbeamrainbowlabs 9bfb428c3f
add override aliases behind a setting 2022-05-24 00:11:22 +01:00
VorTechnix e17b2cce4e small correction 2022-05-23 15:02:59 -07:00
VorTechnix 23140467d2 new parser connected 2022-05-23 14:58:45 -07:00
VorTechnix 2cddccdca4 working (tested) parser implementation 2022-05-23 14:58:27 -07:00
VorTechnix 8789b39d1d Merge branch 'main' into VorTechnix 2022-05-21 07:04:09 -07:00
VorTechnix a0982c70f0 check_dir update (unification) 2022-05-20 19:29:01 -07:00
VorTechnix a6b4d047b8 axes_parser implemented (not added to init) 2022-05-20 19:27:47 -07:00
Starbeamrainbowlabs 1750d62d3c
core: add register_alias command
it is backwards-compatible with worldedit.register_command
2022-05-19 22:50:53 +01:00
Starbeamrainbowlabs c2c0fa5d8d
core: if worldedit is installed also register commands there
This ensures that e.g. //cubeapply continues to work as expected
2022-05-19 22:13:09 +01:00
Starbeamrainbowlabs 8de49ac0af
register commands with worldeditadditions, not worldedit 2022-05-19 22:10:09 +01:00
Starbeamrainbowlabs 3bcca82b43
//maze, //maze3d: registere with our new WEA core rather than WorldEdit 2022-05-19 02:43:19 +01:00
Starbeamrainbowlabs c53fb32d2b
core: fix register_command and run_command 2022-05-19 02:40:05 +01:00
Starbeamrainbowlabs 95c0e96da9
core: fix luacheck errors 2022-05-19 02:32:17 +01:00
Starbeamrainbowlabs b816133716
core: implement fetch_command_def
This rovides an abstraction to fetch a worldedit command's definition, 
regardless of where it was registered.

We would normally expect all commands to be registered in 
wea_c.registered_commands, but before we only do a one-off pass to 
import commands from worldedit should a new mod we aren't aware of 
register a command with worldedit and get loaded after us, we won't 
detect it - hencee  the need for this function.
2022-05-19 02:31:01 +01:00
Starbeamrainbowlabs c60b5c5bad
core: fix bugs, enable! 2022-05-19 01:45:36 +01:00
Starbeamrainbowlabs 4306035ef2
core: implement safe_region 2022-05-18 02:31:08 +01:00
Starbeamrainbowlabs 8f6c3e020f
fixup 2022-05-17 01:04:51 +01:00
Starbeamrainbowlabs d21f7ca5fb
core: minor fixes 2022-05-17 01:04:38 +01:00
Starbeamrainbowlabs 1fda9725c7
Implement run_command, but it's not quite finished yet
We still have yet to implement safe_region. Doing so will be 
non-trivial, as we'll need to override //y and //n, but then  also keep 
track of commands defined in worldedit and call the right version of //y 
and //n.
2022-05-17 01:03:58 +01:00
Starbeamrainbowlabs 4ab386788d
fixup 2022-05-16 23:41:09 +01:00
Starbeamrainbowlabs 9bdd7d2a25
core: add run_command shim, but it's not finished yet 2022-05-16 23:40:17 +01:00
Starbeamrainbowlabs fa9b511e33
core: finish initial register_command 2022-05-16 23:40:03 +01:00
Starbeamrainbowlabs 19c8d0e7b9
core: make options.nodes_needed optional 2022-05-16 23:33:22 +01:00
Starbeamrainbowlabs f984f5d7b7
Begin rewriting worldeditadditions_core
We should be able to make things a lot cleaner and more robust.
2022-05-16 23:32:40 +01:00
Starbeamrainbowlabs d3119ee54a
Delete more copied code 2022-05-16 22:37:10 +01:00
Starbeamrainbowlabs 10f350c967
Delete copied code
Given licence incompatibilities, we can't really copy code from 
WorldEdit
2022-05-16 21:21:15 +01:00
Starbeamrainbowlabs 9d3a4ce263
refactor aliases into a separate file 2022-05-16 20:33:04 +01:00
Starbeamrainbowlabs 60c8f30109
Update changelog 2022-05-16 20:16:48 +01:00
Starbeamrainbowlabs 98909f0fae
//metaball: bugfix
It works!
2022-05-16 20:14:31 +01:00
Starbeamrainbowlabs 722e62bae0
Finish initial //metaballs command implementation, but it's untested 2022-05-16 01:21:09 +01:00
Starbeamrainbowlabs 3311d80a2a
Rework metaballs backend
We need a way of defining metaballs per-player. Our solution to this is 
a custom in-memory per-player storage system. The reason for this is 
because just a position (e.g. that provided by pos1/pos2) is not enough 
- we need a radius as well.
2022-05-16 01:01:01 +01:00
Starbeamrainbowlabs 0d7922d747
typo 2022-05-16 00:29:50 +01:00
VorTechnix bcfe39cd21 Merge branch 'main' into VorTechnix 2022-05-15 13:09:57 -07:00
Starbeamrainbowlabs f34617a3d3
Add backend functionality for metaballs
Implementing a frontend command sounds like a headache to me
2022-05-15 17:42:19 +01:00
Starbeamrainbowlabs 03fb033b70
//dome+: add option to make the resulting dome hollow inside 2022-05-15 15:38:50 +01:00
Starbeamrainbowlabs 04e971e12d
Add //dome+
Improvements oveer //dome:

 - Allow customising the direction it points in
 - Allow multiple pointing directions at once to give the effect of 
creating multiple domes on top of each other in a single command (it's 
actually implemented as an implicit union, and doesn't actually call 
wea.dome more than once).
2022-05-15 15:27:43 +01:00
Starbeamrainbowlabs a99cef7bf9
Merge branch 'main' of github.com:sbrl/Minetest-WorldEditAdditions into main 2022-05-15 13:53:08 +01:00
Starbeamrainbowlabs 6d075be525
docs: fix warning 2022-05-15 13:52:59 +01:00
Starbeamrainbowlabs dbc056139a
Merge pull request #74 from sbrl/dependabot/npm_and_yarn/dot-docs/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6 in /.docs
2022-05-01 17:10:55 +01:00
Starbeamrainbowlabs 8eb1faf1b9
Update changelog
fixes #75
2022-05-01 17:10:24 +01:00
Starbeamrainbowlabs 8b385690c0
modpack.conf: add name field, since mesecons has one 2022-05-01 17:09:00 +01:00
Starbeamrainbowlabs a4237dcca5
depends.txt → mod.conf 2022-05-01 17:07:30 +01:00
Starbeamrainbowlabs 7622d85efa
docs: update dependencies 2022-05-01 17:01:03 +01:00
dependabot[bot] 1c80bbc031
Bump minimist from 1.2.5 to 1.2.6 in /.docs
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-30 02:25:54 +00:00
Starbeamrainbowlabs d77799a871
Merge pull request #73 from sbrl/dependabot/npm_and_yarn/dot-docs/follow-redirects-1.14.8
Bump follow-redirects from 1.14.1 to 1.14.8 in /.docs
2022-02-17 23:53:09 +00:00
dependabot[bot] 2ed3042bc8
Bump follow-redirects from 1.14.1 to 1.14.8 in /.docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.1 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.1...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 08:13:49 +00:00
VorTechnix 9995ea2fb9 Merge branch 'main' into VorTechnix 2022-01-03 06:56:58 -08:00
Starbeamrainbowlabs c443459282
wireframe/corner_set: fix luacheck warnings 2022-01-03 13:30:22 +00:00
Starbeamrainbowlabs 3d12345972
//smake: fix luacheck warnings 2022-01-03 13:28:43 +00:00
Starbeamrainbowlabs 4c7bb6a980
//sfactor: fix luacheck warnings; fix crash 2022-01-03 13:26:51 +00:00
Starbeamrainbowlabs 67b4495aad
README: add link to edit full reference 2022-01-03 12:54:33 +00:00
Starbeamrainbowlabs ee465070c9
fixup 2022-01-03 12:53:41 +00:00
Starbeamrainbowlabs 58933c6435
README: Update command list 2022-01-03 12:49:59 +00:00
VorTechnix 104fe97be3 Update selection.lua 2021-11-16 11:34:58 -08:00
349 changed files with 8601 additions and 6451 deletions

View File

@ -7,8 +7,15 @@ const path = require("path");
const debug = require("debug");
const htmlentities = require("html-entities");
const phin = require("phin");
const CleanCSS = require("clean-css");
const { minify: minify_html } = require("html-minifier-terser");
const HTMLPicture = require("./lib/HTMLPicture.js");
const FileFetcher = require("./lib/FileFetcher.js");
const file_fetcher = new FileFetcher();
const is_production = typeof process.env.NODE_ENV === "string" && process.env.NODE_ENV === "production";
var nextid = 0;
@ -47,23 +54,19 @@ async function shortcode_image_urlpass(src) {
return `/img/${filename}`;
}
async function shortcode_gallerybox(content, src, idthis, idprev, idnext) {
return `<figure class="gallerybox-item" id="${idthis}">
async function shortcode_gallerybox(content, src, id_this, id_prev, id_next) {
return `<figure class="gallerybox-item" id="${id_this}">
<!-- ${await shortcode_image(src, "", "gallerybox-thumb", "300w")} -->
${await shortcode_image(src, "", "", "1920w")}
<figcaption>${content}</figcaption>
<a class="gallerybox-prev" href="#${idprev}"></a>
<a class="gallerybox-next" href="#${idnext}"></a>
<a class="gallerybox-prev" href="#${id_prev}"></a>
<a class="gallerybox-next" href="#${id_next}"></a>
</figure>`;
}
async function fetch(url) {
const pkg_obj = JSON.parse(await fs.promises.readFile(
path.join(__dirname, "package.json"), "utf8"
));
return (await phin({
url,
headers: {
@ -74,9 +77,56 @@ async function fetch(url) {
})).body;
}
function fetch_file(url) {
return file_fetcher.fetch_file(url);
}
function do_minify_css(source, output_path) {
if(!output_path.endsWith(".css") || !is_production) return source;
const result = new CleanCSS({
level: 2
}).minify(source).styles.trim();
console.log(`MINIFY ${output_path}`, source.length, ``, result.length, `(${((1 - (result.length / source.length)) * 100).toFixed(2)}% reduction)`);
return result;
}
async function do_minify_html(source, output_path) {
if(!output_path.endsWith(".html") || !is_production) return source;
const result = await minify_html(source, {
collapseBooleanAttributes: true,
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
continueOnParseError: true,
decodeEntities: true,
keepClosingSlash: true,
minifyCSS: true,
quoteCharacter: `"`,
removeComments: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true,
useShortDoctype: true
});
console.log(`MINIFY ${output_path}`, source.length, ``, result.length, `(${((1 - (result.length / source.length)) * 100).toFixed(2)}% reduction)`);
return result;
}
if(is_production) console.log("Production environment detected, minifying content");
module.exports = function(eleventyConfig) {
eleventyConfig.addTransform("cssmin", do_minify_css);
eleventyConfig.addTransform("htmlmin", do_minify_html);
eleventyConfig.addPassthroughCopy("img2brush/img2brush.js");
eleventyConfig.addAsyncShortcode("fetch", fetch);
eleventyConfig.addFilter("fetch_file", fetch_file);
// eleventyConfig.addPassthroughCopy("images");
// eleventyConfig.addPassthroughCopy("css");

View File

@ -17,7 +17,7 @@ let { sections, categories } = parse_sections(fs.readFileSync(
"utf-8"
))
sections = sections.slice(1).sort((a, b) => a.title.replace(/^\/+/g, "").localeCompare(
sections = sections.sort((a, b) => a.title.replace(/^\/+/g, "").localeCompare(
b.title.replace(/^\/+/g, "")));

View File

@ -2,6 +2,7 @@
<html>
<head>
<meta charset='utf-8' />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{ title }} • WorldEditAdditions</title>
<link rel="stylesheet" href="/theme.css" />
@ -45,11 +46,11 @@
{{ content | safe }}
<footer class="shadow-top">
<p>WorldEditAdditions built with ❤️ by these awesome people:</p>
<p>WorldEditAdditions is built with ❤️ by these awesome people:</p>
<ul class="contributor-list">
{% for contributor in contributors %}
<li><a href="{{ contributor.profile_url }}">
<img class="icon large" src="{{ contributor.avatar_url }}" alt="{{ contributor.name }}" />
<img class="icon large" src="{{ contributor.avatar_url | fetch_file }}" alt="{{ contributor.name }}" />
<span>{{ contributor.name }}</span>
</a></li>
{% endfor %}

View File

@ -1,13 +1,13 @@
---
permalink: theme.css
---
{% include "css/patterns.css" %}
{% include "css/theme.css" %}
{% include "css/gallerybox.css" %}
{% include "css/smallscreens.css" %}
{% include "css/prism-custom.css" %}
{# {% fetch "https://unpkg.com/prismjs/themes/prism-okaidia.css" %} #}
{# {% fetch "https://raw.githubusercontent.com/PrismJS/prism-themes/master/themes/prism-shades-of-purple.css" %} #}
{# {% fetch "https://raw.githubusercontent.com/PrismJS/prism-themes/master/themes/prism-material-light.css" %} #}

View File

@ -10,7 +10,17 @@ be (slightly) less hacky once :target-within lands in browsers.
Exported to codepen: https://codepen.io/sbrl/details/YzZJYxg
*/
:root {
--gallerybox-bg: hsla(0, 0%, 95%, 0.75);
}
@media (prefers-color-scheme: dark) {
:root {
--gallerybox-bg: hsla(0, 0%, 30%, 0.75);
}
}
@media (orientation: landscape) {
.gallerybox-gallery {
max-width: 95vw;
@ -58,7 +68,7 @@ Exported to codepen: https://codepen.io/sbrl/details/YzZJYxg
}
.gallerybox-item > figcaption {
background: hsla(0, 0%, 95%, 0.75);
background: var(--gallerybox-bg);
position: absolute;
bottom: 0.25em; left: 0; right: 0;
padding: 0.75em 1em;

View File

@ -32,6 +32,27 @@
--shadow-dark: hsla(0, 0%, 25%, 0.5);
--highlight: hsl(353, 100%, 36%);
--bg-image: url('{% image_urlpass "images/clouds.png" %}');
}
@media (prefers-color-scheme: dark) {
:root {
--bg-main: #020B18;
--bg-bright: hsl(108, 46%, 34%);
--bg-alt: hsl(228, 68%, 68%);
--bg-transcluscent: hsla(224, 20%, 16%, 0.85);
--bg-transcluscent-alt: hsla(226, 79%, 70%, 0.8);
--text-main: hsl(227, 80%, 95%);
--bg-image: url('{% image_urlpass "images/clouds-night.png" %}');
}
a { color: #7c7cff; }
a:active { color: #ee0000; }
a:not(.nav):not(.bigbutton):visited { color: hsl(296, 84%, 75%); }
}
/* rem is relative to the html element, and em is relative to the current element. */
@ -42,7 +63,7 @@ body
margin: 0;
font-family: sans-serif; /* Serif is awful :( */
background: url('{% image_urlpass "images/clouds.png" %}') center / cover fixed,
background: var(--bg-image) center / cover fixed,
var(--bg-main); /* Don't forget to update the @page one too for paged media */
color: var(--text-main);
}
@ -67,6 +88,7 @@ h1, h2, h3, h4, h5, h6 {
text-align: center;
word-wrap: break-word;
}
.linked-section-heading {
display: flex;
}
@ -90,6 +112,18 @@ h1, h2, h3, h4, h5, h6 {
line-height: 1.5;
align-self: flex-start;
}
h3 {
margin-top: 2em;
padding-bottom: 0.2em;
border-bottom: 0.1em solid var(--cat-colour);
}
h3, h3 > code {
font-size: 1.1em;
text-align: left;
}
h3 > code {
background: transparent;
}
nav {
background: var(--bg-bright);
@ -156,7 +190,6 @@ a { font-weight: bold; }
a:not(.nav):hover { color: hsl(214, 67%, 50%); }
a:not(.nav):active, a:focus { color: hsl(214, 87%, 60%); } */
a:not(.nav):not(.bigbutton):visited { color: hsl(240, 77%, 60%); }
pre {
page-break-inside: avoid;
break-inside: avoid;

View File

@ -1,7 +1,7 @@
{%
# Lists of axes
In various commands such as `//copy+`, `//move+`, and others lists of axes are used. These are all underpinned by a single grammar and a single parser (located in `worldeditadditions/utils/parse/axes.lua`). While the parser itself requires pre-split tokens (see `split_shell` for that), the grammar which it parses is documnted here.
In various commands such as `//copy+`, `//move+`, and others lists of axes are used. These are all underpinned by a single grammar and a single parser (located in `worldeditadditions/utils/parse/axes.lua`). While the parser itself requires pre-split tokens (see `split_shell` for that), the grammar which it parses is documented here.
Examples:

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -13,6 +13,23 @@ window.addEventListener("load", () => {
})
});
function get_source_channel_offset() {
const select = document.querySelector("#img2brush-channel");
console.info(`get_source_channel_offset: channel is ${select.value}`)
switch(select.value) {
case "alpha":
return 3;
case "red":
return 0;
case "green":
return 1;
case "blue":
return 2;
default:
throw new Error(`Error : Unknown channel name ${select.value}.`);
}
}
function select_output() {
let output = document.querySelector("#brushimg-tsv");
@ -26,7 +43,6 @@ function select_output() {
selection.addRange(range);
}
function handle_drag_enter(event) {
event.target.classList.add("dropzone-active");
}
@ -80,12 +96,15 @@ function handle_new_image(image) {
}
function pixels2tsv(pixels) {
const offset = get_source_channel_offset();
console.info(`pixels2tsv: offset is ${offset}`);
let result = "";
for(let y = 0; y < pixels.height; y++) {
let row = [];
for(let x = 0; x < pixels.width; x++) {
// No need to rescale here - this is done automagically by WorldEditAdditions.
row.push(pixels.data[((y*pixels.width + x) * 4) + 3] / 255);
// r/b/g/alpha
row.push(pixels.data[((y*pixels.width + x) * 4) + offset] / 255);
}
result += row.join(`\t`) + `\n`;
}

View File

@ -6,7 +6,17 @@ title: Image to brush converter
<section class="panel-generic">
<h1>Image to sculpting brush converter</h1>
<p>Convert any image to a sculpting brush here! The <strong>alpha (opacity) channel</strong> is used to determine the weight of the brush - <strong>all colour is ignored</strong>.</p>
<p>Convert any image to a sculpting brush here!</p>
<p>
<strong>Use this channel to convert:</strong>
<select name="img2brush-channel" id="img2brush-channel">
<option value="alpha" selected>Alpha (opacity)</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
</p>
<p>Only the selected channel is used to determine the weight of the brush - <strong>all other channels are ignored</strong>! Change the channel option <strong>before</strong> you drag + drop the image onto this page.</p>
</section>
<section id="dropzone" class="bigbox panel-generic">

View File

@ -100,7 +100,10 @@ date: 2000-01-01
<pre><code>cd path/to/worldmods;
git clone https://github.com/Uberi/Minetest-WorldEdit.git worldedit;
git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions;</code></pre>
git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions;
cd worldeditadditions;
git checkout "$(git describe --tags --abbrev=0)";</code></pre>
<p><a class="bigbutton" href="https://github.com/sbrl/Minetest-WorldEditAdditions">Source code on GitHub</a></p>
</div>

65
.docs/lib/FileFetcher.js Normal file
View File

@ -0,0 +1,65 @@
"use strict";
const path = require("path");
const fs = require("fs");
const os = require("os");
const phin = require("phin");
const a = require("./Ansi.js");
const pretty_ms = require("pretty-ms");
class FileFetcher {
#cache = [];
#pkg_obj = null;
constructor() {
}
fetch_file(url) {
let target_client = path.join(`/img`, path.basename(url));
if(this.#cache.includes(url)) return target_client;
this.#cache.push(url);
this.download_file(url); // Returns a promise! We fire-and-forget it though 'cause this function *must* be synchronous :-/
return target_client;
}
async download_file(url) {
const time_start = new Date();
if(this.#pkg_obj === null) {
this.#pkg_obj = JSON.parse(await fs.promises.readFile(
path.join(path.dirname(__dirname), "package.json"), "utf8"
));
}
let target_download = path.join(`_site/img`, path.basename(url));
const response = await phin({
url,
headers: {
"user-agent": `WorldEditAdditionsStaticBuilder/${this.#pkg_obj.version} (Node.js/${process.version}; ${os.platform()} ${os.arch()}) eleventy/${this.#pkg_obj.dependencies["@11ty/eleventy"].replace(/\^/, "")}`
},
followRedirects: true,
parse: 'none' // Returns a Buffer
// If we stream and pipe to a file, the build never ends :-/
});
await fs.promises.writeFile(target_download, response.body);
console.log([
`${a.fred}${a.hicol}FETCH_FILE${a.reset}`,
`${a.fyellow}${pretty_ms(new Date() - time_start)}${a.reset}`,
`${a.fgreen}${url}${a.reset}`
].join("\t"));
}
}
module.exports = FileFetcher;

View File

@ -32,7 +32,6 @@ function calculate_size(width, height, size_spec) {
// Main task list - we make sure it completes before exiting.
var queue = null;
var pMemoize = null;
async function make_queue() {
// 1: Setup task queue
@ -75,7 +74,7 @@ async function srcset(source_image, target_dir, urlpath, format = "__AUTO__", si
quality,
strip
});
console.log(`IMAGE\t${a.fcyan}${queue.size}/${queue.pending} tasks${a.reset}\t${a.fyellow}${pretty_ms(new Date() - start)}${a.reset}\t${a.fgreen}${target_current}${a.reset}`);
console.log(`${a.fmagenta}${a.hicol}IMAGE${a.reset}\t${a.fcyan}${queue.size}/${queue.pending} tasks${a.reset}\t${a.fyellow}${pretty_ms(new Date() - start)}${a.reset}\t${a.fgreen}${target_current}${a.reset}`);
});
// const size_target = await imagickal.dimensions(target_current);

View File

@ -39,6 +39,8 @@ function make_section(acc, cat_current, cats) {
.replace(/\s+/g, "-")
.replace(/-.*$/, ""),
content: markdown.render(acc.slice(1).join("\n"))
.replace(/<h4(\/?)>/g, "<h3$1>")
.replace(/<h5(\/?)>/g, "<h4$1>")
};
}
@ -57,23 +59,26 @@ module.exports = function parse_sections(source) {
for(let line of lines) {
if(line.startsWith(`#`)) {
let heading_level = line.match(/^#+/)[0].length;
// 1: Deal with the previous section
if(acc.length > 0) {
let heading_level_prev = acc[0].match(/^#+/)[0].length;
if(heading_level_prev === 3 && acc.length > 0) {
if(heading_level_prev === 3 && acc.length > 0 && heading_level <= 3) {
result.push(make_section(acc, cat_current, cats));
}
}
// 2: Deal with the new line
let heading_level = line.match(/^#+/)[0].length
if(heading_level === 2)
cat_current = extract_title(line);
acc = [ line ];
if(heading_level > 3)
acc.push(line)
else
acc = [ line ];
}
else
acc.push(line);

6164
.docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "worldeditadditions",
"version": "1.0.0",
"version": "1.14.5",
"description": "Documentation website for WorldEditAdditions",
"main": "index.js",
"private": true,
@ -19,19 +19,19 @@
"url": "https://github.com/sbrl/Minetest-WorldEditAdditions/issues"
},
"homepage": "https://github.com/sbrl/Minetest-WorldEditAdditions#readme",
"devDependencies": {
"@11ty/eleventy": "^0.12.1",
"chroma-js": "^2.1.2",
"columnify": "^1.5.4",
"debug": "^4.3.2",
"imagickal": "^5.0.1",
"markdown-it-prism": "^2.2.1",
"p-memoize": "^6.0.1",
"p-queue": "^7.1.0",
"phin": "^3.6.0",
"pretty-ms": "^7.0.1"
},
"dependencies": {
"html-entities": "^2.3.2"
"@11ty/eleventy": "^2.0.1",
"chroma-js": "^2.4.2",
"clean-css": "^5.3.2",
"columnify": "^1.6.0",
"debug": "^4.3.4",
"html-entities": "^2.4.0",
"html-minifier-terser": "^7.0.0-beta.0",
"imagickal": "^5.0.1",
"markdown-it-prism": "^2.3.0",
"p-memoize": "^7.1.1",
"p-queue": "^7.3.4",
"phin": "^3.7.0",
"pretty-ms": "^7.0.1"
}
}

26
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,26 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
What's the bug? Be clear and concise in our explanation. Don't forget to include any context, error messages, logs, and screenshots required to understand the issue if applicable.
**Reproduction steps:**
Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Enter this command to '....'
4. See error
**System information (please complete the following information):**
- **Operating system and version:** [e.g. iOS]
- **Minetest version:** [e.g. 5.8.0]
- **WorldEdit version:**
- **WorldEditAdditions version:**
Please add any other additional specific system information here too if you think it would help.

View File

@ -0,0 +1,22 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
## Problem
A clear and concise description of what the problem you want to solve is. e.g. I'm always frustrated when [...]
## Solution
Describe clearly the solution you'd like.
## Alternatives
A clear and concise description of any alternative solutions or features you've considered, and how they relate to your proposed feature.
## Additional context
Add any other context or screenshots about the feature request here.
Don't forget to remove replace descriptions, but keep the headers.

View File

@ -3,7 +3,7 @@ codes = true
exclude_files = {
".luarocks/*",
"worldeditadditions/utils/bit.lua"
"worldeditadditions_core/utils/bit.lua"
}
files["worldeditadditions_core/register/check.lua"] = { read_globals = { "table" } }
@ -33,6 +33,7 @@ read_globals = {
"describe",
"bonemeal",
"dofile",
"PerlinNoise"
"PerlinNoise",
"Settings"
}
std = "max"

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.abs", function()
it("should work with a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.add", function()
it("should add 2 positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.area", function()
it("should work with a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.ceil", function()
it("should ceil a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.clamp", function()
it("should work by not changing values if it's already clamped", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.clone", function()
it("should return a new Vector3 instance", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.__concat", function()
it("should work when concatenating a Vector3 + Vector3", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.divide", function()
it("should divide 2 positive vectors", function()
@ -18,10 +18,10 @@ describe("Vector3.divide", function()
)
end)
it("should work with scalar a", function()
local a = 2
local b = Vector3.new(12, 14, 16)
local a = 100
local b = Vector3.new(4, 5, 2)
assert.are.same(
Vector3.new(6, 7, 8),
Vector3.new(25, 20, 50),
a / b
)
end)

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.dot", function()
it("should work with a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.equals", function()
it("should return true when identical", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.expand_region", function()
it("should work with positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.floor", function()
it("should floor a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.is_contained", function()
it("should return true when inside", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
-- To find these numbers, in Javascript:
-- function t(x) { return Math.sqrt((x*x)*3); }

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.length_squared", function()
it("should work with a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.limit_to", function()
it("should limit_to a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.max", function()
it("should work with positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.max_component", function()
it("should work with a positive vector x", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.mean", function()
it("should work with a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.min", function()
it("should work with positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.min_component", function()
it("should work with a positive vector x", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
-- To find these numbers, in Javascript:
-- function t(x) { return Math.sqrt((x*x)*3); }

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.multiply", function()
it("should multiply 2 positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.add", function()
it("should create a new Vector3", function()

View File

@ -0,0 +1,132 @@
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.rotate3d", function()
it("should work with an origin of (0,0,0) X axis", function()
local origin = Vector3.new(0, 0, 0)
local point = Vector3.new(0, 1, 0)
local rotate = Vector3.new(
math.rad(180), -- x axis = yz plane
math.rad(0), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
assert.are.same(
Vector3.new(0, -1, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with an origin of (0,0,0) Y axis", function()
local origin = Vector3.new(0, 0, 0)
local point = Vector3.new(1, 0, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(180), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
assert.are.same(
Vector3.new(-1, 0, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with an origin of (0,0,0) Z axis", function()
local origin = Vector3.new(0, 0, 0)
local point = Vector3.new(1, 0, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(0), -- y axis = xz plane
math.rad(180)-- z axis = xy plane
)
assert.are.same(
Vector3.new(-1, 0, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with a non-zero origin X axis", function()
local origin = Vector3.new(1, 1, 1)
local point = Vector3.new(0, 2, 0)
local rotate = Vector3.new(
math.rad(180), -- x axis = yz plane
math.rad(0), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
assert.are.same(
Vector3.new(0, 0, 2),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with a non-zero origin Y axis", function()
local origin = Vector3.new(1, 1, 1)
local point = Vector3.new(0, 2, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(180), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
assert.are.same(
Vector3.new(2, 2, 2),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with a non-zero origin Z axis", function()
local origin = Vector3.new(1, 1, 1)
local point = Vector3.new(0, 2, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(0), -- y axis = xz plane
math.rad(180)-- z axis = xy plane
)
assert.are.same(
Vector3.new(2, 0, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with a non-zero origin Z axis -90 degrees", function()
local origin = Vector3.new(1, 1, 1)
local point = Vector3.new(0, 2, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(0), -- y axis = xz plane
math.rad(-90)-- z axis = xy plane
)
assert.are.same(
Vector3.new(2, 2, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should work with multiple axes X Y", function()
local origin = Vector3.new(0, 0, 0)
local point = Vector3.new(0, 2, 0)
local rotate = Vector3.new(
math.rad(90), -- x axis = yz plane
math.rad(90), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
assert.are.same(
Vector3.new(2, 0, 0),
Vector3.rotate3d(origin, point, rotate):round_dp(4)
)
end)
it("should return new Vector3 instances", function()
local origin = Vector3.new(0, 0, 0)
local point = Vector3.new(1, 0, 0)
local rotate = Vector3.new(
math.rad(0), -- x axis = yz plane
math.rad(180), -- y axis = xz plane
math.rad(0)-- z axis = xy plane
)
local result = Vector3.rotate3d(origin, point, rotate):round(4)
assert.are.same(Vector3.new(-1, 0, 0), result)
result.y = 999
assert.are.same(Vector3.new(0, 0, 0), origin)
assert.are.same(Vector3.new(1, 0, 0), point)
assert.are.same(Vector3.new(-1, 999, 0), result)
end)
end)

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.round", function()
it("should round a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.set_to", function()
it("should set_to a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.snap_to", function()
it("should snap_to a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.sort", function()
it("should work with positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.sqrt", function()
it("should sqrt a positive vector", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.subtract", function()
it("should subtract 2 positive vectors", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.__tostring", function()
it("should stringify a Vector3", function()

View File

@ -1,4 +1,4 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
-- To find these numbers, in Javascript:
-- function t(x) { return Math.sqrt((x*x)*3); }

View File

@ -0,0 +1,44 @@
local Vector3 = require("worldeditadditions_core.utils.vector3")
describe("Vector3.volume", function()
it("should work", function()
local a = Vector3.new(4, 4, 4)
local b = Vector3.new(8, 8, 8)
assert.are.equal(
64,
Vector3.volume(a, b)
)
end)
it("should work the other way around", function()
local a = Vector3.new(4, 4, 4)
local b = Vector3.new(8, 8, 8)
assert.are.equal(
64,
Vector3.volume(b, a)
)
end)
it("should work with negative values", function()
local a = Vector3.new(-4, -4, -4)
local b = Vector3.new(-8, -8, -8)
assert.are.equal(
64,
Vector3.volume(a, b)
)
end)
it("should work with different values", function()
local a = Vector3.new(5, 6, 7)
local b = Vector3.new(10, 10, 10)
assert.are.equal(
60,
Vector3.volume(a, b)
)
end)
it("should work with mixed values", function()
local a = Vector3.new(10, 5, 8)
local b = Vector3.new(5, 10, 2)
assert.are.equal(
150,
Vector3.volume(a, b)
)
end)
end)

View File

@ -0,0 +1,158 @@
local Vector3 = require("worldeditadditions_core.utils.vector3")
local facing_dirs = dofile("./.tests/parse/axes/include_facing_dirs.lua")
local parse = require("worldeditadditions_core.utils.parse.axes_parser")
local parse_axes = parse.keytable
describe("parse_axes", function()
-- Basic tests
it("should work on single horizontal axes", function()
local minv, maxv = parse_axes({
"x", "3",
"-z", "10",
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, -10), minv)
assert.are.same(Vector3.new(3, 0, 0), maxv)
end)
it("should handle axis clumps and orphan (universal) values", function()
local minv, maxv = parse_axes({
"xz", "-3",
"10",
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(-3, 0, -3), minv)
assert.are.same(Vector3.new(10, 10, 10), maxv)
end)
it("should work on directions and their abriviations", function()
local minv, maxv = parse_axes({
"l", "3", -- +z
"-r", "-3", -- +z
"b", "-10", -- -x
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, -3), minv)
assert.are.same(Vector3.new(10, 0, 3), maxv)
end)
it("should work with compass directions and their abriviations", function()
local minv, maxv = parse_axes({
"n", "3", -- +z
"south", "3", -- -z
"-west", "10", -- +x
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, -3), minv)
assert.are.same(Vector3.new(10, 0, 3), maxv)
end)
it("should work with ?", function()
local minv, maxv = parse_axes({
"?", "3", -- -z
}, facing_dirs.z_neg)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, -3), minv)
assert.are.same(Vector3.new(0, 0, 0), maxv)
end)
it("should work with complex relative / absolute combinations", function()
local minv, maxv = parse_axes({
"f", "3", -- +x
"left", "10", -- +z
"y", "77",
"x", "30",
"back", "99",
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(-99, 0, 0), minv)
assert.are.same(Vector3.new(33, 77, 10), maxv)
end)
it("should work with complex relative / absolute combinations with negative facing_dirs", function()
local minv, maxv = parse_axes({
"f", "3", -- -z
"l", "10", -- +x
"y", "77",
"x", "30",
"b", "99", -- +z
}, facing_dirs.z_neg)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, -3), minv)
assert.are.same(Vector3.new(40, 77, 99), maxv)
end)
it("should return 2 0,0,0 vectors if no input", function()
local minv, maxv = parse_axes({
-- No input
}, facing_dirs.z_neg)
assert.is.truthy(minv)
assert.are.same(Vector3.new(0, 0, 0), minv)
assert.are.same(Vector3.new(0, 0, 0), maxv)
end)
-- Options tests
it("should mirror the max values of the two vectors if mirroring keyword is present", function()
local minv, maxv = parse_axes({
"x", "3",
"f", "-5", -- +x
"z", "-10",
"mir",
}, facing_dirs.x_pos)
assert.is.truthy(minv)
assert.are.same(Vector3.new(-5, 0, -10), minv)
assert.are.same(Vector3.new(5, 0, 10), maxv)
end)
it("should return a single vector if 'sum' input is truthy", function()
local minv, maxv = parse_axes({
"x", "3",
"z", "-10",
}, facing_dirs.x_pos,"sum")
assert.is.truthy(minv)
assert.are.same(Vector3.new(3, 0, -10), minv)
assert.are.same(nil, maxv)
end)
it("should dissable mirroring if 'sum' input is truthy", function()
local minv, maxv = parse_axes({
"x", "3",
"f", "-5", -- +x
"z", "-10",
"sym",
}, facing_dirs.x_pos,"sum")
assert.is.truthy(minv)
assert.are.same(Vector3.new(-2, 0, -10), minv)
assert.are.same(nil, maxv)
end)
-- Error tests
it("should return error if bad axis/dir", function()
local minv, maxv = parse_axes({
"f", "3", -- +x
"lift", "10", -- Invalid axis
"y", "77",
"x", "30",
"back", "99", -- -x
}, facing_dirs.x_pos)
assert.are.same(false, minv)
assert.are.same("string", type(maxv))
end)
it("should return error if bad value", function()
local minv, maxv = parse_axes({
"f", "3", -- +x
"left", "10", -- +z
"y", "!Q", -- Invalid value
"x", "30",
"back", "99",
}, facing_dirs.x_pos)
assert.are.same(false, minv)
assert.are.same("string", type(maxv))
end)
end)

View File

@ -1,6 +1,6 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
local axes = require("worldeditadditions.utils.parse.axes")
local axes = require("worldeditadditions_core.utils.parse.axes")
local parse_abs_axis_name = axes.parse_abs_axis_name

View File

@ -1,8 +1,8 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
local facing_dirs = dofile("./.tests/parse/axes/include_facing_dirs.lua")
local axes = require("worldeditadditions.utils.parse.axes")
local axes = require("worldeditadditions_core.utils.parse.axes")
local parse_axes = axes.parse_axes
--[[ Original idea for how this function was supposed to work from @VorTechnix

View File

@ -1,8 +1,8 @@
local Vector3 = require("worldeditadditions.utils.vector3")
local Vector3 = require("worldeditadditions_core.utils.vector3")
local facing_dirs = dofile("./.tests/parse/axes/include_facing_dirs.lua")
local axes = require("worldeditadditions.utils.parse.axes")
local axes = require("worldeditadditions_core.utils.parse.axes")
local parse_relative_axis_name = axes.parse_relative_axis_name

View File

@ -0,0 +1,36 @@
local parse_chance = require("worldeditadditions_core.utils.parse.chance")
describe("parse.chance", function()
it("should work in 1-in-n mode by default", function()
local source = "50%"
assert.are.equal(
2,
parse_chance(source)
)
end)
it("should work with a different value in 1-in-n mode", function()
local source = "25%"
assert.are.equal(
4,
parse_chance(source)
)
end)
it("should work in weight mode", function()
local source = "50%"
assert.are.equal(
2,
parse_chance(source, "weight")
)
end)
it("should work in weight mode with different number", function()
local source = "90%"
assert.are.equal(
10,
parse_chance(source, "weight")
)
end)
end)

122
.tests/parse/map.test.lua Normal file
View File

@ -0,0 +1,122 @@
_G.worldeditadditions_core = {
split = require("worldeditadditions_core.utils.strings.split"),
table = {
contains = require("worldeditadditions_core.utils.table.table_contains")
}
}
local parse_map = require("worldeditadditions_core.utils.parse.map")
describe("parse.map", function()
it("should work with a single param", function()
local success, result = parse_map("apples yay")
assert.are.equal(true, success)
assert.are.same(
{ apples = "yay" },
result
)
end)
it("should work with 2 params", function()
local success, result = parse_map("apples yay oranges yummy")
assert.are.equal(true, success)
assert.are.same(
{ apples = "yay", oranges = "yummy" },
result
)
end)
it("should work with an int value", function()
local success, result = parse_map("apples 2")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2 },
result
)
end)
it("should work with a float value", function()
local success, result = parse_map("apples 2.71")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2.71 },
result
)
end)
it("should work with 2 int values", function()
local success, result = parse_map("apples 2 banana 23")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = 23 },
result
)
end)
it("should work with mixed values", function()
local success, result = parse_map("apples 2 banana yummy")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = "yummy" },
result
)
end)
it("should work with a value that starts as a number and ends as a string", function()
local success, result = parse_map("apples 20t banana yummy")
assert.are.equal(true, success)
assert.are.same(
{ apples = "20t", banana = "yummy" },
result
)
end)
it("should work with a value that starts as a string and ends as a number", function()
local success, result = parse_map("apples t20 banana yummy")
assert.are.equal(true, success)
assert.are.same(
{ apples = "t20", banana = "yummy" },
result
)
end)
it("should work with multiple spaces", function()
local success, result = parse_map("apples 2 banana \t yummy")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = "yummy" },
result
)
end)
it("should ignore a hanging item at the end", function()
local success, result = parse_map("apples 2 banana")
assert.are.equal(true, success)
assert.are.same(
{ apples = 2 },
result
)
end)
it("should work with hanging items declared as keywords at the end", function()
local success, result = parse_map("apples 2 banana", { "banana" })
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = true },
result
)
end)
it("should work with hanging items declared as keywords in the middle", function()
local success, result = parse_map("apples 2 banana pear paris", { "banana" })
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = true, pear = "paris" },
result
)
end)
it("should work with some but not other hanging items declared as keywords", function()
local success, result = parse_map("apples 2 banana pear paris arrange", { "banana" })
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = true, pear = "paris" },
result
)
end)
it("should work with hanging items declared as keywords at the beginning", function()
local success, result = parse_map("banana apples 2 pear paris", { "banana" })
assert.are.equal(true, success)
assert.are.same(
{ apples = 2, banana = true, pear = "paris" },
result
)
end)
end)

View File

@ -0,0 +1,24 @@
local parse_seed = require("worldeditadditions_core.utils.parse.seed")
describe("parse.seed", function()
it("should work", function()
local source = "a test string"
local result = parse_seed(source)
assert.are.equal(
"number",
type(result)
)
end)
it("should work with a long string", function()
local source = "If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction. If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction."
local result = parse_seed(source)
assert.are.equal(
"number",
type(result)
)
end)
end)

View File

@ -0,0 +1,32 @@
local makeset = require("worldeditadditions_core.utils.table.makeset")
describe("table.makeset", function()
it("should work with a single item", function()
local result = makeset({ "apples" })
assert.are.same(
{ apples = true },
result
)
end)
it("should work with 2 items", function()
local result = makeset({ "apples", "orange" })
assert.are.same(
{ apples = true, orange = true },
result
)
end)
it("should work with duplicate items", function()
local result = makeset({ "apples", "apples" })
assert.are.same(
{ apples = true },
result
)
end)
it("should work with duplicate items and non-duplicate items", function()
local result = makeset({ "apples", "oranges", "apples" })
assert.are.same(
{ apples = true, oranges = true },
result
)
end)
end)

View File

@ -0,0 +1,48 @@
local apply = require("worldeditadditions_core.utils.table.table_apply")
describe("table.makeset", function()
it("should work", function()
local source = { apples = 4 }
local target = { oranges = 3 }
apply(source, target)
assert.are.same(
{ apples = 4, oranges = 3 },
target
)
end)
it("should overwrite values in target", function()
local source = { apples = 4 }
local target = { apples = 3 }
apply(source, target)
assert.are.same(
{ apples = 4 },
target
)
end)
it("should work with strings", function()
local source = { apples = "4" }
local target = { oranges = "3" }
apply(source, target)
assert.are.same(
{ apples = "4", oranges = "3" },
target
)
end)
it("should overwrite values in target with strings", function()
local source = { apples = "4" }
local target = { apples = "3" }
apply(source, target)
assert.are.same(
{ apples = "4" },
target
)
end)
end)

View File

@ -0,0 +1,40 @@
local contains = require("worldeditadditions_core.utils.table.table_contains")
describe("table.makeset", function()
it("should work with a string", function()
assert.are.same(
true,
contains({ "apples" }, "apples")
)
end)
it("should work with a number", function()
assert.are.same(
true,
contains({ 4 }, 4)
)
end)
it("should return false if a number doesn't exist", function()
assert.are.same(
false,
contains({ 5 }, 4)
)
end)
it("should work with a string and multiple items in the table", function()
assert.are.same(
true,
contains({ "yay", "apples", "cat" }, "apples")
)
end)
it("should return false if it doesn't exist", function()
assert.are.same(
false,
contains({ "yay" }, "orange")
)
end)
it("should return false if it doesn't exist wiith multiple items", function()
assert.are.same(
false,
contains({ "yay", "apples", "cat" }, "orange")
)
end)
end)

View File

@ -0,0 +1,178 @@
local split_shell = require("worldeditadditions_core.utils.strings.split_shell")
describe("split_shell", function()
it("should handle a single case x3", function()
assert.are.same(
{ "yay", "yay", "yay" },
split_shell("yay yay yay")
)
end)
it("should handle double quotes simple", function()
assert.are.same(
{ "dirt", "snow block" },
split_shell("dirt \"snow block\"")
)
end)
it("should handle an escaped double quote inside double quotes", function()
assert.are.same(
{ "yay", "yay\" yay", "yay" },
split_shell("yay \"yay\\\" yay\" yay")
)
end)
it("should handle single quotes", function()
assert.are.same(
{ "yay", "yay", "yay" },
split_shell("yay 'yay' yay")
)
end)
it("should handle single quotes again", function()
assert.are.same(
{ "yay", "inside quotes", "another" },
split_shell("yay 'inside quotes' another")
)
end)
it("should handle single quotes inside double quotes", function()
assert.are.same(
{ "yay", "yay 'inside quotes' yay", "yay" },
split_shell("yay \"yay 'inside quotes' yay\" yay")
)
end)
it("should handle single quotes and an escaped double quote inside double quotes", function()
assert.are.same(
{ "yay", "yay 'inside quotes' yay\"", "yay" },
split_shell("yay \"yay 'inside quotes' yay\\\"\" yay")
)
end)
it("should handle a complex case", function()
assert.are.same(
{ "y\"ay", "yay 'in\"side quotes' yay", "y\"ay" },
split_shell("y\"ay \"yay 'in\\\"side quotes' yay\" y\\\"ay")
)
end)
it("should handle a subtly different complex case", function()
assert.are.same(
{ "y\"ay", "yay", "in\"side quotes", "yay", "y\"ay" },
split_shell("y\"ay yay 'in\\\"side quotes' yay y\\\"ay")
)
end)
it("should handle redundant double quotes", function()
assert.are.same(
{ "cake" },
split_shell("\"cake\"")
)
end)
it("should handle redundant double quotes multi", function()
assert.are.same(
{ "cake", "cake", "cake" },
split_shell("\"cake\" \"cake\" \"cake\"")
)
end)
it("should handle redundant single quotes", function()
assert.are.same(
{ "cake" },
split_shell("'cake'")
)
end)
it("should handle redundant single quotes multi", function()
assert.are.same(
{ "cake", "cake", "cake" },
split_shell("'cake' 'cake' 'cake'")
)
end)
it("should handle redundant double and single quotes", function()
assert.are.same(
{ "cake", "cake", "cake" },
split_shell("'cake' \"cake\" 'cake'")
)
end)
it("should handle redundant double and single quotes opposite", function()
assert.are.same(
{ "cake", "cake", "cake" },
split_shell("\"cake\" 'cake' \"cake\"")
)
end)
it("should handle a random backslash single quotes", function()
assert.are.same(
{ "cake", "ca\\ke" },
split_shell("\"cake\" 'ca\\ke'")
)
end)
it("should handle a random backslash double quotes", function()
assert.are.same(
{ "cake", "ca\\ke" },
split_shell("\"cake\" \"ca\\ke\"")
)
end)
it("should handle a backslash after double quotes", function()
assert.are.same(
{ "\\cake", "cake" },
split_shell("\"\\cake\" \"cake\"")
)
end)
it("should handle a double backslash before double quotes", function()
assert.are.same(
{ "\\\"cake\"", "cake" },
split_shell("\\\\\"cake\" \"cake\"")
)
end)
it("should handle a single backslash before double quotes", function()
assert.are.same(
{ "\"cake\"", "cake" },
split_shell("\\\"cake\" \"cake\"")
)
end)
it("should handle a double backslash before single quotes", function()
assert.are.same(
{ "\\'cake'", "cake" },
split_shell("\\\\'cake' 'cake'")
)
end)
it("should handle a single backslash before single quotes", function()
assert.are.same(
{ "\"cake\"", "cake" },
split_shell("\\\"cake\" \"cake\"")
)
end)
it("should handle redundant double and single quotes again", function()
assert.are.same(
{ "cake", "cake", "cake", "is", "a", "li\\e" },
split_shell("\"cake\" 'cake' \"cake\" is a \"li\\e\"")
)
end)
-- Unclosed quotes are currently considered to last until the end of the string.
it("should handle an unclosed double quote", function()
assert.are.same(
{ "the", "cake is a lie" },
split_shell("the \"cake is a lie")
)
end)
it("should handle an unclosed single quote", function()
assert.are.same(
{ "the", "cake is a lie" },
split_shell("the 'cake is a lie")
)
end)
it("should handle an unclosed single quote at the end", function()
assert.are.same(
{ "the", "cake is a lie'" },
split_shell("the \"cake is a lie'")
)
end)
it("should handle an unclosed single and double quote", function()
assert.are.same(
{ "the", "cake is \"a lie" },
split_shell("the 'cake is \"a lie")
)
end)
end)

View File

@ -1,4 +1,4 @@
local polyfill = require("worldeditadditions.utils.strings.polyfill")
local polyfill = require("worldeditadditions_core.utils.strings.polyfill")
describe("str_ends", function()
it("should return true for a single character", function()

View File

@ -1,4 +1,4 @@
local polyfill = require("worldeditadditions.utils.strings.polyfill")
local polyfill = require("worldeditadditions_core.utils.strings.polyfill")
describe("str_padend", function()
it("should pad a string", function()

View File

@ -1,4 +1,4 @@
local polyfill = require("worldeditadditions.utils.strings.polyfill")
local polyfill = require("worldeditadditions_core.utils.strings.polyfill")
describe("str_padstart", function()
it("should pad a string", function()

View File

@ -1,4 +1,4 @@
local polyfill = require("worldeditadditions.utils.strings.polyfill")
local polyfill = require("worldeditadditions_core.utils.strings.polyfill")
describe("str_starts", function()
it("should return true for a single character", function()

View File

@ -1,4 +1,4 @@
local polyfill = require("worldeditadditions.utils.strings.polyfill")
local polyfill = require("worldeditadditions_core.utils.strings.polyfill")
describe("trim", function()
it("work for a string that's already trimmed", function()

12
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"Lua.diagnostics.disable": [
"trailing-space",
"undefined-global",
"lowercase-global",
"cast-local-type"
],
"cSpell.words": [
"ollow",
"weacmd"
]
}

View File

@ -3,6 +3,56 @@ It's about time I started a changelog! This will serve from now on as the main c
Note to self: See the bottom of this file for the release template text.
## v1.14.5: The multipoint update, hotfix 5 (1st August 2023)
- Fix a bug where creative players in survival couldn't punch out position markers
- Added `//listentities`, which lists all currently loaded `ObjectRef`s. This is intended for debugging mods - thanks to @Zughy in #103
## v1.14.4: The multipoint update, hotfix 4 (31st July 2023)
- When any segment of the marker wall is punched, unmark the entire wall
## v1.14.3: The multipoint update, hotfix 3 (18th July 2023)
- Fix regions not remembering their state and being unresettable
## v1.14.2: The multipoint update, hotfix 2 (15th July 2023)
- Fix crash in `//subdivide`, again due to the new position system
## v1.14.1: The multipoint update, hotfix 1 (12th July 2023)
- Fix issue #100, which caused a crash as `//pos1` and `//pos2` allowed non-integer positions to be set
## v1.14: The multipoint update (11th July 2023)
- Add `//dome+`, which allows you to change the direction the dome is pointing in, and also create multiple domes at once
- Add `//metaball`, which renders 2 or more [metaballs](https://en.wikipedia.org/wiki/Metaballs) in Minetest
- Significant backend refactoring to tidy things up
- Add new multi-point selection wand ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png) to select many points at once.
- Implement custom region boxing UI, which replaces the WorldEdit region box when using WorldEditAdditions wands.
- Is backwards compatible with regular WorldEdit wands and tools, as WorldEditAdditions keeps the new positioning system in sync with WorldEdit's.
- The new multipoint wand required this as a prerequisite
- Add [`//pos`](https://worldeditadditions.mooncarrot.space/Reference/#pos), for setting any numbered point (i.e. not just pos1 and pos2, but pos3 and beyond)
- Add [`//spline`](https://worldeditadditions.mooncarrot.space/Reference/#spline), for drawing curved lines with an arbitrary number of points **(uses the new multi-point wand)**
- Add [`//revolve`](https://worldeditadditions.mooncarrot.space/Reference/#revolve), which makes multiple evenly-spaced rotated copies of the defined region **(uses the new multi-point wand)**
- [`//copy+`](https://worldeditadditions.mooncarrot.space/Reference/#copy), [`//move+`](https://worldeditadditions.mooncarrot.space/Reference/#move):
- Added support for integrated `airapply` mode, which replaces nodes at the target only if they are air - append `airapply`/`aa` to the command to use
- Respect node rotation (i.e. param2) when copying/moving
- Override `//move` and `//copy` by default
### Bugfixes and changes
- Migrate from `depends.txt` to `mod.conf`
- Cloud wand: fix typo in item description.
- Commands that modify the terrain now ignore liquids
- `//sculpt`:
- Fix undefined `default` brush
- Change defaults to `circle`, `height=1`, and `brushsize=8`.
- Change argument ordering to put `height` after `brushsize` instead of the other way around
- `//hollow`: Fix safe region bug
- Make `//pos1`, `//1`, `//pos2`, `//2`, `//mark`, `//unmark`, and `//reset` aware of the new WEA positioning system
## v1.13: The transformational update (2nd January 2022)
- Add [`//sfactor`](https://worldeditadditions.mooncarrot.space/Reference/#sfactor) (_selection factor_) - Selection Tools by @VorTechnix are finished for now.
- Add [`//mface`](https://worldeditadditions.mooncarrot.space/Reference/#mface) (_measure facing_), [`//midpos`](https://worldeditadditions.mooncarrot.space/Reference/#midpos) (_measure middle position_), [`//msize`](https://worldeditadditions.mooncarrot.space/Reference/#msize) (_measure size_), [`//mtrig`](#mtrig) (_measure trigonometry_) - Measuring Tools implemented by @VorTechnix.
@ -19,10 +69,10 @@ Note to self: See the bottom of this file for the release template text.
- Add [`//sculpt`](https://worldeditadditions.mooncarrot.space/Reference/#sculpt) and [`//sculptlist`](https://worldeditadditions.mooncarrot.space/Reference/#sculptlist) for sculpting terrain using a number of custom brushes.
- Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues [code quality from now on will be significantly improved]
- Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting
- `//layers`: Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/))
- `//bonemeal`: Add optional node list constraint
- `//walls`: Add optional thickness argument
- `//sstack`: Add human-readable approx volumes of regions in the selection stack
- [`//layers`](https://worldeditadditions.mooncarrot.space/Reference/#layers): Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/))
- [`//bonemeal`](https://worldeditadditions.mooncarrot.space/Reference/#bonemeal): Add optional node list constraint
- [`//walls`](https://worldeditadditions.mooncarrot.space/Reference/#walls): Add optional thickness argument
- [`//sstack`](https://worldeditadditions.mooncarrot.space/Reference/#sstack): Add human-readable approx volumes of regions in the selection stack
### Bugfixes

View File

@ -37,7 +37,9 @@ When actually implementing stuff, here are a few guidelines that I recommend to
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ████ ██ ██ ██ ██ ███████
local wea = worldeditadditions
worldedit.register_command("{name}", {
local weac = worldeditadditions_core
local Vector3 = weac.Vector3
worldeditadditions_core.register_command("{name}", {
params = "<argument> <argument=default> <option1|option2|...> [<optional_argument> <optional_argument2> ...] | [<optional_argument> [<optional_argument2>]]",
description = "A **brief** description of what this command does",
privs = { worldedit = true },
@ -47,18 +49,18 @@ worldedit.register_command("{name}", {
return true, param1, param2
end,
nodes_needed = function(name) --Optional
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
return Vector3.volume(weac.pos.get1(name), weac.pos.get2(name))
end,
func = function(name, param1, param2)
-- Start a timer
local start_time = wea.get_ms_time()
local start_time = weac.get_ms_time()
-- Do stuff
-- Finish timer
local time_taken = wea.get_ms_time() - start_time
local time_taken = weac.get_ms_time() - start_time
minetest.log("This is a logged message!")
return true, "Completed command in " .. wea.format.human_time(time_taken)
return true, "Completed command in " .. weac.format.human_time(time_taken)
end
})
```

View File

@ -22,6 +22,74 @@ Other useful links:
██████ ███████ ██████ ██ ██ ███████ ██ ██ ██ ██
-->
### `//metaball add <radius> | remove <index> | render <replace_node> [<threshold=1>] | list | clear | volume`
Draws two or more [metaballs](https://en.wikipedia.org/wiki/Metaballs). Based on a subcommand system, since each metaball may have a different radius.
Calling `//metaball render <replace_node>` actually makes changes to the world - all others manipulate an internal player-local list of metaballs to be drawn.
#### `//metaball add <radius>`
Adds a new metaball to the (player-local) list of metaballs to be draw with the given radius. The position of the new metaball is taken from pos1.
```weacmd
//metaball add 5
//metaball add 10
//metaball add 65
```
#### `//metaball remove <index>`
Removes the metaball with the given index from the list. See also `//metaball list`.
```weacmd
//metaball remove 1
//metaball remove 2
//metaball remove 5
```
#### `//metaball render <replace_node> [<threshold=1>]`
Renders the current list of metaballs to the world using replace_node to draw with.
Threshold is a value that acts as an offset for large or small the metaballs should be. Defaults to 1, with larger values resulting in **smaller** metaballs and smaller values resulting in **larger** metaballs. It is not recommended to set threshold to a negative number.
Does not clear the list of metaballs after rendering - see `//metaball clear` for that.
```weacmd
//metaball render dirt
//metaball render glass
//metaball render stone
//metaball render stone 2
//metaball render cobble 0.5
```
#### `//metaball list`
Lists all the metaballs currently registered for the current player (all `//metaball` commands operate on the current player's metaball list only), and their indexes, positions, and sizes. Useful when using `//metaball remove <index>` to identify which metaball you want to remove.
Example output:
```
Index Position Radius
1 (-495, 37, 150) 7
2 (-506, 33, 142) 7
3 (-516, 35, 152) 10
```
```weacmd
//metaball list
```
#### `//metaball clear`
Clears the list of metaballs for the current player.
```weacmd
//metaball clear
```
#### `//metaball volume`
Calculate an estimated volume of the metaballs currently in the list.
```weacmd
//metaball volume
```
### `//ellipsoid <rx> <ry> <rz> <node_name> [h[ollow]]`
Creates a solid ellipsoid at position 1 with the radius `(rx, ry, rz)`.
@ -105,6 +173,8 @@ Generates a maze using replace_node as the walls and air as the paths. Uses [an
Requires the currently selected area to be at least 3x3 on the x and z axes respectively.
Mazes are generated from the bottom to the top of the defined region. In other words, the height of the walls of the maze is equal to the height of the defined region.
The optional `path_length` and `path_width` arguments require additional explanation. When generating a maze, a multi-headed random walk is performed. When the generator decides to move forwards from a point, it does so `path_length` nodes at a time. `path_length` defaults to `2`.
`path_width` is easier to explain. It defaults to `1`, and is basically the number of nodes wide the path generated is.
@ -126,7 +196,7 @@ The last example below shows how to set the path length and width:
### `//maze3d <replace_node> [<path_length> [<path_width> [<path_depth> [<seed>]]]]`
Same as `//maze`, but instead generates mazes in 3 dimensions instead of 2. Requires the currently selected area to be at least 3x3x3.
The optional `path_depth` parameter defaults to `1` and allows customisation of the height of the paths generated.
The optional `path_depth` parameter defaults to `1` and allows customisation of the height of the paths generated. In other words, it customises the ceiling height, or the distance from the floor to the ceiling of the paths generated.
To get a better look at the generated maze, try inverting it like so:
@ -172,6 +242,37 @@ Generates both square and circular spiral shapes with the given `<replace_node>`
```
### `//dome+ <radius> <replace_node> [<pointing_dir:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> ...] [h[ollow]]`
Creates a dome shape (i.e. a hemisphere; half a sphere) with a specified radius of the defined node, optionally specifying the direction it should be pointing in (defaults to the positive y direction).
For example, `//dome+ 5 stone y` creates a dome shape pointing upwards, but `//dome+ 5 stone -y` creates a dome shape pointing downwards.
Multiple pointing direction axes can be chained together to create multiple domes on top of each other. Multiple conflicting directions will cancel each other out.
If `h` or `hollow` is specified at the end, then the resulting dome shape is made hollow.
```
//dome+ 5 stone y
//dome+ 10 diamond -x
//dome+ 25 cactus y z
//dome+ 9 dirt x y z
```
### `//spline <replace_node> <width_start> [<width_end=width_start> [<steps=3>]]`
Draws a curved line, using all the currently defined points as control points. The starting and ending widths of the line can be controlled, and the width will be linearly interpolated.
**Note:** `//spline` uses the **new** WorldEditAdditions positions! Use the [multipoint wand](#multi-point-wand) to define the control points for the resulting line.
For those interested, WorldEditAdditions uses the [chaikin curve algorithm](https://starbeamrainbowlabs.com/blog/article.php?article=posts/196-Chaikin-Curve-Generator.html) with linear interpolation for the width to draw the curve.
```weacmd
//spline dirt 5 2
//spline glass 3
//spline bakedclay:violet 3
```
![An example of what //spline can do.](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/.docs/images/reference/spline.jpeg)
## Misc
<!--
@ -196,6 +297,8 @@ Floods all connected nodes of the same type starting at _pos1_ with `<replace_no
### `//wbox <replace_node>`
Sets the edges of the current selection to `<replace_node>`to create an outline of a rectangular prism. Useful for roughing in walls.
In other words, creates a wireframe of a box defined by the current selection.
```weacmd
//wbox silver_sandstone
//wbox dirt
@ -300,7 +403,7 @@ By adding 3 extra numbers for the x, y, and z axes respectively, we can control
So in the above example, we scale in the positive x and z directions, and the negative y direction.
### `//copy+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`
### `//copy+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [aa|airapply]`
Fully backwards-compatible with `//copy` from regular WorldEdit, but allows you to specify multiple axes at once in a single copy operation. Each successive axis in the list is specified in the form `<axis> <count>`, where:
- `<axis>` is the name of the axis to move the defined region along
@ -323,6 +426,8 @@ All of the following values are valid axes:
Additionally all the absolute axis names (`x`/`y`/`z`/`-x`/`-y`/`-z`) may also be specified multiple times under the same count - e.g. `xy-z 6`.
Finally, if the word `airapply` (or `aa` for short) is present at the end of the command invocation it enables the integrated airapply mode, which replaces target nodes only if they are air-like.
```
//copy+ x 6
//copy+ y 10 z 4
@ -331,12 +436,17 @@ Additionally all the absolute axis names (`x`/`y`/`z`/`-x`/`-y`/`-z`) may also b
//copy+ xz 50 front 22
//copy+ yx 25
//copy+ -xz-y 10
//copy+ y 45 aa
//copy+ -y 15 z 5 airapply
```
### `//move+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`
### `//move+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [aa|airapply]`
Identical to [`//copy+`](#copy), but instead moves the defined region instead of copying it.
Note that the integrated `airapply` (`aa` for short) also works as in [`//copy+`](#copy), but remember that if a given target node is not *not* air-like and the integrated `airapply` mode is enabled, the source node is still moved from the source, but destroyed because it is can't be set at the target.
```
//move+ x 6
//move+ y 10 z 4
@ -345,6 +455,8 @@ Identical to [`//copy+`](#copy), but instead moves the defined region instead of
//move+ xz 50 front 22
//move+ yx 25
//move+ -xz-y 10
//move+ back 20 aa
//move+ -z 45 y 3 airapply
```
@ -406,6 +518,18 @@ Here are all the above examples together:
```
### `//revolve <times> [<pivot_point_number=last_point>]`
Makes a given number of copies of the currently defined region (bounded by pos1 and pos2) at a given number of equally spaced points rotated around a given pivot/origin point.
For example, `//revolve 4` would make rotated copies of the currently defined region at intervals 0° (the source to copy), 90°, 180°, and 270° around the given pivot point.
`pivot_point_number` is the number of the defined position that should act as the pivot point, or origin for the revolve operation. It defaults to the last position defined. Note that it cannot be pos1 or pos2, as these are used to define the region that should be rotated. Use the [multi-point wand](#multi) to define a position with an index of 3 or more.
```weacmd
//revolve 4
//revolve 6 6
```
## Terrain
<!--
@ -507,7 +631,7 @@ Currently implemented algorithms:
Algorithm | Mode | Description
------------|-------|-------------------
`snowballs` | 2D | The default - based on [this blog post](https://jobtalle.com/simulating_hydraulic_erosion.html). Simulates snowballs rolling across the terrain, eroding & depositing material. Then runs a 3x3 gaussian kernel over the result (i.e. like the `//conv` / `//smoothadv` command).
`river` | 2D | Fills in potholes and lowers pillars using a cellular automata-like algorithm that analyses the height of neighouring columns.
`river` | 2D | Fills in potholes and lowers pillars using a cellular automata-like algorithm that analyses the height of neighbouring columns.
Usage examples:
@ -571,7 +695,7 @@ Applies 2D noise to the terrain in the defined region. Like `//erode`, this comm
Parameter | Type | Default Value | Description
------------|-----------|---------------|-----------------------
algorithm | `string` | perlinmt | The 2D noise algorithm to apply - see below.
apply | `string|integer` | 5 | How to apply the noise to the terrain - see below.
apply | `string¦integer` | 5 | How to apply the noise to the terrain - see below.
scalex | `float` | 1 | The scale of the noise on the x axis.
scaley | `float` | 1 | The scale of the noise on the y axis.
scalez | `float` | 1 | The scale of the noise on the z axis.
@ -593,7 +717,7 @@ The following algorithms are currently available:
Algorithm | Description
------------|--------------------------
`perlinmt` | **Default**.Perlin noise, backed by Minetest's inbuilt `PerlinNoise` class.
`perlinmt` | **Default**. Perlin noise, backed by Minetest's inbuilt `PerlinNoise` class.
`perlin` | Perlin noise, backed by a pure Lua perlin noise implementation. Functional, but currently contains artefacts I'm having difficulty tracking down.
`sin` | A sine wave created with `math.sin()`.
`white` | Random white noise.
@ -625,7 +749,7 @@ Lists all the available sculpting brushes for use with `//sculpt`. If the `previ
```
### `//sculpt [<brush_name=default> [<height=5> [<brush_size=10>]]]`
### `//sculpt [<brush_name=default> [<brush_size=8> [<height=1>]]]`
Applies a specified brush to the terrain at position 1 with a given height and a given size. Multiple brushes exist (see [`//sculptlist`](#sculptlist)) - and are represented as a 2D grid of values between 0 and 1, which are then scaled to the specified height. The terrain around position 1 is first converted to a 2D heightmap (as in [`//convolve`](#convolve) before the brush "heightmap" is applied to it.
Similar to [`//sphere`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#sphere-radius-node), [`//cubeapply 10 set`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#cubeapply-sizesizex-sizey-sizez-command-parameters), or [`//cylinder y 5 10 10 dirt`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#cylinder-xyz-length-radius1-radius2-node) (all from [WorldEdit](https://content.minetest.net/packages/sfan5/worldedit/)), but has a number of added advantages:
@ -641,9 +765,9 @@ The selection of available brushes is limited at the moment, but see below on ho
```
//sculpt
//sculpt default 10 25
//sculpt default 25 3
//sculpt ellipse
//sculpt circle 5 50
//sculpt circle 50 3
```
#### Create your own brushes
@ -812,7 +936,75 @@ Returns the absolute canonical name of a node, given an alias or partial node na
███████ ███████ ███████ ███████ ██████ ██ ██ ██████ ██ ████
-->
### `//unmark`
Hides the in-game UI that indicates where the current positions and region are located.
This hides both the WorldEditAdditions *and* the WorldEdit UI if displayed, but does **not** change or remove any points that are registered.
Should more than 2 points be defined, they are all hidden.
```weacmd
//unmark
```
### `//mark`
Shows the in-game UI that indicates where the current positions and region are located once more.
Should more than 2 points be defined, they are all shown once more.
Often used after calling [`//unmark`](#unmark)
```weacmd
//mark
```
### `//pos1`
Sets pos1 to the location of the calling player.
This is, as with all other WorldEditAdditions commands, seamlessly synchronised with WorldEdit, allowing you to use any combination of WorldEditAdditions and WorldEdit commands and tools without them desynchronising from one another.
**Aliases:** `//1`
```weacmd
//pos2
```
### `//pos2`
Sets pos1 to the location of the calling player.
This is, as with all other WorldEditAdditions commands, seamlessly synchronised with WorldEdit, allowing you to use any combination of WorldEditAdditions and WorldEdit commands and tools without them desynchronising from one another.
**Aliases:** `//2`
```weacmd
//pos2
```
### `//pos <index>`
Sets position with the given index `<index>` to the location of the calling player.
Should the index be less than or equal to 2, then as with all other WorldEditAdditions commands, seamlessly synchronised with WorldEdit, allowing you to use any combination of WorldEditAdditions and WorldEdit commands and tools without them desynchronising from one another.
Should the index be greater than 2, the position will only be registered in WorldEditAdditions, as WorldEdit does not support defining more than 2 points.
If no index is specified, an error is returned and nothing is done.
```weacmd
//pos 1
//pos 3
//pos 45
//pos 2
```
### `//reset`
Clears all positions defined and the defined region.
This also synchronises with WorldEdit, as all other WorldEditAdditions commands do.
```weacmd
//reset
```
### `//scol [<axis1> ] <length>`
@ -1151,11 +1343,23 @@ This is equivalent to executing the following 3 commands in sequence:
Here are some more examples:
```
//for meselamp brick snowblock bamboo:wood do { //multi //maze %% //sshift y 5 }
//for meselamp brick snowblock bamboo:wood do //multi //maze %% //sshift y 5
//for 5 10 15 do //torus %% 3 dirt xz
//for 1 2 3 4 5 do //multi //hollowcylinder y 1 5 meselamp //shift y %%
```
### `//listentities`
Lists all currently loaded ObjectRefs. Displays their IDs, Names (if possible), and possitions.
This command is intended for development and modding. You will not normally need to use this command using WorldEditAdditions.
`//listentities` takes no arguments.
```
//listentities
```
## Extras
<!--
@ -1198,10 +1402,12 @@ Prevents the execution of a command if it could potentially affect a large numbe
-->
### Far Wand
The far wand (`worldeditadditions:farwand`) is a variant on the traditional WorldEdit wand (`worldedit:wand`). It looks like this: ![A picture of the far wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/master/worldeditadditions_farwand/textures/worldeditadditions_farwand.png)
The far wand (`worldeditadditions:farwand`) is a variant on the traditional WorldEdit wand (`worldedit:wand`). It looks like this: ![A picture of the far wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_farwand.png)
It functions very similarly to the regular WorldEdit wand, except that it has a _much_ longer range - which can be very useful for working on large-scale terrain for example. It also comes with an associated command to control it.
Note that punching out the positions **does not unset them**. Use `//reset` to reset the defined region.
### `//farwand skip_liquid (true|false) | maxdist <number>`
This command helps control the behaviour of the [WorldEditAdditions far wand](#far-wand) and [cloud wand](#cloud-wand). Calling it without any arguments shows the current status:
@ -1227,8 +1433,23 @@ You can change the maximum range with the `maxdist` subcommand:
Note that the number there isn't in blocks (because hard maths). It is however proportional to the distance the wand will raycast looks for nodes, so a higher value will result in it raycasting further.
### Cloud Wand
The cloud wand (`worldeditadditions:cloudwand`) is a another variant the above _Far Wand_. It looks like this: ![A picture of the far wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/master/worldeditadditions_farwand/textures/worldeditadditions_cloudwand.png)
The cloud wand (`worldeditadditions:cloudwand`) is a another variant the above _Far Wand_. It looks like this: ![A picture of the far wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_cloudwand.png)
Unlike the other 2 wands, this wand functions in an additive manner. Left-click on a node to expand the currently defined region (creating a new one if one isn't defined already) to include that node. Right click to clear the currently defined region.
It has the range of the _Far Wand_ mentioned above too, so you can select nodes from a great distance. It also abides by preferences set via the `//farwand` chat command.
Note that punching out the positions **does not unset them**. Use `//reset` to reset the defined region.
### Multi-Point Wand
The third type of wand provided by WorldEditAdditions is completely different, in that it allows you to select up to **999 points** at once! It looks like this: ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png)
It is important to note that (at present) the points selected by this wand **are not compatible with normal points**. This will change in the future, but requires a lot of work to implement.
It has the following actions:
- **Left click:** Add a new point
- **Right click:** Undo adding a point
It has the range of the other wands mentioned above though, so you can select nodes from a great distance. It also abides by preferences set via the `//farwand` chat command.

View File

@ -1,5 +1,5 @@
# ![](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions-64.png) Minetest-WorldEditAdditions
![GitHub release (latest by date)](https://img.shields.io/github/v/release/sbrl/Minetest-WorldEditAdditions?color=green&label=latest%20release) [![View the changelog](https://img.shields.io/badge/%F0%9F%93%B0-Changelog-informational)](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/CHANGELOG.md) [![ContentDB](https://content.minetest.net/packages/Starbeamrainbowlabs/worldeditadditions/shields/downloads/)](https://content.minetest.net/packages/Starbeamrainbowlabs/worldeditadditions/)
# ![](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions-64.png) WorldEditAdditions
![GitHub release (latest by date)](https://img.shields.io/github/v/release/sbrl/Minetest-WorldEditAdditions?color=green&label=latest%20release) [![View the changelog](https://img.shields.io/badge/%F0%9F%93%B0-Changelog-informational)](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/CHANGELOG.md) [![ContentDB](https://content.minetest.net/packages/Starbeamrainbowlabs/worldeditadditions/shields/downloads/)](https://content.minetest.net/packages/Starbeamrainbowlabs/worldeditadditions/) [![Join the official discord server](https://worldeditadditions.mooncarrot.space/img/shield-discord.svg)](https://discord.gg/FzD73kuhsk)
> Extra tools and commands to extend WorldEdit for Minetest
@ -25,9 +25,12 @@ _(Do you have a cool build that you used WorldEditAdditions to build? [Get in to
## Quick Command Reference
The detailed explanations have moved! Check them out [here](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md), or click the links below.
The detailed explanations have moved! Check them out [here](https://worldeditadditions.mooncarrot.space/Reference/) (or edit at [Chat-Command-Reference.md](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md)), or click the links below.
### Geometry
- [`//spline <replace_node> <width_start> [<width_end=width_start> [<steps=3>]]`](https://worldeditadditions.mooncarrot.space/Reference/#spline)
- [`//dome+ <radius> <replace_node> [<pointing_dir:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> ...] [h[ollow]]`](https://worldeditadditions.mooncarrot.space/Reference/#dome)
- [`//metaball add <radius> | remove <index> | render <replace_node> [<threshold=1>] | list | clear | volume`](https://worldeditadditions.mooncarrot.space/Reference/#metaball)
- [`//ellipsoid <rx> <ry> <rz> <node_name> [h[ollow]]`](https://worldeditadditions.mooncarrot.space/Reference/#ellipsoid)
- [`//ellipsoid2 <node_name> [h[ollow]]`](https://worldeditadditions.mooncarrot.space/Reference/#ellipsoid2)
- [`//hollowellipsoid <rx> <ry> <rz> <node_name>`](https://worldeditadditions.mooncarrot.space/Reference/#hollowellipsoid)
@ -39,10 +42,14 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//maze <replace_node> [<path_length> [<path_width> [<seed>]]]`](https://worldeditadditions.mooncarrot.space/Reference/#maze)
- [`//maze3d <replace_node> [<path_length> [<path_width> [<path_depth> [<seed>]]]]`](https://worldeditadditions.mooncarrot.space/Reference/#maze3d)
- [`//spiral2 [<circle|square>] [<replace_node=dirt> [<interval=3> [<acceleration=0>] ] ]`](https://worldeditadditions.mooncarrot.space/Reference/#spiral2)
- [`//wbox <replace_node>`](https://worldeditadditions.mooncarrot.space/Reference/#wbox)
- [`//wcompass <replace_node> [<bead_node>]`](https://worldeditadditions.mooncarrot.space/Reference/#wcompass)
- [`//wcorner <replace_node>`](https://worldeditadditions.mooncarrot.space/Reference/#wcorner)
### Misc
- [`//copy+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`](https://worldeditadditions.mooncarrot.space/Reference/#copy+)
- [`//move+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`](https://worldeditadditions.mooncarrot.space/Reference/#copy+)
- [`//revolve <times> [<pivot_point_number=last_point>]`](https://worldeditadditions.mooncarrot.space/Reference/#revolve)
- [`//copy+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`](https://worldeditadditions.mooncarrot.space/Reference/#copy)
- [`//move+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`](https://worldeditadditions.mooncarrot.space/Reference/#move)
- [`//replacemix <target_node> [<chance>] <replace_node_a> [<chance_a>] [<replace_node_b> [<chance_b>]] [<replace_node_N> [<chance_N>]] ....`](https://worldeditadditions.mooncarrot.space/Reference/#replacemix)
- [`//floodfill [<replace_node> [<radius>]]`](https://worldeditadditions.mooncarrot.space/Reference/#floodfill)
- [`//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]`](https://worldeditadditions.mooncarrot.space/Reference/#scale) **experimental**
@ -54,7 +61,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//convolve <kernel> [<width>[,<height>]] [<sigma>]`](https://worldeditadditions.mooncarrot.space/Reference/#convolve)
- [`//erode [<snowballs|river> [<key_1> [<value_1>]] [<key_2> [<value_2>]] ...]`](https://worldeditadditions.mooncarrot.space/Reference/#erode) **experimental**
- [`//noise2d [<key_1> [<value_1>]] [<key_2> [<value_2>]] ...]`](https://worldeditadditions.mooncarrot.space/Reference/#noise2d)
- [`//sculpt [<brush_name=default> [<height=5> [<brush_size=10>]]]`](https://worldeditadditions.mooncarrot.space/Reference/#sculpt)
- [`//sculpt [[<brush_name=default> [<brush_size=8> [<height=1>]]]`](https://worldeditadditions.mooncarrot.space/Reference/#sculpt)
- [`//sculptlist [preview]`](https://worldeditadditions.mooncarrot.space/Reference/#sculptlist)
### Flora
@ -77,6 +84,14 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//sstack`](https://worldeditadditions.mooncarrot.space/Reference/#sstack)
- [`//spush`](https://worldeditadditions.mooncarrot.space/Reference/#spush)
- [`//spop`](https://worldeditadditions.mooncarrot.space/Reference/#spop)
- [`//sshift <axis1> <length1> [<axis2> <length2> [<axis3> <length3>]]`](https://worldeditadditions.mooncarrot.space/Reference/#sshift)
- [`//sfactor <mode:grow|shrink|average> <factor> [<target=xz>]`](https://worldeditadditions.mooncarrot.space/Reference/#sfactor)
- [`//pos <index>`](https://worldeditadditions.mooncarrot.space/Reference/#pos)
- [`//pos1`](https://worldeditadditions.mooncarrot.space/Reference/#pos1)
- [`//pos2`](https://worldeditadditions.mooncarrot.space/Reference/#pos2)
- [`//mark`](https://worldeditadditions.mooncarrot.space/Reference/#mark)
- [`//unmark`](https://worldeditadditions.mooncarrot.space/Reference/#unmark)
- [`//reset`](https://worldeditadditions.mooncarrot.space/Reference/#reset)
### Measure
- [`//mface`](https://worldeditadditions.mooncarrot.space/Reference/#mface) _(new in v1.13)_
@ -91,6 +106,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//ellipsoidapply <command_name> <args>`](https://worldeditadditions.mooncarrot.space/Reference/#ellipsoidapply) _(new in v1.9)_
- [`//airapply <command_name> <args>`](https://worldeditadditions.mooncarrot.space/Reference/#airapply) _(new in v1.9)_
- [`//noiseapply2d <threshold> <scale> <command_name> <args>`](https://worldeditadditions.mooncarrot.space/Reference/#noiseapply2d) _(new in v1.13)_
- [`//for <value1> <value2> <value3>... do //<command> <arg> %% <arg>`](https://worldeditadditions.mooncarrot.space/Reference/#for) _(new in v1.13)_
### Extras
- [`//y`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#y)
@ -122,6 +138,8 @@ cd WorldEditAdditions
git checkout "$(git describe --tags --abbrev=0)";
```
If you do not checkout the latest release, you will be using the development version of WorldEditAdditions. While every effort is made to ensure that the development version is stable at all times, this is not a guarantee.
Windows users, you'll need to check the [releases page](https://github.com/sbrl/Minetest-WorldEditAdditions/releases) and find the name of the latest release, then do this instead of the `git checkout` above:
```bash
@ -144,13 +162,34 @@ Please update to v1.8+. There was a bug in earlier versions that caused a race c
### Why don't the [moretrees](https://content.minetest.net/packages/VanessaE/moretrees/) trees work with `//forest`?
As far as I can tell, the saplings provided by the [`moretrees` mod](https://content.minetest.net/packages/VanessaE/moretrees/) don't properly interact with bonemeal from the [bonemeal mod](https://content.minetest.net/packages/TenPlus1/bonemeal/), which WorldEditAdditions uses to grow trees. As far as I can tell WorldEditAdditions has everything in place needed to support them, but until applying bonemeal to `moretrees` saplings results in a tree rather than waiting for one to grow over time, WorldEditAdditions will always fail to place trees provided by the `moretrees` mod, unfortunately.
### The region markers look weird!
We've implemented a custom replacement for the WorldEdit region markers that supports selecting more than 2 points. This new WorldEditAdditions positioning system synchronises with WorldEdit's positioning system, so you can use both WorldEdit and WorldEditAdditions tools and commands interchangeably and they will seamlessly sync with each other.
The only side effect of this is that WorldEdit commands such as `//shift` are not aware of the new WorldEditAdditions positioning system, so you may encounter a situation where both WorldEdit and WorldEditAdditions region markers may display until you use another WorldEditAdditions command or tool to update them. This will be fixed in time as more commands and tools are implemented.
### The position markers disappear when far way
This is a limitation of Minetest. You can workaround it though by setting [`active_block_range`](https://github.com/minetest/minetest/blob/5.6.1/minetest.conf.example#L2868) to a higher value - though be aware this also affects ABMs and other entities as well, so it can cause server lag.
The new positioning system now partially rectifies this issue with the region marker walls by creating a grid of entities instead of a single entity, such that a portion of them are more likely to be in range.
## Contributing
Contributions are welcome! Please state in your pull request(s) that you release your contribution under the _Mozilla Public License 2.0_.
Please also make sure that the logic for every new command has it's own file. For example, the logic for `//floodfill` goes in `worldeditadditions/floodfill.lua`, the logic for `//overlay` goes in `worldeditadditions/overlay.lua`, etc. More contributing help can be found in [the contributing guide](CONTRIBUTING.md).
I, Starbeamrainbowlabs (@sbrl), have the ultimate final say.
### Inspiration
Want to contribute, but finding it tough to search for inspiration of what to implement? Here are some great places to look:
- [**Our issue tracker:**](https://github.com/sbrl/Minetest-WorldEditAdditions/issues) There are always a bunch of issues open with cool commands and features that have yet to be implemented.
- **Other software:** Software for Minecraft is often far more mature than that available for Minetest. As a result, it's full of cool ideas. A lot of the existing commands in WorldEditAdditions were sourced from here.
- WorldEdit for Minecraft
- VoxelSniper(-Reimagined) for Minecraft
- WorldPainter for Minecraft
- **Do some building:** When you put WorldEditAdditions to use in building projects of your own, things will absolutely stand out to you what you want in the creative building process that WorldEditAdditions doesn't yet have.
- **Watch others build stuff:** Doesn't even have to be Minetest! There are lots of talented Minecraft builders with videos and series on e.g. YouTube. From their creative building processes, many ideas can be derived.
The ultimate goal is for WorldEditAdditions to support the creative building process in a way that enables builders of all backgrounds to create incredible things.
## WorldEditAdditions around the web

157
bresenham.lua Normal file
View File

@ -0,0 +1,157 @@
local Vector3 = dofile("worldeditadditions/utils/vector3.lua")
local function make_grid(size)
local grid = {}
for y=1,size.y do
for x=1,size.x do
grid[(size.x * y) + x] = 0
end
end
return {
size = size,
data = grid
}
end
local function index(grid, pos)
return (grid.size.x * pos.y) + pos.x
end
local function grid_to_string(grid)
local result = {}
for y=1,grid.size.y do
for x=1,grid.size.x do
local i = index(grid, Vector3.new(x, y))
if grid.data[i] == 0 then
table.insert(result, "#")
elseif grid.data[i] == 1 then
table.insert(result, " ")
elseif grid.data[i] < 10 then
table.insert(result, tostring(grid.data[i]))
else
table.insert(result, "?")
end
end
table.insert(result, "\n")
end
return table.concat(result, "")
end
--- Draws a line using Bresenham's algorithm in 2d.
-- Implemented ported from https://github.com/anushaihalapathirana/Bresenham-line-drawing-algorithm/blob/f51f153459a1656bfb1f433edc75e6644a052bb2/src/index.js
-- @param grid Grid The grid to draw on.
-- @param pos1 Vector3 The starting point of the line.
-- @param pos2 Vector3 The ending point of the line.
-- @param value number The number to fill in grid cells we draw in.
-- @returns void
local function draw_line_2d(grid, pos1, pos2, value)
if not value then value = 1 end
if pos1 == pos2 then
grid.data[index(grid, pos1)] = value
return
end
grid.data[index(grid, pos1)] = value -- plot pos1
local delta = pos2 - pos1
local absdelta = delta:abs()
local delta_error = (2 * absdelta.y) - absdelta.x -- d
if absdelta.x <= absdelta.y then delta_error = (2 * absdelta.x) - absdelta.y end
local pos_current = pos1:clone()
local steps = 0
local limit = absdelta.y
if absdelta.x > absdelta.y then limit = absdelta.x end
for _=1,limit do
local do_x = false
local do_y = false
if absdelta.x > absdelta.y then
do_x = true
if delta_error < 0 then
delta_error = delta_error + 2*absdelta.y
else
do_y = true
delta_error = delta_error + (2*absdelta.y - 2*absdelta.x)
end
else
do_y = true
if delta_error < 0 then
delta_error = delta_error + 2*absdelta.x
else
do_x = true
delta_error = delta_error + (2*absdelta.x) - (2*absdelta.y)
end
end
if do_x then
local acc = 1
if delta.x < 0 then acc = -1 end
pos_current.x = pos_current.x + acc
end
if do_y then
local acc = 1
if delta.y < 0 then acc = -1 end
pos_current.y = pos_current.y + acc
end
local i = index(grid, pos_current)
grid.data[i] = value
steps = steps + 1
end
end
local size = Vector3.new(120, 40)
local grid = make_grid(size)
-- draw_line_2d(grid, Vector3.new(10, 10), Vector3.new(40, 10))
-- draw_line_2d(grid, Vector3.new(70, 10), Vector3.new(70, 10))
draw_line_2d(grid, Vector3.new(75, 10), Vector3.new(75, 40))
draw_line_2d(grid, Vector3.new(80, 40), Vector3.new(80, 10))
-- local centre = Vector3.new(25, 25)
-- draw_line_2d(grid, centre, Vector3.new(0, 0))
-- draw_line_2d(grid, centre, Vector3.new(5, 0))
-- draw_line_2d(grid, centre, Vector3.new(10, 0))
-- draw_line_2d(grid, centre, Vector3.new(15, 0))
-- draw_line_2d(grid, centre, Vector3.new(20, 0))
-- draw_line_2d(grid, centre, Vector3.new(25, 0))
-- draw_line_2d(grid, centre, Vector3.new(30, 0), 3)
for i=1,9 do
print("LINE", i)
local pos1 = Vector3.new(
math.random(0, size.x),
math.random(0, size.y)
)
local pos2 = Vector3.new(
math.random(0, size.x),
math.random(0, size.y)
)
draw_line_2d(grid, pos1, pos2)
end
-- draw_line_2d(grid,
-- Vector3.new(3, 4),
-- Vector3.new(8, 9)
-- )
-- draw_line_2d(grid,
-- Vector3.new(10, 9),
-- Vector3.new(15, 4)
-- )
-- draw_line_2d(grid,
-- Vector3.new(20, 10),
-- Vector3.new(40, 20)
-- )
-- draw_line_2d(grid,
-- Vector3.new(10, 9),
-- Vector3.new(55, 4)
-- )
print(grid_to_string(grid))

View File

@ -2,10 +2,10 @@
set -e;
# current_branch="$(git rev-parse --abbrev-ref HEAD)";
is_main="$(git branch --contains HEAD | awk '/HEAD/ { next } /main/ { print $1 }')";
is_main="$(git branch --contains HEAD | awk '/HEAD/ { next } /dev/ { print $1 }')";
if [[ "${1}" == "ci" ]] && [[ ! -z "${is_main}" ]]; then
echo "Skipping build, because this commit does not appear to be on the 'main' branch, and we only deploy commits on the 'main' branch.";
echo "Skipping build, because this commit does not appear to be on the 'dev' branch, and we only deploy commits on the 'main' branch.";
fi
# ██████ ██ ██████ ██ ██ ██ ██ ██████
@ -91,6 +91,9 @@ npm install;
log_msg "Building website";
# This causes the eleventy docs site to minify stuff
# Note that this is NOT before the npm install, as npm doesn't install everything if we do that
export NODE_ENV=production;
npm run build;
if [[ ! -d "_site" ]]; then

View File

@ -1,5 +1,6 @@
name = worldeditadditions
description = Extra tools and commands to extend WorldEdit. Currently has over 22 commands!
depends = worldedit
optional_depends = bonemeal,cool_trees,default,moretrees,ethereal
min_minetest_version = 5.1
min_minetest_version = 5.2

77
rotate.js Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env node
/**
* Rotate a given point around an origin point in 3d space.
* NOTE: This function is not as intuitive as it sounds.
* A whiteboard and a head for mathematics is recommended before using this
* function.
* @source GitHub Copilot
* @warning Not completely tested! Pending a thorough evaluation.
* @param {Vector3} origin The origin point to rotate around
* @param {Vector3} point The point to rotate.
* @param {Number} x Rotate this much around the X axis (yz plane), in radians.
* @param {Number} y Rotate this much around the Y axis (xz plane), in radians.
* @param {Number} z Rotate this much around the Z axis (xy plane), in radians.
* @return {Vector3} The rotated point.
*/
function rotate_point_3d(origin, point, x, y, z)
{
point = [...point];
point[0] = point[0] - origin[0];
point[1] = point[1] - origin[1];
point[2] = point[2] - origin[2];
// rotate around x
var x1 = point[0];
var y1 = point[1] * Math.cos(x) - point[2] * Math.sin(x);
var z1 = point[1] * Math.sin(x) + point[2] * Math.cos(x);
// rotate around y
var x2 = x1 * Math.cos(y) + z1 * Math.sin(y);
var y2 = y1;
var z2 = -x1 * Math.sin(y) + z1 * Math.cos(y);
// rotate around z
var x3 = x2 * Math.cos(z) - y2 * Math.sin(z);
var y3 = x2 * Math.sin(z) + y2 * Math.cos(z);
var z3 = z2;
return [x3+origin[0], y3+origin[1], z3+origin[2]];
}
function deg_to_rad(deg)
{
return deg * Math.PI / 180;
}
function point_to_string(point, decimal_places=3)
{
return "(x " + point[0].toFixed(decimal_places) + ", y " + point[1].toFixed(decimal_places) + ", z " + point[2].toFixed(decimal_places) + ")";
}
function do_test(origin, point, ...args) {
const result = rotate_point_3d(origin, point, ...args);
console.log(`ORIGIN`, point_to_string(origin), `\tPOINT`, point_to_string(point), `\tRESULT`, point_to_string(result));
}
do_test(
[1, 0, 0],
[5, 0, 0],
deg_to_rad(0), // rotate around x axis = yz plane
deg_to_rad(0), // rotate around y axis = xz plane
deg_to_rad(180) // rotate around z axis = xy plane
);
do_test(
[1, 0, 0],
[0, 1, 0],
deg_to_rad(0), // rotate around x axis = yz plane
deg_to_rad(0), // rotate around y axis = xz plane
deg_to_rad(180) // rotate around z axis = xy plane
);
do_test(
[10, 100, 0],
[0, 0, 0],
deg_to_rad(0), // rotate around x axis = yz plane
deg_to_rad(0), // rotate around y axis = xz plane
deg_to_rad(180) // rotate around z axis = xy plane
);

7
settingtypes.txt Normal file
View File

@ -0,0 +1,7 @@
# https://github.com/minetest/minetest/blob/master/builtin/settingtypes.txt#L1
# Will WorldEditAdditions override commands?
worldeditadditions.override_commands (Override WorldEdit Commands) bool false
# Will WorldEditAdditions wands be craftable?
worldeditadditions.wand_craft (Craftable Wands) bool false

View File

@ -31,7 +31,15 @@ check_command luarocks;
luarocks_root="${PWD}/.luarocks";
# Setup the lua module path
eval "$(luarocks --tree "${luarocks_root}" path)";
if [[ "${OSTYPE}" == *"msys"* ]]; then
PATH="$(luarocks --tree "${luarocks_root}" path --lr-bin):${PATH}";
LUA_PATH="$(luarocks --tree "${luarocks_root}" path --lr-path);init.lua;./?.lua;${LUA_PATH}";
LUA_CPATH="$(luarocks --tree "${luarocks_root}" path --lr-cpath);./?.so;${LUA_CPATH}";
else
eval "$(luarocks --tree "${luarocks_root}" path)";
fi
export PATH LUA_PATH LUA_CPATH;
mode="${1}"; if [[ "$#" -gt 0 ]]; then shift; fi
@ -46,7 +54,15 @@ run_syntax_check() {
}
run_test() {
.luarocks/bin/busted --no-auto-insulate --pattern ".test.lua" .tests;
busted_path=".luarocks/bin/busted";
if [[ ! -r "${busted_path}" ]]; then
busted_path=".luarocks/bin/busted.bat";
fi
if [[ ! -r "${busted_path}" ]]; then
echo "Error: Failed to find busted at .luarocks/bin/busted or .luarocks/bin/busted.bat" >&2;
exit 1;
fi
"${busted_path}" --no-auto-insulate --pattern ".test.lua" .tests;
}
case "${mode}" in
@ -62,10 +78,6 @@ case "${mode}" in
run_test;
;;
busted )
.luarocks/bin/busted "${@}";
;;
* )
echo -e "Usage:
path/to/run.sh setup # Setup to run the tests

View File

@ -1,6 +0,0 @@
worldedit
bonemeal?
cool_trees?
default?
moretrees?
ethereal?

View File

@ -1,7 +1,7 @@
--- WorldEditAdditions
-- @module worldeditadditions
-- @release 0.1
-- @copyright 2018 Starbeamrainbowlabs
-- @namespace worldeditadditions
-- @release 1.14.5
-- @copyright 2023 Starbeamrainbowlabs
-- @license Mozilla Public License, 2.0
-- @author Starbeamrainbowlabs
@ -9,35 +9,6 @@ worldeditadditions = {}
local wea = worldeditadditions
wea.modpath = minetest.get_modpath("worldeditadditions")
wea.Set = dofile(wea.modpath.."/utils/set.lua")
wea.Vector3 = dofile(wea.modpath.."/utils/vector3.lua")
wea.Mesh, wea.Face = dofile(wea.modpath.."/utils/mesh.lua")
wea.Queue = dofile(wea.modpath.."/utils/queue.lua")
wea.LRU = dofile(wea.modpath.."/utils/lru.lua")
wea.inspect = dofile(wea.modpath.."/utils/inspect.lua")
-- I/O compatibility layer
wea.io = dofile(wea.modpath.."/utils/io.lua")
wea.bit = dofile(wea.modpath.."/utils/bit.lua")
wea.terrain = dofile(wea.modpath.."/utils/terrain/init.lua")
dofile(wea.modpath.."/utils/vector.lua")
dofile(wea.modpath.."/utils/strings/init.lua")
dofile(wea.modpath.."/utils/format/init.lua")
dofile(wea.modpath.."/utils/parse/init.lua")
dofile(wea.modpath.."/utils/tables/init.lua")
dofile(wea.modpath.."/utils/numbers.lua")
dofile(wea.modpath.."/utils/nodes.lua")
dofile(wea.modpath.."/utils/node_identification.lua")
dofile(wea.modpath.."/utils/raycast_adv.lua") -- For the farwand
dofile(wea.modpath.."/utils/player.lua") -- Player info functions
dofile(wea.modpath.."/lib/compat/saplingnames.lua")
dofile(wea.modpath.."/lib/floodfill.lua")
@ -58,10 +29,14 @@ dofile(wea.modpath.."/lib/scale_down.lua")
dofile(wea.modpath.."/lib/scale.lua")
dofile(wea.modpath.."/lib/spiral_square.lua")
dofile(wea.modpath.."/lib/spiral_circle.lua")
dofile(wea.modpath.."/lib/dome.lua")
dofile(wea.modpath.."/lib/spline.lua")
dofile(wea.modpath.."/lib/revolve.lua")
dofile(wea.modpath.."/lib/conv/conv.lua")
dofile(wea.modpath.."/lib/erode/erode.lua")
dofile(wea.modpath.."/lib/noise/init.lua")
wea.sculpt = dofile(wea.modpath.."/lib/sculpt/init.lua")
wea.sculpt = dofile(wea.modpath.."/lib/sculpt/init.lua")
wea.metaballs = dofile(wea.modpath.."/lib/metaballs/init.lua")
dofile(wea.modpath.."/lib/copy.lua")
dofile(wea.modpath.."/lib/move.lua")

View File

@ -1,3 +1,6 @@
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- █████ ██ ██████
-- ██ ██ ██ ██ ██
-- ███████ ██ ██████
@ -10,24 +13,24 @@
-- ██ ██ ██ ██ ██ ██
-- ██ ██ ██ ██ ███████ ██
--- Similar to cubeapply, except that it takes 2 positions and only keeps an ellipsoid-shaped area defined by the boundaries of the defined region.
--- Like ellipsoidapply, but only keeps changes that replace airlike nodes, and discards any other changes made.
-- Takes a backup copy of the defined region, runs the given function, and then
-- restores the bits around the edge that aren't inside the largest ellipsoid that will fit inside the defined region.
-- @param {Position} pos1 The 1st position defining the region boundary
-- @param {Position} pos2 The 2nd positioon defining the region boundary
-- @param {Function} func The function to call that performs the action in question. It is expected that the given function will accept no arguments.
function worldeditadditions.airapply(pos1, pos2, func)
local time_taken_all = worldeditadditions.get_ms_time()
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local time_taken_all = wea_c.get_ms_time()
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
local manip_before, area_before = worldedit.manip_helpers.init(pos1, pos2)
local data_before = manip_before:get_data()
local time_taken_fn = worldeditadditions.get_ms_time()
local time_taken_fn = wea_c.get_ms_time()
func()
time_taken_fn = worldeditadditions.get_ms_time() - time_taken_fn
time_taken_fn = wea_c.get_ms_time() - time_taken_fn
local manip_after, area_after = worldedit.manip_helpers.init(pos1, pos2)
local data_after = manip_after:get_data()
@ -37,7 +40,7 @@ function worldeditadditions.airapply(pos1, pos2, func)
for x = pos2.x, pos1.x, -1 do
local i_before = area_before:index(x, y, z)
local i_after = area_after:index(x, y, z)
local old_is_airlike = worldeditadditions.is_airlike(data_before[i_before])
local old_is_airlike = wea_c.is_airlike(data_before[i_before])
-- Roll everything that replaces nodes that aren't airlike
if not old_is_airlike then
@ -52,6 +55,6 @@ function worldeditadditions.airapply(pos1, pos2, func)
worldedit.manip_helpers.finish(manip_after, data_after)
time_taken_all = worldeditadditions.get_ms_time() - time_taken_all
time_taken_all = wea_c.get_ms_time() - time_taken_all
return true, { all = time_taken_all, fn = time_taken_fn }
end

View File

@ -1,12 +1,16 @@
--- Bonemeal command.
-- Applies bonemeal to all notes
-- @module worldeditadditions.overlay
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- strength The strength to apply - see bonemeal:on_use
-- chance Positive integer that represents the chance bonemealing will occur
--- Bonemeal command.
-- Applies bonemeal to all nodes with an air bloc above then.
-- @param strength The strength to apply - see bonemeal:on_use
-- @param chance Positive integer that represents the chance bonemealing will occur
-- @returns bool,number,number 1. Whether the command succeeded or not.
-- 2. The number of nodes actually bonemealed
-- 3. The number of possible candidates we could have bonemealed
function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list)
if not nodename_list then nodename_list = {} end
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- This command requires the bonemeal mod to be installed
@ -15,7 +19,7 @@ function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list
return false, "Bonemeal mod not loaded"
end
local node_list = worldeditadditions.table.map(nodename_list, function(nodename)
local node_list = wea_c.table.map(nodename_list, function(nodename)
return minetest.get_content_id(nodename)
end)
local node_list_count = #nodename_list
@ -34,9 +38,9 @@ function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list
for x = pos2.x, pos1.x, -1 do
for y = pos2.y, pos1.y, -1 do
local i = area:index(x, y, z)
if not worldeditadditions.is_airlike(data[i]) then
if not wea_c.is_airlike(data[i]) then
local should_bonemeal = true
if node_list_count > 0 and not worldeditadditions.table.contains(node_list, data[i]) then
if node_list_count > 0 and not wea_c.table.contains(node_list, data[i]) then
should_bonemeal = false
end
@ -45,7 +49,7 @@ function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list
if should_bonemeal and math.random(0, chance - 1) == 0 then
bonemeal:on_use(
{ x = x, y = y, z = z },
Vector3.new(x, y, z),
strength,
nil
)

View File

@ -1,3 +1,4 @@
local wea_c = worldeditadditions_core
--[[
This file contains sapling alias definitions for a number of different mods.
If your mod is not listed here, please open a pull request to add it :-)
@ -7,15 +8,16 @@ This mod's repository can be found here: https://github.com/sbrl/Minetest-WorldE
Adding support for your mod is a 2 step process:
1. Update this file with your definitions
2. Update depends.txt to add a soft dependency on your mod. Find that file here: https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/worldeditadditions/depends.txt - for example, add something line "my_awesome_mod?" (note the question mark at the end) on a new line(without quotes).
2. Update depends.txt to add a soft dependency on your mod. Find that file here: https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/worldeditadditions/depends.txt - for example, add something line "my_awesome_mod?" (note the question mark at the end) on a new line(without quotes).
Alternatively, you can register support in your mod directly. Do that by adding a soft dependency on worldeditadditions, and then calling worldeditadditions.normalise_saplingname if worldeditadditions is loaded.
Alternatively, you can register support in your mod directly. Do that by adding a soft dependency on worldeditadditions_core, and then calling worldeditadditions_core.normalise_saplingname if worldeditadditions is loaded.
]]--
-- worldeditadditions.register_sapling_alias("")
-- TODO: MOVE register_sapling_alias & register_sapling_alias_many back to worldeditadditions from worldeditadditions_core!!!!
-- wea_c.register_sapling_alias("")
if minetest.get_modpath("default") then
worldeditadditions.register_sapling_alias_many({
wea_c.register_sapling_alias_many({
{ "default:sapling", "apple" },
{ "default:bush_sapling", "bush" },
{ "default:pine_sapling", "pine" },
@ -31,27 +33,27 @@ if minetest.get_modpath("default") then
end
if minetest.get_modpath("moretrees") then
worldeditadditions.register_sapling_alias_many({
{ "moretrees:spruce_sapling_ongen", "spruce" },
{ "moretrees:rubber_tree_sapling_ongen", "rubber" },
{ "moretrees:beech_sapling_ongen", "beech" },
{ "moretrees:jungletree_sapling_ongen", "jungle_moretrees" },
{ "moretrees:fir_sapling_ongen", "fir" },
{ "moretrees:willow_sapling_ongen", "willow_moretrees" },
{ "moretrees:poplar_sapling_ongen", "poplar" },
{ "moretrees:poplar_small_sapling_ongen", "poplar_small" },
{ "moretrees:apple_tree_sapling_ongen", "apple_moretrees" },
{ "moretrees:birch_sapling_ongen", "birch_moretrees" },
{ "moretrees:palm_sapling_ongen", "palm_moretrees" },
{ "moretrees:date_palm_sapling_ongen", "palm_date" },
{ "moretrees:sequoia_sapling_ongen", "sequoia" },
{ "moretrees:oak_sapling_ongen", "oak_moretrees" },
{ "moretrees:cedar_sapling_ongen", "cedar" }
wea_c.register_sapling_alias_many({
{ "moretrees:spruce_sapling", "spruce" },
{ "moretrees:rubber_tree_sapling", "rubber" },
{ "moretrees:beech_sapling", "beech" },
{ "moretrees:jungletree_sapling", "jungle_moretrees" },
{ "moretrees:fir_sapling", "fir" },
{ "moretrees:willow_sapling", "willow_moretrees" },
{ "moretrees:poplar_sapling", "poplar" },
{ "moretrees:poplar_small_sapling", "poplar_small" },
{ "moretrees:apple_tree_sapling", "apple_moretrees" },
{ "moretrees:birch_sapling", "birch_moretrees" },
{ "moretrees:palm_sapling", "palm_moretrees" },
{ "moretrees:date_palm_sapling", "palm_date" },
{ "moretrees:sequoia_sapling", "sequoia" },
{ "moretrees:oak_sapling", "oak_moretrees" },
{ "moretrees:cedar_sapling", "cedar" }
})
end
if minetest.get_modpath("ethereal") then
worldeditadditions.register_sapling_alias_many({
wea_c.register_sapling_alias_many({
{ "ethereal:mushroom_sapling", "mushroom" },
{ "ethereal:sakura_sapling", "sakura" },
{ "ethereal:birch_sapling", "birch" },
@ -75,56 +77,56 @@ end
-- ██████ ██████ ██████ ███████ ███████ ██ ██ ██ ███████ ███████ ███████
if minetest.get_modpath("lemontree") then
worldeditadditions.register_sapling_alias("lemontree:sapling", "lemon")
wea_c.register_sapling_alias("lemontree:sapling", "lemon")
end
if minetest.get_modpath("pineapple") then
worldeditadditions.register_sapling_alias("pineapple:sapling", "pineapple")
wea_c.register_sapling_alias("pineapple:sapling", "pineapple")
end
if minetest.get_modpath("baldcypress") then
worldeditadditions.register_sapling_alias("baldcypress:sapling", "baldcypress")
wea_c.register_sapling_alias("baldcypress:sapling", "baldcypress")
end
if minetest.get_modpath("bamboo") then
worldeditadditions.register_sapling_alias("bamboo:sprout", "bamboo")
wea_c.register_sapling_alias("bamboo:sprout", "bamboo")
end
if minetest.get_modpath("birch") then
worldeditadditions.register_sapling_alias("birch:sapling", "birch")
wea_c.register_sapling_alias("birch:sapling", "birch")
end
if minetest.get_modpath("cherrytree") then
worldeditadditions.register_sapling_alias("cherrytree:sapling", "cherry")
wea_c.register_sapling_alias("cherrytree:sapling", "cherry")
end
if minetest.get_modpath("clementinetree") then
worldeditadditions.register_sapling_alias("clementinetree:sapling", "clementine")
wea_c.register_sapling_alias("clementinetree:sapling", "clementine")
end
if minetest.get_modpath("ebony") then
worldeditadditions.register_sapling_alias("ebony:sapling", "ebony")
wea_c.register_sapling_alias("ebony:sapling", "ebony")
end
if minetest.get_modpath("jacaranda") then
worldeditadditions.register_sapling_alias("jacaranda:sapling", "jacaranda")
wea_c.register_sapling_alias("jacaranda:sapling", "jacaranda")
end
if minetest.get_modpath("larch") then
worldeditadditions.register_sapling_alias("larch:sapling", "larch")
wea_c.register_sapling_alias("larch:sapling", "larch")
end
if minetest.get_modpath("maple") then
worldeditadditions.register_sapling_alias("maple:sapling", "maple")
wea_c.register_sapling_alias("maple:sapling", "maple")
end
if minetest.get_modpath("palm") then
worldeditadditions.register_sapling_alias("palm:sapling", "palm")
wea_c.register_sapling_alias("palm:sapling", "palm")
end
if minetest.get_modpath("plumtree") then
worldeditadditions.register_sapling_alias("plumtree:sapling", "plum")
wea_c.register_sapling_alias("plumtree:sapling", "plum")
end
if minetest.get_modpath("hollytree") then
worldeditadditions.register_sapling_alias("hollytree:sapling", "holly")
wea_c.register_sapling_alias("hollytree:sapling", "holly")
end
if minetest.get_modpath("pomegranate") then
worldeditadditions.register_sapling_alias("pomegranate:sapling", "pomegranate")
wea_c.register_sapling_alias("pomegranate:sapling", "pomegranate")
end
if minetest.get_modpath("willow") then
worldeditadditions.register_sapling_alias("willow:sapling", "willow")
wea_c.register_sapling_alias("willow:sapling", "willow")
end
if minetest.get_modpath("mahogany") then
worldeditadditions.register_sapling_alias("mahogany:sapling", "mahogany")
wea_c.register_sapling_alias("mahogany:sapling", "mahogany")
end
if minetest.get_modpath("chestnuttree") then
worldeditadditions.register_sapling_alias("chestnuttree:sapling", "chestnut")
wea_c.register_sapling_alias("chestnuttree:sapling", "chestnut")
end

View File

@ -1,5 +1,6 @@
local wea = worldeditadditions
local Vector3 = wea.Vector3
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
wea.conv = {}
@ -62,8 +63,8 @@ function wea.convolve(pos1, pos2, kernel, kernel_size)
local node_id_air = minetest.get_content_id("air")
local heightmap, heightmap_size = wea.terrain.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_conv = wea.table.shallowcopy(heightmap)
local heightmap, heightmap_size = wea_c.terrain.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_conv = wea_c.table.shallowcopy(heightmap)
wea.conv.convolve(
heightmap_conv,
@ -73,11 +74,11 @@ function wea.convolve(pos1, pos2, kernel, kernel_size)
)
-- print("original")
-- wea.format.array_2d(heightmap, (pos2.z - pos1.z) + 1)
-- wea_c.format.array_2d(heightmap, (pos2.z - pos1.z) + 1)
-- print("transformed")
-- wea.format.array_2d(heightmap_conv, (pos2.z - pos1.z) + 1)
-- wea_c.format.array_2d(heightmap_conv, (pos2.z - pos1.z) + 1)
wea.terrain.apply_heightmap_changes(
wea_c.terrain.apply_heightmap_changes(
pos1, pos2, area, data,
heightmap, heightmap_conv, heightmap_size
)

View File

@ -1,5 +1,5 @@
local wea = worldeditadditions
local Vector3 = wea.Vector3
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
--[[
Convolves over a given 2D heightmap with a given matrix.
Note that this *mutates* the given heightmap.
@ -17,7 +17,7 @@ function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, mat
-- We need to reference a *copy* of the heightmap when convolving
-- This is because we need the original values when we perform a
-- convolution on a given pixel
local heightmap_copy = wea.table.shallowcopy(heightmap)
local heightmap_copy = wea_c.table.shallowcopy(heightmap)
local border_size = Vector3.new(
(matrix_size.x-1) / 2, -- x = height

View File

@ -1,3 +1,4 @@
local wea_c = worldeditadditions_core
-- Ported from Javascript by Starbeamrainbowlabs
-- Original source: https://github.com/sidorares/gaussian-convolution-kernel/
-- From
@ -27,7 +28,7 @@ function worldeditadditions.conv.kernel_gaussian(dimension, sigma)
local sum = 0
for i = 0, dimension-1 do
for j = 0, dimension-1 do
local distance = worldeditadditions.hypotenuse(i, j, centre, centre)
local distance = wea_c.hypotenuse(i, j, centre, centre)
-- The following is an algorithm that came from the gaussian blur
-- wikipedia page [1].
@ -35,7 +36,7 @@ function worldeditadditions.conv.kernel_gaussian(dimension, sigma)
-- http://en.wikipedia.org/w/index.php?title=Gaussian_blur&oldid=608793634#Mechanics
local gaussian = (1 / math.sqrt(
math.pi * two_sigma_square
)) * math.exp((-1) * (math.pow(distance, 2) / two_sigma_square));
)) * math.exp((-1) * ((distance ^ 2) / two_sigma_square));
sum = sum + gaussian
kernel[i*dimension + j] = gaussian

View File

@ -1,8 +1,6 @@
--- Copies a region to another location, potentially overwriting the exiting region.
-- @module worldeditadditions.copy
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
local wea = worldeditadditions
local Vector3 = wea.Vector3
-- ██████ ██████ ██████ ██ ██
-- ██ ██ ██ ██ ██ ██ ██
@ -10,7 +8,16 @@ local Vector3 = wea.Vector3
-- ██ ██ ██ ██ ██
-- ██████ ██████ ██ ██
function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2)
--- Copies a region to another location, potentially overwriting the exiting region.
-- @param source_pos1 Vector3 pos1 of the source region to copy.
-- @param source_pos2 Vector3 pos2 of the source region to copy.
-- @param target_pos1 Vector3 pos1 of the target region to copy to.
-- @param target_pos2 Vector3 pos2 of the target region to copy to.
-- @param airapply=false bool Whether to only replace target nodes that are air-like, leaving those that are not air-like. If false, then all target nodes are replaced regardless of whether they are air-like nodes or not.
-- @returns bool,numbers 1. Whether the copy operation was successful or not
-- 2. The total number of nodes copied.
function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2, airapply)
if airapply == nil then airapply = false end
source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2)
target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2)
@ -20,28 +27,39 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p
-- Fetch the nodes in the source area
local manip_source, area_source = worldedit.manip_helpers.init(source_pos1, source_pos2)
local data_source = manip_source:get_data()
local data_source_param2 = manip_source:get_param2_data()
-- Fetch a manip for the target area
local manip_target, area_target = worldedit.manip_helpers.init(target_pos1, target_pos2)
local data_target = manip_target:get_data()
local data_target_param2 = manip_target:get_param2_data()
-- z y x is the preferred loop order (because CPU cache, since then we're iterating linearly through the data array backwards. This only holds true for little-endian machines however)
local total_replaced = 0
for z = source_pos2.z, source_pos1.z, -1 do
for y = source_pos2.y, source_pos1.y, -1 do
for x = source_pos2.x, source_pos1.x, -1 do
local source = Vector3.new(x, y, z)
local source_i = area_source:index(x, y, z)
local target = source:subtract(offset)
local target = source - offset
local target_i = area_target:index(target.x, target.y, target.z)
data_target[target_i] = data_source[source_i]
local should_replace = true
if airapply then
should_replace = wea_c.is_airlike(data_target[target_i])
end
if should_replace then
data_target[target_i] = data_source[source_i]
data_target_param2[target_i] = data_source_param2[source_i]
total_replaced = total_replaced + 1
end
end
end
end
-- Save the modified nodes back to disk & return
manip_target:set_param2_data(data_target_param2)
worldedit.manip_helpers.finish(manip_target, data_target)
return true, worldedit.volume(target_pos1, target_pos2)
return true, total_replaced
end

View File

@ -1,13 +1,21 @@
--- Counts the nodes in a given area.
-- @module worldeditadditions.count
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- ██████ ██████ ██ ██ ███ ██ ████████
-- ██ ██ ██ ██ ██ ████ ██ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██████ ██████ ██████ ██ ████ ██
--- Counts the nodes in a given area.
-- @param pos1 Vector3 pos1 of the defined region to count nodes in.
-- @param pos2 Vector3 pos2 of the defined region to count nodes in.
-- @param do_human_counts bool Whether to return human-readable counts (as a string) instead of the raw numbers.
-- @returns bool,table<number,number>,number 1. Whether the operation was successful or not.
-- 2. A table mapping node ids to the number of that node id seen.
-- 3. The total number of nodes counted.
function worldeditadditions.count(pos1, pos2, do_human_counts)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
@ -29,7 +37,7 @@ function worldeditadditions.count(pos1, pos2, do_human_counts)
for node_name, count in pairs(counts) do
table.insert(results, {
count,
tostring(worldeditadditions.round((count / total) * 100, 2)).."%",
tostring(wea_c.round((count / total) * 100, 2)).."%",
minetest.get_name_from_content_id(node_name)
})
end
@ -37,7 +45,7 @@ function worldeditadditions.count(pos1, pos2, do_human_counts)
if do_human_counts then
for key,item in pairs(results) do
item[1] = worldeditadditions.format.human_size(item[1], 2)
item[1] = wea_c.format.human_size(item[1], 2)
end
end

View File

@ -0,0 +1,83 @@
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- ██████ ██████ ███ ███ ███████
-- ██ ██ ██ ██ ████ ████ ██
-- ██ ██ ██ ██ ██ ████ ██ █████
-- ██ ██ ██ ██ ██ ██ ██ ██
-- ██████ ██████ ██ ██ ███████
--- Creates a dome shape with the given node, optionally specifying the
-- direction the point should point.
-- @param pos Vector3 The central point to start drawing the dome from.
-- @param radius number The radius of the dome to create.
-- @param replace_node string The fully qualified name of the node to use to make the dome with.
-- @param pointing_dir Vector3 Optional. The direction the dome should point. Defaults to (0, 1, 0). See also wea_c.parse.axis_name.
-- @param hollow boolean Whether to make the dome hollow or not. Defaults to false.
function worldeditadditions.dome(pos, radius, replace_node, pointing_dir, hollow)
pos = Vector3.clone(pos)
local pos1 = pos - radius
local pos2 = pos + radius
if not pointing_dir then pointing_dir = Vector3.new(0, 1, 0) end
if hollow == nil then hollow = false end
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
local node_id_replace = minetest.get_content_id(replace_node)
local radius_sq = radius * radius
local radius_inner_sq = (radius-1) * (radius-1)
local centrepoint = Vector3.mean(pos1, pos2)
local replaced = 0
for z = pos2.z, pos1.z, -1 do
for y = pos2.y, pos1.y, -1 do
for x = pos2.x, pos1.x, -1 do
local distance_sq = (Vector3.new(x, y, z) - centrepoint):length_squared()
local is_in_range = distance_sq < radius_sq
if hollow and distance_sq < radius_inner_sq then
is_in_range = false
end
if is_in_range then
-- It's inside the radius, but we're still not sure given this is a dome and not a sphere
local should_include = false
if x <= centrepoint.x and pointing_dir.x < 0 then
should_include = true
end
if x >= centrepoint.x and pointing_dir.x > 0 then
should_include = true
end
if y <= centrepoint.y and pointing_dir.y < 0 then
should_include = true
end
if y >= centrepoint.y and pointing_dir.y > 0 then
should_include = true
end
if z <= centrepoint.z and pointing_dir.z < 0 then
should_include = true
end
if z >= centrepoint.z and pointing_dir.z > 0 then
should_include = true
end
if should_include then
data[area:index(x, y, z)] = node_id_replace
replaced = replaced + 1
end
end
end
end
end
-- Save the modified nodes back to disk & return
worldedit.manip_helpers.finish(manip, data)
return true, replaced
end

View File

@ -1,3 +1,6 @@
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- ███████ ██ ██ ██ ██████ ███████ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██
-- █████ ██ ██ ██ ██████ ███████ █████
@ -13,12 +16,9 @@
-- @param hollow bool Whether the ellipsoid should be hollow or not.
-- @returns number The number of nodes filled to create the (optionally hollow) ellipsoid. This number will be lower with hollow ellipsoids, since the internals of an ellipsoid aren't altered.
function worldeditadditions.ellipsoid(position, radius, target_node, hollow)
radius = Vector3.clone(radius)
-- position = { x, y, z }
local hollow_inner_radius = {
x = radius.x - 1,
y = radius.y - 1,
z = radius.z - 1
}
local hollow_inner_radius = radius - 1
-- Fetch the nodes in the specified area
-- OPTIMIZE: We should be able to calculate a more efficient box-area here
@ -39,21 +39,19 @@ function worldeditadditions.ellipsoid(position, radius, target_node, hollow)
local i = idx_y_base
for x = -radius.x, radius.x do
local here = Vector3.new(x, y, z)
-- If we're inside the ellipse, then fill it in
local x_comp, y_comp, z_comp = x/radius.x, y/radius.y, z/radius.z
local ellipsoid_dist = x_comp*x_comp + y_comp*y_comp + z_comp*z_comp
local comp = here / radius
local ellipsoid_dist = Vector3.dot(comp, comp)
if ellipsoid_dist <= 1 then
local place_ok = not hollow;
if not place_ok then
-- It must be hollow! Do some additional calculations.
local hx_comp = x/hollow_inner_radius.x
local hy_comp = y/hollow_inner_radius.y
local hz_comp = z/hollow_inner_radius.z
local h_comp = here / hollow_inner_radius
-- It's only ok to place it if it's outside our inner ellipse
place_ok = hx_comp*hx_comp + hy_comp*hy_comp + hz_comp*hz_comp >= 1
place_ok = Vector3.dot(h_comp, h_comp) >= 1
end
if place_ok then

View File

@ -1,4 +1,5 @@
local wea = worldeditadditions
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- ███████ ██ ██ ██ ██████ ███████ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██
@ -8,21 +9,17 @@ local wea = worldeditadditions
function worldeditadditions.ellipsoid2(pos1, pos2, target_node, hollow)
pos1, pos2 = wea.Vector3.sort(pos1, pos2)
local volume = pos2:subtract(pos1)
local volume_half = volume:divide(2)
pos1, pos2 = Vector3.sort(pos1, pos2)
local volume = pos2 - pos1
local volume_half = volume / 2
local radius = pos2:subtract(pos1):divide(2)
local radius = (pos2 - pos1) / 2
print("DEBUG:ellipsoid2 | pos1: "..pos1..", pos2: "..pos2..", target_node: "..target_node)
print("DEBUG:ellipsoid2 radius", radius)
-- print("DEBUG:ellipsoid2 | pos1: "..pos1..", pos2: "..pos2..", target_node: "..target_node)
-- print("DEBUG:ellipsoid2 radius", radius)
-- position = { x, y, z }
local hollow_inner_radius = {
x = radius.x - 1,
y = radius.y - 1,
z = radius.z - 1
}
local hollow_inner_radius = radius - 1
-- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
@ -35,26 +32,23 @@ function worldeditadditions.ellipsoid2(pos1, pos2, target_node, hollow)
for z = pos2.z, pos1.z, -1 do
for y = pos2.y, pos1.y, -1 do
for x = pos2.x, pos1.x, -1 do
local here = Vector3.new(x, y, z)
local pos_relative = (here - pos1) - volume_half
local pos_relative = wea.Vector3.new(x, y, z):subtract(pos1)
:subtract(volume_half)
print("DEBUG pos1", pos1, "pos2", pos2, "volume_half", volume_half, "pos_relative", pos_relative)
-- print("DEBUG pos1", pos1, "pos2", pos2, "volume_half", volume_half, "pos_relative", pos_relative)
-- If we're inside the ellipse, then fill it in
local comp = pos_relative:divide(radius)
local comp = pos_relative / radius
local ellipsoid_dist = comp:length_squared()
if ellipsoid_dist <= 1 then
local place_ok = not hollow;
if not place_ok then
-- It must be hollow! Do some additional calculations.
local hx_comp = x/hollow_inner_radius.x
local hy_comp = y/hollow_inner_radius.y
local hz_comp = z/hollow_inner_radius.z
local h_comp = here / hollow_inner_radius
-- It's only ok to place it if it's outside our inner ellipse
place_ok = hx_comp*hx_comp + hy_comp*hy_comp + hz_comp*hz_comp >= 1
place_ok = Vector3.dot(h_comp, h_comp) >= 1
end
if place_ok then

View File

@ -1,3 +1,6 @@
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- ███████ ██ ██ ██ ██████ ███████ ██████ ██ ██████
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- █████ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██
@ -17,40 +20,29 @@
-- @param {Position} pos2 The 2nd positioon defining the region boundary
-- @param {Function} func The function to call that performs the action in question. It is expected that the given function will accept no arguments.
function worldeditadditions.ellipsoidapply(pos1, pos2, func)
local time_taken_all = worldeditadditions.get_ms_time()
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local time_taken_all = wea_c.get_ms_time()
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
local manip_before, area_before = worldedit.manip_helpers.init(pos1, pos2)
local data_before = manip_before:get_data()
local time_taken_fn = worldeditadditions.get_ms_time()
local time_taken_fn = wea_c.get_ms_time()
func()
time_taken_fn = worldeditadditions.get_ms_time() - time_taken_fn
time_taken_fn = wea_c.get_ms_time() - time_taken_fn
local manip_after, area_after = worldedit.manip_helpers.init(pos1, pos2)
local data_after = manip_after:get_data()
local radius = {
x = (pos2.x - pos1.x) / 2,
y = (pos2.y - pos1.y) / 2,
z = (pos2.z - pos1.z) / 2
}
local e_centre = {
x = pos2.x - radius.x,
y = pos2.y - radius.y,
z = pos2.z - radius.z
}
local radius = (pos2 - pos1) / 2
local e_centre = pos2 - radius
for z = pos2.z, pos1.z, -1 do
for y = pos2.y, pos1.y, -1 do
for x = pos2.x, pos1.x, -1 do
local x_comp = (x - e_centre.x) / radius.x
local y_comp = (y - e_centre.y) / radius.y
local z_comp = (z - e_centre.z) / radius.z
local distance_mult = x_comp*x_comp + y_comp*y_comp + z_comp*z_comp
local comp = (Vector3.new(x, y, z) - e_centre) / radius
local distance_mult = Vector3.dot(comp, comp)
-- Roll everything that's outside the ellipse back
if distance_mult > 1 then
@ -65,6 +57,6 @@ function worldeditadditions.ellipsoidapply(pos1, pos2, func)
worldedit.manip_helpers.finish(manip_after, data_after)
time_taken_all = worldeditadditions.get_ms_time() - time_taken_all
time_taken_all = wea_c.get_ms_time() - time_taken_all
return true, { all = time_taken_all, fn = time_taken_fn }
end

View File

@ -1,4 +1,5 @@
local wea = worldeditadditions
local wea_c = worldeditadditions_core
wea.erode = {}
dofile(wea.modpath.."/lib/erode/snowballs.lua")
@ -18,12 +19,12 @@ function wea.erode.run(pos1, pos2, algorithm, params)
local region_height = (pos2.y - pos1.y) + 1
local heightmap = wea.terrain.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_eroded = wea.table.shallowcopy(heightmap)
local heightmap = wea_c.terrain.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_eroded = wea_c.table.shallowcopy(heightmap)
-- print("[erode.run] algorithm: "..algorithm..", params:");
-- print(wea.format.map(params))
-- wea.format.array_2d(heightmap, heightmap_size.x)
-- print(wea_c.format.map(params))
-- wea_c.format.array_2d(heightmap, heightmap_size.x)
local success, msg, stats
if algorithm == "snowballs" then
success, msg = wea.erode.snowballs(
@ -49,7 +50,7 @@ function wea.erode.run(pos1, pos2, algorithm, params)
return false, "Error: Unknown algorithm '"..algorithm.."'. Currently implemented algorithms: snowballs (2d; hydraulic-like), river (2d; cellular automata-like; fills potholes and lowers towers). Ideas for algorithms to implement are welcome!"
end
success, stats = wea.terrain.apply_heightmap_changes(
success, stats = wea_c.terrain.apply_heightmap_changes(
pos1, pos2, area, data,
heightmap, heightmap_eroded, heightmap_size
)

View File

@ -1,12 +1,13 @@
local wea = worldeditadditions
local wea_c = worldeditadditions_core
--- Parses a comma-separated side numbers list out into a list of numbers.
-- @param list string The command separated list to parse.
-- @returns number[] A list of side numbers.
local function parse_sides_list(list)
list = list:gsub("%s", "") -- Spaces are not permitted
return wea.table.unique(wea.table.map(
wea.split(list, ","),
return wea_c.table.unique(wea_c.table.map(
wea_c.split(list, ","),
function(value) return tonumber(value) end
))
end
@ -20,7 +21,7 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
dolower = true -- Whether to do lower operations or not
}
-- Apply the custom settings
wea.table.apply(params_custom, params)
wea_c.table.apply(params_custom, params)
params.lower_sides = parse_sides_list(params.lower_sides)
params.raise_sides = parse_sides_list(params.raise_sides)
@ -30,8 +31,8 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
local removed = 0
for i=1,params.steps do
-- print("[DEBUG:river] step ", i)
-- wea.format.array_2d(heightmap, heightmap_size.x)
local time_start = wea.get_ms_time()
-- wea_c.format.array_2d(heightmap, heightmap_size.x)
local time_start = wea_c.get_ms_time()
-- Store up changes to make and make them at the end of the step
-- This is important, because decisions
@ -105,7 +106,7 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
removed = removed + 1
end
-- print("[DEBUG:river] sides_higher", sides_higher, "sides_lower", sides_lower, "action", action)
-- wea.format.array_2d(heightmap, heightmap_size.x)
-- wea_c.format.array_2d(heightmap, heightmap_size.x)
end
end
@ -116,8 +117,8 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
heightmap[hi] = heightmap[hi] - 1
end
table.insert(timings, wea.get_ms_time() - time_start)
table.insert(timings, wea_c.get_ms_time() - time_start)
end
return true, params.steps.." steps made, raising "..filled.." and lowering "..removed.." columns in "..wea.format.human_time(wea.sum(timings)).." (~"..wea.format.human_time(wea.average(timings)).." per step)"
return true, params.steps.." steps made, raising "..filled.." and lowering "..removed.." columns in "..wea_c.format.human_time(wea_c.sum(timings)).." (~"..wea_c.format.human_time(wea_c.average(timings)).." per step)"
end

View File

@ -1,16 +1,19 @@
local wea = worldeditadditions
local Vector3 = wea.Vector3
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
-- Test command: //multi //fp set1 1313 6 5540 //fp set2 1338 17 5521 //erode snowballs
local function snowball(heightmap, normalmap, heightmap_size, startpos, params)
local sediment = 0
local pos = { x = startpos.x, z = startpos.z }
local pos_prev = { x = pos.x, z = pos.z }
local velocity = {
x = (math.random() * 2 - 1) * params.init_velocity,
z = (math.random() * 2 - 1) * params.init_velocity
}
local pos = Vector3.new(startpos.x, 0, startpos.z) -- X/Z
local pos_prev = Vector3.new(pos.x, 0, pos.z) -- X/Z
local velocity = Vector3.new(
(math.random() * 2 - 1) * params.init_velocity,
0,
(math.random() * 2 - 1) * params.init_velocity
) -- X/Z
local heightmap_length = #heightmap
-- print("[snowball] startpos ("..pos.x..", "..pos.z.."), velocity: ("..velocity.x..", "..velocity.z..")")
@ -29,7 +32,7 @@ local function snowball(heightmap, normalmap, heightmap_size, startpos, params)
end
if #hist_velocity > 0 and i > 5
and wea.average(hist_velocity) < 0.03 then
and wea_c.average(hist_velocity) < 0.03 then
-- print("[snowball] It looks like we've stopped")
return true, i
end
@ -50,13 +53,13 @@ local function snowball(heightmap, normalmap, heightmap_size, startpos, params)
end
velocity.x = params.friction * velocity.x + normalmap[hi].x * params.speed
velocity.y = 0 -- Just in case
velocity.z = params.friction * velocity.z + normalmap[hi].y * params.speed
-- print("[snowball] now at ("..x..", "..z..") velocity "..wea.vector.lengthsquared(velocity)..", sediment "..sediment)
local new_vel_sq = wea.vector.lengthsquared(velocity)
-- print("[snowball] now at ("..x..", "..z..") velocity "..velocity:length_squared()..", sediment "..sediment)
local new_vel_sq = velocity:length_squared()
if new_vel_sq > 1 then
-- print("[snowball] velocity squared over 1, normalising")
velocity = wea.vector.normalize(velocity)
velocity = velocity:normalise()
end
table.insert(hist_velocity, new_vel_sq)
if #hist_velocity > params.velocity_hist_count then table.remove(hist_velocity, 1) end
@ -89,12 +92,12 @@ function wea.erode.snowballs(heightmap_initial, heightmap, heightmap_size, regio
count = 25000
}
-- Apply the custom settings
wea.table.apply(params_custom, params)
wea_c.table.apply(params_custom, params)
-- print("[erode/snowballs] params: ")
-- print(wea.format.map(params))
-- print(wea_c.format.map(params))
local normals = wea.terrain.calculate_normals(heightmap, heightmap_size)
local normals = wea_c.terrain.calculate_normals(heightmap, heightmap_size)
local stats_steps = {}
for i = 1, params.count do
@ -142,5 +145,5 @@ function wea.erode.snowballs(heightmap_initial, heightmap, heightmap_size, regio
)
end
return true, ""..#stats_steps.." snowballs simulated, max "..params.max_steps.." steps (averaged ~"..wea.average(stats_steps).." steps)"
return true, ""..#stats_steps.." snowballs simulated, max "..params.max_steps.." steps (averaged ~"..wea_c.average(stats_steps).." steps)"
end

View File

@ -1,8 +1,14 @@
--- Overlap command. Places a specified node on top of each column.
-- @module worldeditadditions.overlay
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
--- Fill caves command. Fills underneath non-air nodes in the defined region.
-- @param pos1 Vector3 pos1 of the defined region to fill caves in.
-- @param pos2 Vector3 pos2 of the defined region to fill caves in.
-- @param node_name string The name of the node to replace air nodes with. Should have been already normalised, as with all other worldeditadditions.* functions.
-- @returns bool,{replaced=number} 1. Whether the fill caves operation was successful or not.
-- 2. A table of statistics about the operation. Currently the only key in this table is `replaced`, which is the number of (air-like) nodes that were replaced during the operation.
function worldeditadditions.fillcaves(pos1, pos2, node_name)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
@ -12,8 +18,8 @@ function worldeditadditions.fillcaves(pos1, pos2, node_name)
local node_id_replace = minetest.get_content_id(node_name)
local node_id_ignore = minetest.get_content_id("ignore")
-- minetest.log("action", "pos1: " .. worldeditadditions.vector.tostring(pos1))
-- minetest.log("action", "pos2: " .. worldeditadditions.vector.tostring(pos2))
-- minetest.log("action", "pos1: " .. pos1)
-- minetest.log("action", "pos2: " .. pos2)
-- z y x is the preferred loop order, but that isn't really possible here
@ -27,7 +33,7 @@ function worldeditadditions.fillcaves(pos1, pos2, node_name)
for y = pos2.y, pos1.y, -1 do
local i = area:index(x, y, z)
local is_air = worldeditadditions.is_airlike(data[i]) or worldeditadditions.is_liquidlike(data[i])
local is_air = wea_c.is_airlike(data[i]) or wea_c.is_liquidlike(data[i])
local is_ignore = data[i] == node_id_ignore
-- If the previous node was air and this one isn't, then we've found the top level

View File

@ -1,13 +1,19 @@
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
--- Flood-fill command for complex lakes etc.
-- @module worldeditadditions.floodfill
local wea = worldeditadditions
-- @param start_pos Vector3 The position to start floodfilling from.
-- @param radius number The maximum radius to limit the floodfill operation too.
-- @param replace_node string The (normalised) name of the node to replace with when floodfilling.
-- @returns number The number of nodes replaced.
function worldeditadditions.floodfill(start_pos, radius, replace_node)
start_pos = Vector3.clone(start_pos)
-- Calculate the area we want to modify
local pos1 = vector.add(start_pos, { x = radius, y = 0, z = radius })
local pos2 = vector.subtract(start_pos, { x = radius, y = radius, z = radius })
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local pos1 = start_pos + Vector3.new(radius, 0, radius)
local pos2 = start_pos - Vector3.new(radius, radius, radius)
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
@ -27,7 +33,7 @@ function worldeditadditions.floodfill(start_pos, radius, replace_node)
end
local count = 0
local remaining_nodes = wea.Queue.new() remaining_nodes:enqueue(start_pos_index)
local remaining_nodes = wea_c.Queue.new() remaining_nodes:enqueue(start_pos_index)
-- Do the floodfill
while remaining_nodes:is_empty() == false do
@ -41,35 +47,35 @@ function worldeditadditions.floodfill(start_pos, radius, replace_node)
-- We don't need to go upwards here, since we're filling in lake-style
local xplus = cur + 1 -- +X
if data[xplus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(xplus), start_pos)) < radius_sq and
(Vector3.clone(area:position(xplus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(xplus) then
-- minetest.log("action", "[floodfill] [+X] index " .. xplus .. " is a " .. data[xplus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(xplus)
end
local xminus = cur - 1 -- -X
if data[xminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(xminus), start_pos)) < radius_sq and
(Vector3.clone(area:position(xminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(xminus) then
-- minetest.log("action", "[floodfill] [-X] index " .. xminus .. " is a " .. data[xminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(xminus)
end
local zplus = cur + area.zstride -- +Z
if data[zplus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(zplus), start_pos)) < radius_sq and
(Vector3.clone(area:position(zplus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(zplus) then
-- minetest.log("action", "[floodfill] [+Z] index " .. zplus .. " is a " .. data[zplus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(zplus)
end
local zminus = cur - area.zstride -- -Z
if data[zminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(zminus), start_pos)) < radius_sq and
(Vector3.clone(area:position(zminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(zminus) then
-- minetest.log("action", "[floodfill] [-Z] index " .. zminus .. " is a " .. data[zminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(zminus)
end
local yminus = cur - area.ystride -- -Y
if data[yminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(yminus), start_pos)) < radius_sq and
(Vector3.clone(area:position(yminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(yminus) then
-- minetest.log("action", "[floodfill] [-Y] index " .. yminus .. " is a " .. data[yminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(yminus)

Some files were not shown because too many files have changed in this diff Show More