2020-06-26 19:46:35 +00:00
local wea = worldeditadditions
2020-06-26 17:57:25 +00:00
-- Test command:
-- //multi //fp set1 1330 60 5455 //fp set2 1355 35 5430 //subdivide 10 10 10 fixlight //y
2020-06-26 19:46:35 +00:00
2020-06-26 01:13:11 +00:00
local function will_trigger_saferegion ( name , cmd_name , args )
2020-06-26 17:43:07 +00:00
if not worldedit.registered_commands [ cmd_name ] then return nil , " Error: That worldedit command could not be found (perhaps it hasn't been upgraded to worldedit.register_command() yet?) " end
local def = worldedit.registered_commands [ cmd_name ]
if not def.parse then return nil , " Error: No parse method found (this is a bug). " end
local parsed = { def.parse ( args ) }
local parse_success = table.remove ( parsed , 1 )
2021-02-06 19:34:46 +00:00
if not parse_success then return nil , table.remove ( parsed , 1 ) end
2020-06-26 17:43:07 +00:00
if not def.nodes_needed then return false end
2021-02-07 01:28:07 +00:00
local result = def.nodes_needed ( name , unpack ( parsed ) )
if not result then return nil , result end
2020-06-26 01:13:11 +00:00
if result > 10000 then return true end
return false
end
2020-10-10 20:43:22 +00:00
local function emerge_stats_tostring ( tbl_emerge )
local result = { }
for key , value in pairs ( tbl_emerge ) do
2020-10-10 21:22:53 +00:00
if value > 0 then
table.insert ( result , string.format ( " %s=%d " , key , value ) )
end
2020-06-26 20:56:26 +00:00
end
2020-10-10 20:43:22 +00:00
return table.concat ( result , " , " )
2020-06-26 20:56:26 +00:00
end
2020-06-26 01:13:11 +00:00
worldedit.register_command ( " subdivide " , {
params = " <size_x> <size_y> <size_z> <command> <params> " ,
description = " Subdivides the given worldedit area into chunks and runs a worldedit command multiple times to cover the defined region. Note that the given command must NOT be prepended with any forward slashes - just like //cubeapply. " ,
privs = { worldedit = true } ,
require_pos = 2 ,
parse = function ( params_text )
2020-06-26 19:46:35 +00:00
local parts = wea.split ( params_text , " %s+ " , false )
2020-06-26 01:13:11 +00:00
if # parts < 4 then
return false , " Error: Not enough arguments (try /help /subdivide). "
end
local chunk_size = {
x = tonumber ( parts [ 1 ] ) ,
y = tonumber ( parts [ 2 ] ) ,
z = tonumber ( parts [ 3 ] )
}
if chunk_size.x == nil then return false , " Error: Invalid value for size_x (must be an integer). " end
if chunk_size.y == nil then return false , " Error: Invalid value for size_y (must be an integer). " end
if chunk_size.z == nil then return false , " Error: Invalid value for size_x (must be an integer). " end
chunk_size.x = math.floor ( chunk_size.x )
chunk_size.y = math.floor ( chunk_size.y )
chunk_size.z = math.floor ( chunk_size.z )
local cmd_name = parts [ 4 ]
if not worldedit.registered_commands [ cmd_name ] then
return false , " Error: The worldedit command ' " .. parts [ 4 ] .. " ' does not exist (try /help). "
end
-- success, chunk_size, command_name, args
return true , chunk_size , parts [ 4 ] , table.concat ( parts , " " , 5 )
end ,
nodes_needed = function ( name )
return worldedit.volume ( worldedit.pos1 [ name ] , worldedit.pos2 [ name ] )
end ,
func = function ( name , chunk_size , cmd_name , args )
2020-10-10 20:43:22 +00:00
local time_total = wea.get_ms_time ( )
2020-06-26 01:13:11 +00:00
local pos1 , pos2 = worldedit.sort_pos ( worldedit.pos1 [ name ] , worldedit.pos2 [ name ] )
local volume = worldedit.volume ( pos1 , pos2 )
2020-06-26 20:15:13 +00:00
2020-06-26 01:13:11 +00:00
local cmd = worldedit.registered_commands [ cmd_name ]
2020-10-10 20:43:22 +00:00
-- Note that we don't need to check for //multi privileges, as it does it at runtime
2020-06-26 01:13:11 +00:00
if not minetest.check_player_privs ( name , cmd.privs ) then
return false , " Error: Your privileges are unsufficient to run ' " .. cmd_name .. " '. "
end
2020-06-26 20:56:26 +00:00
-- local chunks_total = math.ceil((pos2.x - pos1.x) / (chunk_size.x - 1))
-- * math.ceil((pos2.y - pos1.y) / (chunk_size.y - 1))
-- * math.ceil((pos2.z - pos1.z) / (chunk_size.z - 1))
local msg_prefix = " [ subdivide | " .. table.concat ( { cmd_name , args } , " " ) .. " ] "
2020-10-10 20:43:22 +00:00
local time_last_msg = wea.get_ms_time ( )
2020-10-10 20:50:03 +00:00
wea.subdivide ( pos1 , pos2 , chunk_size , function ( cpos1 , cpos2 , stats )
2020-10-10 20:43:22 +00:00
-- Called on every subblock
if stats.chunks_completed == 0 then
2020-10-10 21:41:19 +00:00
local chunk_size_display = {
x = stats.chunk_size . x + 1 ,
y = stats.chunk_size . y + 1 ,
z = stats.chunk_size . z + 1
}
2020-10-10 20:43:22 +00:00
worldedit.player_notify ( name , string.format (
" %sStarting - chunk size: %s, %d chunks total (%d nodes) " ,
msg_prefix ,
2020-10-10 21:41:19 +00:00
wea.vector . tostring ( chunk_size_display ) ,
2020-10-10 20:43:22 +00:00
stats.chunks_total ,
stats.volume_nodes
) )
2020-06-26 01:13:11 +00:00
end
2020-10-10 20:43:22 +00:00
worldedit.player_notify_suppress ( name )
worldedit.pos1 [ name ] = cpos1
worldedit.pos2 [ name ] = cpos2
2020-10-10 21:22:53 +00:00
worldedit.marker_update ( name )
2020-10-10 20:43:22 +00:00
cmd.func ( name , args )
if will_trigger_saferegion ( name , cmd_name , args ) then
2021-02-07 01:28:07 +00:00
minetest.chatcommands [ " /y " ] . func ( name )
2020-10-10 20:43:22 +00:00
end
worldedit.player_notify_unsuppress ( name )
-- Send updates every 2 seconds, and after the first 3 chunks are done
2021-02-07 01:35:06 +00:00
if worldeditadditions.get_ms_time ( ) - time_last_msg > 2 * 1000 or stats.chunks_completed == 3 or stats.chunks_completed == stats.chunks_total then
2020-10-10 20:43:22 +00:00
worldedit.player_notify ( name ,
string.format ( " %s%d / %d (~%.2f%%) complete | last chunk: %s, average: %s, %.2f%% emerge overhead, ETA: ~%s " ,
msg_prefix ,
stats.chunks_completed , stats.chunks_total ,
( stats.chunks_completed / stats.chunks_total ) * 100 ,
2021-02-06 14:34:30 +00:00
wea.human_time ( math.floor ( stats.times . step_last ) ) , -- the time is an integer anyway because precision
2020-10-10 20:43:22 +00:00
wea.human_time ( wea.average ( stats.times . steps ) ) ,
stats.emerge_overhead * 100 ,
wea.human_time ( stats.eta )
)
)
time_last_msg = wea.get_ms_time ( )
end
end , function ( _ , _ , stats )
2020-10-10 21:22:53 +00:00
worldedit.pos1 [ name ] = pos1
worldedit.pos2 [ name ] = pos2
worldedit.marker_update ( name )
2020-10-10 20:43:22 +00:00
-- Called on completion
2020-10-10 21:22:53 +00:00
minetest.log ( " action " , string.format ( " %s used //subdivide at %s - %s, with %d chunks and %d total nodes in %s " ,
2020-10-10 20:43:22 +00:00
name ,
wea.vector . tostring ( pos1 ) ,
wea.vector . tostring ( pos2 ) ,
stats.chunks_completed ,
stats.volume_nodes ,
wea.human_time ( stats.times . total )
) )
2020-10-10 21:22:53 +00:00
worldedit.player_notify ( name , string.format (
2020-10-10 20:43:22 +00:00
" %sComplete: %d chunks processed in %s (%.2f%% emerge overhead, emerge totals: %s) " ,
msg_prefix ,
stats.chunks_completed ,
2020-10-10 21:22:53 +00:00
wea.human_time ( stats.times . total ) ,
2020-10-10 20:43:22 +00:00
stats.emerge_overhead * 100 ,
emerge_stats_tostring ( stats.emerge )
2020-10-10 21:22:53 +00:00
) )
2020-10-10 20:43:22 +00:00
end )
2020-06-26 01:13:11 +00:00
2020-10-10 21:22:53 +00:00
return true
2020-06-26 01:13:11 +00:00
end
} )