local c_air = minetest.get_content_id("air") -- moves the source to the target area -- no protection- or overlap checking is done here jumpdrive.move = function(source_pos1, source_pos2, target_pos1, target_pos2) minetest.log("action", "[jumpdrive] initiating jump (" .. minetest.pos_to_string(source_pos1) .. "-" .. minetest.pos_to_string(source_pos2) .. ") (" .. minetest.pos_to_string(target_pos1) .. "-" .. minetest.pos_to_string(target_pos2) .. ")") -- step 1: copy via voxel manip -- https://dev.minetest.net/VoxelManip#Examples -- delta between source and target local delta_vector = vector.subtract(target_pos1, source_pos1) -- center of source local source_center = vector.add(source_pos1, vector.divide(vector.subtract(source_pos2, source_pos1), 2)) minetest.log("action", "[jumpdrive] source-center: " .. minetest.pos_to_string(source_center)) local t0 = minetest.get_us_time() -- load areas (just a precaution) if minetest.load_area then minetest.load_area(source_pos1, source_pos2) minetest.load_area(target_pos1, target_pos2) end -- read source local manip = minetest.get_voxel_manip() local e1, e2 = manip:read_from_map(source_pos1, source_pos2) local source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2}) local source_data = manip:get_data() local source_param1 = manip:get_light_data() local source_param2 = manip:get_param2_data() minetest.log("action", "[jumpdrive] read source-data") -- write target manip = minetest.get_voxel_manip() e1, e2 = manip:read_from_map(target_pos1, target_pos2) local target_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2}) local target_data = manip:get_data() local target_param1 = manip:get_light_data() local target_param2 = manip:get_param2_data() minetest.log("action", "[jumpdrive] read target-data"); for z=source_pos1.z, source_pos2.z do for y=source_pos1.y, source_pos2.y do for x=source_pos1.x, source_pos2.x do local source_index = source_area:index(x, y, z) local target_index = target_area:index(x+delta_vector.x, y+delta_vector.y, z+delta_vector.z) -- copy block id target_data[target_index] = source_data[source_index] -- copy params target_param1[target_index] = source_param1[source_index] target_param2[target_index] = source_param2[source_index] end end end manip:set_data(target_data) manip:set_light_data(target_param1) manip:set_param2_data(target_param2) manip:write_to_map() manip:update_map() local t1 = minetest.get_us_time() minetest.log("action", "[jumpdrive] step I took " .. (t1 - t0) .. " us") -- step 2: check meta/timers and copy if needed t0 = minetest.get_us_time() jumpdrive.move_metadata(source_pos1, source_pos2, delta_vector) jumpdrive.move_nodetimers(source_pos1, source_pos2, delta_vector) t1 = minetest.get_us_time() minetest.log("action", "[jumpdrive] step II took " .. (t1 - t0) .. " us") -- step 3: execute target region compat code t0 = minetest.get_us_time() jumpdrive.target_region_compat(target_pos1, target_pos2, delta_vector) t1 = minetest.get_us_time() minetest.log("action", "[jumpdrive] step III took " .. (t1 - t0) .. " us") -- step 4: move objects t0 = minetest.get_us_time() jumpdrive.move_objects(source_center, source_pos1, source_pos2, delta_vector) -- move players for _,player in ipairs(minetest.get_connected_players()) do local playerPos = player:get_pos() local xMatch = playerPos.x >= (source_pos1.x-0.5) and playerPos.x <= (source_pos2.x+0.5) local yMatch = playerPos.y >= (source_pos1.y-0.5) and playerPos.y <= (source_pos2.y+0.5) local zMatch = playerPos.z >= (source_pos1.z-0.5) and playerPos.z <= (source_pos2.z+0.5) if xMatch and yMatch and zMatch and player:is_player() then minetest.log("action", "[jumpdrive] moving player: " .. player:get_player_name()) local new_player_pos = vector.add(playerPos, delta_vector) local op = player:get_physics_override() player:set_physics_override({speed = 0, gravity = 0, jump = 0}) player:set_pos( new_player_pos ); minetest.after(3, function(o, pos) player:set_physics_override({gravity = o.gravity, jump = o.jump, speed = o.speed}) player:set_pos( pos ); end, op, new_player_pos) end end t1 = minetest.get_us_time() minetest.log("action", "[jumpdrive] step IV took " .. (t1 - t0) .. " us") -- step 5: clear source area with voxel manip t0 = minetest.get_us_time() manip = minetest.get_voxel_manip() e1, e2 = manip:read_from_map(source_pos1, source_pos2) source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2}) source_data = manip:get_data() for z=source_pos1.z, source_pos2.z do for y=source_pos1.y, source_pos2.y do for x=source_pos1.x, source_pos2.x do local source_index = source_area:index(x, y, z) source_data[source_index] = c_air end end end manip:set_data(source_data) manip:write_to_map() manip:update_map() t1 = minetest.get_us_time() minetest.log("action", "[jumpdrive] step V took " .. (t1 - t0) .. " us") end