2020-06-26 19:46:35 +00:00
local wea = worldeditadditions
2022-05-19 01:31:01 +00:00
local wea_c = worldeditadditions_core
2022-09-18 21:37:26 +00:00
local Vector3 = wea_c.Vector3
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
2022-09-18 21:37:26 +00:00
local result = def.nodes_needed ( name , wea_c.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 ,
2024-10-17 01:26:44 +00:00
async = true ,
2020-06-26 01:13:11 +00:00
parse = function ( params_text )
2022-09-18 21:37:26 +00:00
local parts = wea_c.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 ,
2024-10-17 01:26:44 +00:00
func = function ( callback , name , chunk_size , cmd_name , args )
2022-09-18 21:37:26 +00:00
local time_total = wea_c.get_ms_time ( )
2020-06-26 01:13:11 +00:00
2022-09-18 21:37:26 +00:00
local pos1 , pos2 = Vector3.sort ( worldedit.pos1 [ name ] , worldedit.pos2 [ name ] )
2020-06-26 01:13:11 +00:00
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))
2022-09-18 21:37:26 +00:00
local msg_prefix = " [ subdivide | " .. wea_c.trim ( table.concat ( { cmd_name , args } , " " ) ) .. " ] "
local time_last_msg = wea_c.get_ms_time ( )
2020-10-10 20:43:22 +00:00
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
2022-09-18 21:37:26 +00:00
local chunk_size_display = Vector3.new (
stats.chunk_size . x + 1 , -- x
stats.chunk_size . y + 1 , -- y
stats.chunk_size . z + 1 -- z
)
2024-10-17 01:26:44 +00:00
wea_c.notify . info ( name , string.format (
2020-10-10 20:43:22 +00:00
" %sStarting - chunk size: %s, %d chunks total (%d nodes) " ,
msg_prefix ,
2022-09-18 21:37:26 +00:00
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
2024-10-17 01:26:44 +00:00
wea_c.notify . suppress_for_function ( name , function ( )
-- We still call `worldedit.player_notify_suppress` here because we may be subdividing a WorldEdit function as opposed to one from WEA
worldedit.player_notify_suppress ( name )
wea_c.pos . set1 ( name , cpos1 )
wea_c.pos . set2 ( name , cpos2 )
-- worldedit.pos1[name] = cpos1
-- worldedit.pos2[name] = cpos2
-- worldedit.marker_update(name)
cmd.func ( name , wea_c.table . unpack ( cmd_args_parsed ) )
if will_trigger_saferegion ( name , cmd_name , args ) then
minetest.registered_chatcommands [ " /y " ] . func ( name )
end
worldedit.player_notify_unsuppress ( name )
end )
2020-10-10 20:43:22 +00:00
-- Send updates every 2 seconds, and after the first 3 chunks are done
2022-09-18 21:37:26 +00:00
if wea_c.get_ms_time ( ) - time_last_msg > 2 * 1000 or stats.chunks_completed == 3 or stats.chunks_completed == stats.chunks_total then
2024-10-17 01:26:44 +00:00
wea_c.notify . info ( name ,
2020-10-10 20:43:22 +00:00
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 ,
2022-09-18 21:37:26 +00:00
wea_c.format . human_time ( math.floor ( stats.times . step_last ) ) , -- the time is an integer anyway because precision
wea_c.format . human_time ( wea_c.average ( stats.times . steps ) ) ,
2020-10-10 20:43:22 +00:00
stats.emerge_overhead * 100 ,
2022-09-18 21:37:26 +00:00
wea_c.format . human_time ( stats.eta )
2020-10-10 20:43:22 +00:00
)
)
2022-09-18 21:37:26 +00:00
time_last_msg = wea_c.get_ms_time ( )
2020-10-10 20:43:22 +00:00
end
end , function ( _ , _ , stats )
2024-10-17 01:26:44 +00:00
-- Called on completion
2023-07-02 01:02:42 +00:00
wea_c.pos . set1 ( name , pos1 )
wea_c.pos . set2 ( name , pos2 )
-- worldedit.pos1[name] = pos1
-- worldedit.pos2[name] = pos2
-- worldedit.marker_update(name)
2020-10-10 21:22:53 +00:00
2024-10-17 01:26:44 +00:00
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 ,
2022-09-18 21:37:26 +00:00
tostring ( pos1 ) ,
tostring ( pos2 ) ,
2020-10-10 20:43:22 +00:00
stats.chunks_completed ,
stats.volume_nodes ,
2022-09-18 21:37:26 +00:00
wea_c.format . human_time ( stats.times . total )
2020-10-10 20:43:22 +00:00
) )
2024-10-17 01:26:44 +00:00
callback ( true , 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 ,
2022-09-18 21:37:26 +00:00
wea_c.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
} )