2020-06-26 19:46:35 +00:00
local wea = worldeditadditions
2022-05-19 01:31:01 +00:00
local wea_c = worldeditadditions_core
2020-06-26 19:46:35 +00:00
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 )
2022-05-19 01:31:01 +00:00
local def = wea_c.fetch_command_def ( cmd_name )
if not def then return nil , " Error: That worldedit command could not be found (perhaps it hasn't been upgraded to worldedit.register_command() yet?) " end
2020-06-26 17:43:07 +00:00
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-06-27 23:56:29 +00:00
local result = def.nodes_needed ( name , wea.table . unpack ( parsed ) )
2021-02-07 01:28:07 +00:00
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
2022-05-19 21:10:09 +00:00
worldeditadditions_core.register_command ( " subdivide " , {
2020-06-26 01:13:11 +00:00
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 ]
2022-05-19 01:31:01 +00:00
if not wea_c.fetch_command_def ( cmd_name ) then
2020-06-26 01:13:11 +00:00
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
2022-05-19 01:31:01 +00:00
local cmd = wea_c.fetch_command_def ( 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
2021-02-21 15:19:21 +00:00
if cmd.require_pos ~= 2 then
return false , " Error: The WorldEdit command ' " .. cmd_name .. " ' does not take 2 region markers, so can't be executed using //subdivide. "
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))
2021-02-07 02:59:41 +00:00
local msg_prefix = " [ subdivide | " .. wea.trim ( table.concat ( { cmd_name , args } , " " ) ) .. " ] "
2020-10-10 20:43:22 +00:00
local time_last_msg = wea.get_ms_time ( )
2021-02-21 15:19:21 +00:00
local cmd_args_parsed = { cmd.parse ( args ) }
local success = table.remove ( cmd_args_parsed , 1 )
if not success then
2021-07-30 17:06:44 +00:00
return false , cmd_name .. " : " .. ( cmd_args_parsed [ 1 ] or " invalid usage " )
2021-02-21 15:19:21 +00:00
end
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
2021-02-07 03:12:09 +00:00
if stats.chunks_completed == 1 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 )
2021-06-27 23:56:29 +00:00
cmd.func ( name , wea.table . unpack ( cmd_args_parsed ) )
2020-10-10 20:43:22 +00:00
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-03-20 01:48:56 +00:00
worldeditadditions.format . human_time ( math.floor ( stats.times . step_last ) ) , -- the time is an integer anyway because precision
worldeditadditions.format . human_time ( wea.average ( stats.times . steps ) ) ,
2020-10-10 20:43:22 +00:00
stats.emerge_overhead * 100 ,
2021-03-20 01:48:56 +00:00
worldeditadditions.format . human_time ( stats.eta )
2020-10-10 20:43:22 +00:00
)
)
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 ,
2021-03-20 01:48:56 +00:00
worldeditadditions.format . human_time ( stats.times . total )
2020-10-10 20:43:22 +00:00
) )
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 ,
2021-03-20 01:48:56 +00:00
worldeditadditions.format . 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
} )