Skip to content

Commit b29523d

Browse files
committedMar 12, 2014
Implement full size checking for every possible command.
1 parent 0dddffa commit b29523d

File tree

2 files changed

+303
-274
lines changed

2 files changed

+303
-274
lines changed
 

‎worldedit_commands/init.lua

+246-274
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ if minetest.place_schematic then
1313
end
1414

1515
dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua")
16+
dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua")
1617

1718
local get_position = function(name)
1819
local pos1 = worldedit.pos1[name]
@@ -31,71 +32,6 @@ local get_node = function(name, nodename)
3132
return node
3233
end
3334

34-
35-
--`callback` is a callback to run when the user confirms
36-
--`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed
37-
local safe_region
38-
do --safe region wrapper function
39-
local safe_region_callback
40-
local safe_region_name
41-
local safe_region_param
42-
safe_region = function(callback, nodes_needed)
43-
nodes_needed = nodes_needed or worldedit.volume
44-
return function(name, param)
45-
--obtain positions
46-
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
47-
if pos1 == nil or pos2 == nil then
48-
worldedit.player_notify(name, "no region selected")
49-
return nil
50-
end
51-
52-
--check volume
53-
local count = nodes_needed(pos1, pos2, name, param)
54-
if not count or count < 10000 then
55-
return callback(name, param, pos1, pos2)
56-
end
57-
58-
--save callback to call later
59-
safe_region_callback, safe_region_name, safe_region_param = callback, name, param
60-
worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel")
61-
end
62-
end
63-
64-
minetest.register_chatcommand("/y", {
65-
params = "",
66-
description = "Confirm a pending operation",
67-
func = function()
68-
local callback, name, param = safe_region_callback, safe_region_name, safe_region_param
69-
if not callback then
70-
worldedit.player_notify(name, "no operation pending")
71-
return
72-
end
73-
74-
--obtain positions
75-
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
76-
if pos1 == nil or pos2 == nil then
77-
worldedit.player_notify(name, "no region selected")
78-
return
79-
end
80-
81-
safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil --reset pending operation
82-
callback(name, param, pos1, pos2)
83-
end,
84-
})
85-
86-
minetest.register_chatcommand("/n", {
87-
params = "",
88-
description = "Confirm a pending operation",
89-
func = function()
90-
if not safe_region_callback then
91-
worldedit.player_notify(name, "no operation pending")
92-
return
93-
end
94-
safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil
95-
end,
96-
})
97-
end
98-
9935
worldedit.player_notify = function(name, message)
10036
minetest.chat_send_player(name, "WorldEdit -!- " .. message, false)
10137
end
@@ -135,7 +71,16 @@ worldedit.player_axis = function(name)
13571
return "z", dir.z > 0 and 1 or -1
13672
end
13773

74+
local check_region = function(name, param)
75+
--obtain positions
76+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
77+
if pos1 == nil or pos2 == nil then
78+
worldedit.player_notify(name, "no region selected")
79+
return nil
80+
end
13881

82+
return worldedit.volume(pos1, pos2)
83+
end
13984

14085
minetest.register_chatcommand("/about", {
14186
params = "",
@@ -344,259 +289,270 @@ minetest.register_chatcommand("/volume", {
344289
end,
345290
})
346291

292+
local check_set = function(name, param)
293+
local node = get_node(name, param)
294+
if not node then return nil end
295+
return check_region(name, param)
296+
end
297+
347298
minetest.register_chatcommand("/set", {
348299
params = "<node>",
349300
description = "Set the current WorldEdit region to <node>",
350301
privs = {worldedit=true},
351-
func = safe_region(function(name, param, pos1, pos2)
302+
func = safe_region(function(name, param)
303+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
352304
local node = get_node(name, param)
353-
if not node then return end
354-
355305
local count = worldedit.set(pos1, pos2, node)
356306
worldedit.player_notify(name, count .. " nodes set")
357-
end),
307+
end, check_set),
358308
})
359309

310+
local check_replace = function(name, param)
311+
local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")
312+
if found == nil then
313+
worldedit.player_notify(name, "invalid usage: " .. param)
314+
return nil
315+
end
316+
local newsearchnode = worldedit.normalize_nodename(searchnode)
317+
if not newsearchnode then
318+
worldedit.player_notify(name, "invalid search node name: " .. searchnode)
319+
return nil
320+
end
321+
local newreplacenode = worldedit.normalize_nodename(replacenode)
322+
if not newreplacenode then
323+
worldedit.player_notify(name, "invalid replace node name: " .. replacenode)
324+
return nil
325+
end
326+
return check_region(name, param)
327+
end
328+
360329
minetest.register_chatcommand("/replace", {
361330
params = "<search node> <replace node>",
362331
description = "Replace all instances of <search node> with <replace node> in the current WorldEdit region",
363332
privs = {worldedit=true},
364-
func = safe_region(function(name, param, pos1, pos2)
333+
func = safe_region(function(name, param)
334+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
365335
local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")
366-
if found == nil then
367-
worldedit.player_notify(name, "invalid usage: " .. param)
368-
return
369-
end
370336
local newsearchnode = worldedit.normalize_nodename(searchnode)
371-
if not newsearchnode then
372-
worldedit.player_notify(name, "invalid search node name: " .. searchnode)
373-
return
374-
end
375337
local newreplacenode = worldedit.normalize_nodename(replacenode)
376-
if not newreplacenode then
377-
worldedit.player_notify(name, "invalid replace node name: " .. replacenode)
378-
return
379-
end
380-
381338
local count = worldedit.replace(pos1, pos2, newsearchnode, newreplacenode)
382339
worldedit.player_notify(name, count .. " nodes replaced")
383-
end),
340+
end, check_replace),
384341
})
385342

386343
minetest.register_chatcommand("/replaceinverse", {
387344
params = "<search node> <replace node>",
388345
description = "Replace all nodes other than <search node> with <replace node> in the current WorldEdit region",
389346
privs = {worldedit=true},
390-
func = safe_region(function(name, param, pos1, pos2)
347+
func = safe_region(function(name, param)
348+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
391349
local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$")
392-
if found == nil then
393-
worldedit.player_notify(name, "invalid usage: " .. param)
394-
return
395-
end
396350
local newsearchnode = worldedit.normalize_nodename(searchnode)
397-
if not newsearchnode then
398-
worldedit.player_notify(name, "invalid search node name: " .. searchnode)
399-
return
400-
end
401351
local newreplacenode = worldedit.normalize_nodename(replacenode)
402-
if not newreplacenode then
403-
worldedit.player_notify(name, "invalid replace node name: " .. replacenode)
404-
return
405-
end
406-
407352
local count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode)
408353
worldedit.player_notify(name, count .. " nodes replaced")
409-
end),
354+
end, check_replace),
410355
})
411356

357+
local check_sphere = function(name, param)
358+
if worldedit.pos1[name] == nil then
359+
worldedit.player_notify(name, "no position 1 selected")
360+
return nil
361+
end
362+
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
363+
if found == nil then
364+
worldedit.player_notify(name, "invalid usage: " .. param)
365+
return nil
366+
end
367+
local node = get_node(name, nodename)
368+
if not node then return nil end
369+
return math.ceil((4 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of sphere
370+
end
371+
412372
minetest.register_chatcommand("/hollowsphere", {
413373
params = "<radius> <node>",
414374
description = "Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>",
415375
privs = {worldedit=true},
416-
func = function(name, param)
417-
local pos = get_position(name)
418-
if pos == nil then return end
419-
376+
func = safe_region(function(name, param)
377+
local pos = worldedit.pos1[name]
420378
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
421-
if found == nil then
422-
worldedit.player_notify(name, "invalid usage: " .. param)
423-
return
424-
end
425379
local node = get_node(name, nodename)
426-
if not node then return end
427-
428380
local count = worldedit.hollow_sphere(pos, tonumber(radius), node)
429381
worldedit.player_notify(name, count .. " nodes added")
430-
end,
382+
end, check_sphere),
431383
})
432384

433385
minetest.register_chatcommand("/sphere", {
434386
params = "<radius> <node>",
435387
description = "Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>",
436388
privs = {worldedit=true},
437-
func = function(name, param)
438-
local pos = get_position(name)
439-
if pos == nil then return end
440-
389+
func = safe_region(function(name, param)
390+
local pos = worldedit.pos1[name]
441391
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
442-
if found == nil then
443-
worldedit.player_notify(name, "invalid usage: " .. param)
444-
return
445-
end
446392
local node = get_node(name, nodename)
447-
if not node then return end
448-
449393
local count = worldedit.sphere(pos, tonumber(radius), node)
450394
worldedit.player_notify(name, count .. " nodes added")
451-
end,
395+
end, check_sphere),
452396
})
453397

398+
local check_dome = function(name, param)
399+
if worldedit.pos1[name] == nil then
400+
worldedit.player_notify(name, "no position 1 selected")
401+
return nil
402+
end
403+
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
404+
if found == nil then
405+
worldedit.player_notify(name, "invalid usage: " .. param)
406+
return nil
407+
end
408+
local node = get_node(name, nodename)
409+
if not node then return nil end
410+
return math.ceil((2 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of dome
411+
end
412+
454413
minetest.register_chatcommand("/hollowdome", {
455414
params = "<radius> <node>",
456415
description = "Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>",
457416
privs = {worldedit=true},
458-
func = function(name, param)
459-
local pos = get_position(name)
460-
if pos == nil then return end
461-
462-
local found, _, radius, nodename = param:find("^([+-]?%d+)%s+(.+)$")
463-
if found == nil then
464-
worldedit.player_notify(name, "invalid usage: " .. param)
465-
return
466-
end
417+
func = safe_region(function(name, param)
418+
local pos = worldedit.pos1[name]
419+
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
467420
local node = get_node(name, nodename)
468-
if not node then return end
469-
470421
local count = worldedit.hollow_dome(pos, tonumber(radius), node)
471422
worldedit.player_notify(name, count .. " nodes added")
472-
end,
423+
end, check_dome),
473424
})
474425

475426
minetest.register_chatcommand("/dome", {
476427
params = "<radius> <node>",
477428
description = "Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>",
478429
privs = {worldedit=true},
479-
func = function(name, param)
480-
local pos = get_position(name)
481-
if pos == nil then return end
482-
483-
local found, _, radius, nodename = param:find("^([+-]?%d+)%s+(.+)$")
484-
if found == nil then
485-
worldedit.player_notify(name, "invalid usage: " .. param)
486-
return
487-
end
430+
func = safe_region(function(name, param)
431+
local pos = worldedit.pos1[name]
432+
local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$")
488433
local node = get_node(name, nodename)
489-
if not node then return end
490-
491434
local count = worldedit.dome(pos, tonumber(radius), node)
492435
worldedit.player_notify(name, count .. " nodes added")
493-
end,
436+
end, check_dome),
494437
})
495438

439+
local check_cylinder = function(name, param)
440+
if worldedit.pos1[name] == nil then
441+
worldedit.player_notify(name, "no position 1 selected")
442+
return nil
443+
end
444+
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
445+
if found == nil then
446+
worldedit.player_notify(name, "invalid usage: " .. param)
447+
return nil
448+
end
449+
local node = get_node(name, nodename)
450+
if not node then return nil end
451+
return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length))
452+
end
453+
496454
minetest.register_chatcommand("/hollowcylinder", {
497455
params = "x/y/z/? <length> <radius> <node>",
498456
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
499457
privs = {worldedit=true},
500-
func = function(name, param)
501-
local pos = get_position(name)
502-
if pos == nil then return end
503-
458+
func = safe_region(function(name, param)
459+
local pos = worldedit.pos1[name]
504460
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
505-
if found == nil then
506-
worldedit.player_notify(name, "invalid usage: " .. param)
507-
return
508-
end
509-
length, radius = tonumber(length), tonumber(radius)
461+
length = tonumber(length)
510462
if axis == "?" then
511463
axis, sign = worldedit.player_axis(name)
512464
length = length * sign
513465
end
514466
local node = get_node(name, nodename)
515-
if not node then return end
516-
517-
local count = worldedit.hollow_cylinder(pos, axis, length, radius, node)
467+
local count = worldedit.hollow_cylinder(pos, axis, length, tonumber(radius), node)
518468
worldedit.player_notify(name, count .. " nodes added")
519-
end,
469+
end, check_cylinder),
520470
})
521471

522472
minetest.register_chatcommand("/cylinder", {
523473
params = "x/y/z/? <length> <radius> <node>",
524474
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
525475
privs = {worldedit=true},
526-
func = function(name, param)
527-
local pos = get_position(name)
528-
if pos == nil then return end
529-
476+
func = safe_region(function(name, param)
477+
local pos = worldedit.pos1[name]
530478
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$")
531-
if found == nil then
532-
worldedit.player_notify(name, "invalid usage: " .. param)
533-
return
534-
end
535-
length, radius = tonumber(length), tonumber(radius)
479+
length = tonumber(length)
536480
if axis == "?" then
537481
axis, sign = worldedit.player_axis(name)
538482
length = length * sign
539483
end
540484
local node = get_node(name, nodename)
541-
if not node then return end
542-
543-
local count = worldedit.cylinder(pos, axis, length, radius, node)
485+
local count = worldedit.cylinder(pos, axis, length, tonumber(radius), node)
544486
worldedit.player_notify(name, count .. " nodes added")
545-
end,
487+
end, check_cylinder),
546488
})
547489

548490
minetest.register_chatcommand("/pyramid", {
549491
params = "x/y/z/? <height> <node>",
550492
description = "Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>",
551493
privs = {worldedit=true},
552-
func = function(name, param)
494+
func = safe_region(function(name, param)
553495
local pos = get_position(name)
554-
if pos == nil then return end
555-
556496
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
557-
if found == nil then
558-
worldedit.player_notify(name, "invalid usage: " .. param)
559-
return
560-
end
561497
height = tonumber(height)
562498
if axis == "?" then
563499
axis, sign = worldedit.player_axis(name)
564500
height = height * sign
565501
end
566502
local node = get_node(name, nodename)
567-
if not node then return end
568-
569503
local count = worldedit.pyramid(pos, axis, height, node)
570504
worldedit.player_notify(name, count .. " nodes added")
571505
end,
506+
function(name, param)
507+
if worldedit.pos1[name] == nil then
508+
worldedit.player_notify(name, "no position 1 selected")
509+
return nil
510+
end
511+
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
512+
if found == nil then
513+
worldedit.player_notify(name, "invalid usage: " .. param)
514+
return nil
515+
end
516+
local node = get_node(name, nodename)
517+
if not node then return nil end
518+
height = tonumber(height)
519+
return math.ceil(((height * 2 + 1) ^ 2) * height / 3)
520+
end),
572521
})
573522

574523
minetest.register_chatcommand("/spiral", {
575524
params = "<length> <height> <space> <node>",
576525
description = "Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>",
577526
privs = {worldedit=true},
578-
func = function(name, param)
579-
local pos = get_position(name)
580-
if pos == nil then return end
581-
527+
func = safe_region(function(name, param)
528+
local pos = worldedit.pos1[name]
582529
local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
583-
if found == nil then
584-
worldedit.player_notify(name, "invalid usage: " .. param)
585-
return
586-
end
587530
local node = get_node(name, nodename)
588-
if not node then return end
589-
590531
local count = worldedit.spiral(pos, tonumber(length), tonumber(height), tonumber(space), node)
591532
worldedit.player_notify(name, count .. " nodes added")
592533
end,
534+
function(name, param)
535+
if worldedit.pos1[name] == nil then
536+
worldedit.player_notify(name, "no position 1 selected")
537+
return nil
538+
end
539+
local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
540+
if found == nil then
541+
worldedit.player_notify(name, "invalid usage: " .. param)
542+
return nil
543+
end
544+
local node = get_node(name, nodename)
545+
if not node then return nil end
546+
return check_region(name, param)
547+
end),
593548
})
594549

595550
minetest.register_chatcommand("/copy", {
596551
params = "x/y/z/? <amount>",
597552
description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
598553
privs = {worldedit=true},
599-
func = safe_region(function(name, param, pos1, pos2)
554+
func = safe_region(function(name, param)
555+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
600556
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
601557
if found == nil then
602558
worldedit.player_notify(name, "invalid usage: " .. param)
@@ -610,14 +566,19 @@ minetest.register_chatcommand("/copy", {
610566

611567
local count = worldedit.copy(pos1, pos2, axis, amount)
612568
worldedit.player_notify(name, count .. " nodes copied")
569+
end,
570+
function(name, param)
571+
local volume = check_region(name, param)
572+
return volume and volume * 2 or volume
613573
end),
614574
})
615575

616576
minetest.register_chatcommand("/move", {
617577
params = "x/y/z/? <amount>",
618578
description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
619579
privs = {worldedit=true},
620-
func = safe_region(function(name, param, pos1, pos2)
580+
func = safe_region(function(name, param)
581+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
621582
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
622583
if found == nil then
623584
worldedit.player_notify(name, "invalid usage: " .. param)
@@ -636,51 +597,43 @@ minetest.register_chatcommand("/move", {
636597
worldedit.mark_pos1(name)
637598
worldedit.mark_pos2(name)
638599
worldedit.player_notify(name, count .. " nodes moved")
639-
end),
600+
end, check_region),
640601
})
641602

642603
minetest.register_chatcommand("/stack", {
643604
params = "x/y/z/? <count>",
644605
description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",
645606
privs = {worldedit=true},
646-
func = safe_region(function(name, param, pos1, pos2)
607+
func = safe_region(function(name, param)
608+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
647609
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
648-
if found == nil then
649-
worldedit.player_notify(name, "invalid usage: " .. param)
650-
return
651-
end
652610
repetitions = tonumber(repetitions)
653611
if axis == "?" then
654612
axis, sign = worldedit.player_axis(name)
655613
repetitions = repetitions * sign
656614
end
657-
658615
local count = worldedit.stack(pos1, pos2, axis, repetitions)
659616
worldedit.player_notify(name, count .. " nodes stacked")
660617
end,
661-
function(pos1, pos2, name, param)
618+
function(name, param)
662619
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
663-
if found then
664-
return tonumber(repetitions) * worldedit.volume(pos1, pos2)
620+
if found == nil then
621+
worldedit.player_notify(name, "invalid usage: " .. param)
665622
end
623+
local count = check_region(name, param)
624+
if count then return (tonumber(repetitions) + 1) * count end
625+
return nil
666626
end),
667627
})
668628

669629
minetest.register_chatcommand("/stretch", {
670630
params = "<stretchx> <stretchy> <stretchz>",
671631
description = "Scale the current WorldEdit positions and region by a factor of <stretchx>, <stretchy>, <stretchz> along the X, Y, and Z axes, repectively, with position 1 as the origin",
672632
privs = {worldedit=true},
673-
func = safe_region(function(name, param, pos1, pos2)
633+
func = safe_region(function(name, param)
634+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
674635
local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$")
675-
if found == nil then
676-
worldedit.player_notify(name, "invalid usage: " .. param)
677-
return
678-
end
679636
stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)
680-
if stretchx == 0 or stretchy == 0 or stretchz == 0 then
681-
worldedit.player_notify(name, "invalid scaling factors: " .. param)
682-
end
683-
684637
local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)
685638

686639
--reset markers to scaled positions
@@ -691,35 +644,31 @@ minetest.register_chatcommand("/stretch", {
691644

692645
worldedit.player_notify(name, count .. " nodes stretched")
693646
end,
694-
function(pos1, pos2, name, param)
647+
function(name, param)
695648
local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$")
696-
if found then
697-
return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * worldedit.volume(pos1, pos2)
649+
if found == nil then
650+
worldedit.player_notify(name, "invalid usage: " .. param)
651+
return nil
698652
end
653+
stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)
654+
if stretchx == 0 or stretchy == 0 or stretchz == 0 then
655+
worldedit.player_notify(name, "invalid scaling factors: " .. param)
656+
end
657+
local count = check_region(name, param)
658+
if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end
659+
return nil
699660
end),
700661
})
701662

702663
minetest.register_chatcommand("/transpose", {
703664
params = "x/y/z/? x/y/z/?",
704665
description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",
705666
privs = {worldedit=true},
706-
func = safe_region(function(name, param, pos1, pos2)
667+
func = safe_region(function(name, param)
668+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
707669
local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")
708-
if found == nil then
709-
worldedit.player_notify(name, "invalid usage: " .. param)
710-
return
711-
end
712-
if axis1 == "?" then
713-
axis1 = worldedit.player_axis(name)
714-
end
715-
if axis2 == "?" then
716-
axis2 = worldedit.player_axis(name)
717-
end
718-
if axis1 == axis2 then
719-
worldedit.player_notify(name, "invalid usage: axes must be different")
720-
return
721-
end
722-
670+
if axis1 == "?" then axis1 = worldedit.player_axis(name) end
671+
if axis2 == "?" then axis2 = worldedit.player_axis(name) end
723672
local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
724673

725674
--reset markers to transposed positions
@@ -729,45 +678,48 @@ minetest.register_chatcommand("/transpose", {
729678
worldedit.mark_pos2(name)
730679

731680
worldedit.player_notify(name, count .. " nodes transposed")
681+
end,
682+
function(name, param)
683+
local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")
684+
if found == nil then
685+
worldedit.player_notify(name, "invalid usage: " .. param)
686+
return nil
687+
end
688+
if axis1 == axis2 then
689+
worldedit.player_notify(name, "invalid usage: axes must be different")
690+
return nil
691+
end
692+
return check_region(name, param)
732693
end),
733694
})
734695

735696
minetest.register_chatcommand("/flip", {
736697
params = "x/y/z/?",
737698
description = "Flip the current WorldEdit region along the x/y/z/? axis",
738699
privs = {worldedit=true},
739-
func = safe_region(function(name, param, pos1, pos2)
740-
if param == "?" then
741-
param = worldedit.player_axis(name)
742-
end
743-
if param ~= "x" and param ~= "y" and param ~= "z" then
744-
worldedit.player_notify(name, "invalid usage: " .. param)
745-
return
746-
end
747-
700+
func = safe_region(function(name, param)
701+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
702+
if param == "?" then param = worldedit.player_axis(name) end
748703
local count = worldedit.flip(pos1, pos2, param)
749704
worldedit.player_notify(name, count .. " nodes flipped")
705+
end,
706+
function(name, param)
707+
if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then
708+
worldedit.player_notify(name, "invalid usage: " .. param)
709+
return nil
710+
end
711+
return check_region(name, param)
750712
end),
751713
})
752714

753715
minetest.register_chatcommand("/rotate", {
754716
params = "<axis> <angle>",
755717
description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",
756718
privs = {worldedit=true},
757-
func = safe_region(function(name, param, pos1, pos2)
719+
func = safe_region(function(name, param)
720+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
758721
local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
759-
if found == nil then
760-
worldedit.player_notify(name, "invalid usage: " .. param)
761-
return
762-
end
763-
if axis == "?" then
764-
axis = worldedit.player_axis(name)
765-
end
766-
if angle % 90 ~= 0 then
767-
worldedit.player_notify(name, "invalid usage: angle must be multiple of 90")
768-
return
769-
end
770-
722+
if axis == "?" then axis = worldedit.player_axis(name) end
771723
local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle)
772724

773725
--reset markers to rotated positions
@@ -777,35 +729,51 @@ minetest.register_chatcommand("/rotate", {
777729
worldedit.mark_pos2(name)
778730

779731
worldedit.player_notify(name, count .. " nodes rotated")
732+
end,
733+
function(name, param)
734+
local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
735+
if found == nil then
736+
worldedit.player_notify(name, "invalid usage: " .. param)
737+
return nil
738+
end
739+
if angle % 90 ~= 0 then
740+
worldedit.player_notify(name, "invalid usage: angle must be multiple of 90")
741+
return nil
742+
end
743+
return check_region(name, param)
780744
end),
781745
})
782746

783747
minetest.register_chatcommand("/orient", {
784748
params = "<angle>",
785749
description = "Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)",
786750
privs = {worldedit=true},
787-
func = safe_region(function(name, param, pos1, pos2)
751+
func = safe_region(function(name, param)
752+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
753+
local found, _, angle = param:find("^([+-]?%d+)$")
754+
local count = worldedit.orient(pos1, pos2, angle)
755+
worldedit.player_notify(name, count .. " nodes oriented")
756+
end,
757+
function(name, param)
788758
local found, _, angle = param:find("^([+-]?%d+)$")
789759
if found == nil then
790760
worldedit.player_notify(name, "invalid usage: " .. param)
791-
return
761+
return nil
792762
end
793763
if angle % 90 ~= 0 then
794764
worldedit.player_notify(name, "invalid usage: angle must be multiple of 90")
795-
return
765+
return nil
796766
end
797-
798-
local count = worldedit.orient(pos1, pos2, angle)
799-
800-
worldedit.player_notify(name, count .. " nodes oriented")
767+
return check_region(name, param)
801768
end),
802769
})
803770

804771
minetest.register_chatcommand("/fixlight", {
805772
params = "",
806773
description = "Fix the lighting in the current WorldEdit region",
807774
privs = {worldedit=true},
808-
func = safe_region(function(name, param, pos1, pos2)
775+
func = safe_region(function(name, param)
776+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
809777
local count = worldedit.fixlight(pos1, pos2)
810778
worldedit.player_notify(name, count .. " nodes updated")
811779
end),
@@ -815,7 +783,8 @@ minetest.register_chatcommand("/hide", {
815783
params = "",
816784
description = "Hide all nodes in the current WorldEdit region non-destructively",
817785
privs = {worldedit=true},
818-
func = safe_region(function(name, param, pos1, pos2)
786+
func = safe_region(function(name, param)
787+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
819788
local count = worldedit.hide(pos1, pos2)
820789
worldedit.player_notify(name, count .. " nodes hidden")
821790
end),
@@ -825,33 +794,32 @@ minetest.register_chatcommand("/suppress", {
825794
params = "<node>",
826795
description = "Suppress all <node> in the current WorldEdit region non-destructively",
827796
privs = {worldedit=true},
828-
func = safe_region(function(name, param, pos1, pos2)
797+
func = safe_region(function(name, param)
798+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
829799
local node = get_node(name, param)
830-
if not node then return end
831-
832800
local count = worldedit.suppress(pos1, pos2, node)
833801
worldedit.player_notify(name, count .. " nodes suppressed")
834-
end),
802+
end, check_set),
835803
})
836804

837805
minetest.register_chatcommand("/highlight", {
838806
params = "<node>",
839807
description = "Highlight <node> in the current WorldEdit region by hiding everything else non-destructively",
840808
privs = {worldedit=true},
841-
func = safe_region(function(name, param, pos1, pos2)
809+
func = safe_region(function(name, param)
810+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
842811
local node = get_node(name, param)
843-
if not node then return end
844-
845812
local count = worldedit.highlight(pos1, pos2, node)
846813
worldedit.player_notify(name, count .. " nodes highlighted")
847-
end),
814+
end, check_set),
848815
})
849816

850817
minetest.register_chatcommand("/restore", {
851818
params = "",
852819
description = "Restores nodes hidden with WorldEdit in the current WorldEdit region",
853820
privs = {worldedit=true},
854-
func = safe_region(function(name, param, pos1, pos2)
821+
func = safe_region(function(name, param)
822+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
855823
local count = worldedit.restore(pos1, pos2)
856824
worldedit.player_notify(name, count .. " nodes restored")
857825
end),
@@ -861,7 +829,8 @@ minetest.register_chatcommand("/save", {
861829
params = "<file>",
862830
description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",
863831
privs = {worldedit=true},
864-
func = safe_region(function(name, param, pos1, pos2)
832+
func = safe_region(function(name, param)
833+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
865834
if param == "" then
866835
worldedit.player_notify(name, "invalid usage: " .. param)
867836
return
@@ -1002,7 +971,8 @@ minetest.register_chatcommand("/luatransform", {
1002971
params = "<code>",
1003972
description = "Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region",
1004973
privs = {worldedit=true, server=true},
1005-
func = safe_region(function(name, param, pos1, pos2)
974+
func = safe_region(function(name, param)
975+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
1006976
local admin = minetest.setting_get("name")
1007977
if not admin or not name == admin then
1008978
worldedit.player_notify(name, "this command can only be run by the server administrator")
@@ -1022,7 +992,8 @@ minetest.register_chatcommand("/mtschemcreate", {
1022992
params = "<file>",
1023993
description = "Save the current WorldEdit region using the Minetest Schematic format to \"(world folder)/schems/<filename>.mts\"",
1024994
privs = {worldedit=true},
1025-
func = safe_region(function(name, param, pos1, pos2)
995+
func = safe_region(function(name, param)
996+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
1026997
if param == nil then
1027998
worldedit.player_notify(name, "No filename specified")
1028999
return
@@ -1111,7 +1082,8 @@ minetest.register_chatcommand("/clearobjects", {
11111082
params = "",
11121083
description = "Clears all objects within the WorldEdit region",
11131084
privs = {worldedit=true},
1114-
func = safe_region(function(name, param, pos1, pos2)
1085+
func = safe_region(function(name, param)
1086+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
11151087
local count = worldedit.clearobjects(pos1, pos2)
11161088
worldedit.player_notify(name, count .. " objects cleared")
11171089
end),

‎worldedit_commands/safe.lua

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
local safe_region_callback
2+
local safe_region_name
3+
local safe_region_param
4+
5+
--`callback` is a callback to run when the user confirms
6+
--`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed
7+
safe_region = function(callback, nodes_needed)
8+
--default node volume calculation
9+
nodes_needed = nodes_needed or check_region
10+
11+
return function(name, param)
12+
--check if the operation applies to a safe number of nodes
13+
local count = nodes_needed(name, param)
14+
if count == nil then return end --invalid command
15+
if count < 10000 then
16+
return callback(name, param)
17+
end
18+
19+
--save callback to call later
20+
safe_region_callback, safe_region_name, safe_region_param = callback, name, param
21+
worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel")
22+
end
23+
end
24+
25+
minetest.register_chatcommand("/y", {
26+
params = "",
27+
description = "Confirm a pending operation",
28+
func = function()
29+
local callback, name, param = safe_region_callback, safe_region_name, safe_region_param
30+
if not callback then
31+
worldedit.player_notify(name, "no operation pending")
32+
return
33+
end
34+
35+
--obtain positions
36+
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
37+
if pos1 == nil or pos2 == nil then
38+
worldedit.player_notify(name, "no region selected")
39+
return
40+
end
41+
42+
safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil --reset pending operation
43+
callback(name, param, pos1, pos2)
44+
end,
45+
})
46+
47+
minetest.register_chatcommand("/n", {
48+
params = "",
49+
description = "Confirm a pending operation",
50+
func = function()
51+
if not safe_region_callback then
52+
worldedit.player_notify(name, "no operation pending")
53+
return
54+
end
55+
safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil
56+
end,
57+
})

0 commit comments

Comments
 (0)
Please sign in to comment.