function edit.schematic_from_map(pos, size)
	local schematic = {data = {}}
	schematic.size = size
	schematic._pos = pos
	schematic._meta = {}
	schematic._timers = {}
	schematic._rotation = 0

	local start = vector.new(1, 1, 1)
	local voxel_area = VoxelArea:new({MinEdge = start, MaxEdge = size})

	for i in voxel_area:iterp(start, size) do
		local offset = voxel_area:position(i)
		local node_pos = vector.subtract(vector.add(pos, offset), start)
		local node = minetest.get_node(node_pos)
		node.param1 = nil
		schematic.data[i] = node

		local meta = minetest.get_meta(node_pos):to_table()

		local has_meta = false
		-- Convert metadata item stacks to item strings
		for name, inventory in pairs(meta.inventory) do
			for i, stack in ipairs(inventory) do
				has_meta = true
				if stack.to_string then
					inventory[i] = stack:to_string()
				end
			end
		end

		if meta.fields and next(meta.fields) ~= nil then
			has_meta = true
		end

		if not has_meta then
			for k in pairs(meta) do
				if k ~= "inventory" and k ~= "fields" then
					has_meta = true
					break
				end
			end
		end

		if has_meta then
			local key = minetest.hash_node_position(offset)
			schematic._meta[key] = meta
		end

		local timer = minetest.get_node_timer(node_pos)
		local timeout = timer:get_timeout()
		if timeout ~= 0 then
			local key = minetest.hash_node_position(offset)
			local elapsed = timer:get_elapsed()
			schematic._timers[key] = {timeout, elapsed}
		end
	end

	return schematic
end

function edit.set_schematic_rotation(schematic, angle)
	schematic._rotation = schematic._rotation + angle
	if schematic._rotation < 0 then
		schematic._rotation = schematic._rotation + 360
	elseif schematic._rotation > 270 then
		schematic._rotation = schematic._rotation - 360
	end

	--[[local old_schematic = player_data[player].schematic
	local new_schematic = {data = {}}
	player_data[player].schematic = new_schematic
	
	local old_size = old_schematic.size
	local new_size
	if direction == "L" or direction == "R" then
		new_size = vector.new(old_size.z, old_size.y, old_size.x)
	elseif direction == "U" or direction == "D" then
		new_size = vector.new(old_size.y, old_size.x, old_size.z)
	end
	new_schematic.size = new_size
	
	local sign = vector.apply(old_schematic._offset, math.sign)
	new_schematic._offset = vector.apply(
		vector.multiply(new_size, sign),
		function(n) return n < 0 and n or 1 end
	)

	local start = vector.new(1, 1, 1)
	local old_voxel_area = VoxelArea:new({MinEdge = start, MaxEdge = old_size})
	local new_voxel_area = VoxelArea:new({MinEdge = start, MaxEdge = new_size})
	for old_index in old_voxel_area:iterp(start, old_schematic.size) do
		local old_pos = old_voxel_area:position(old_index)
		local new_pos
		local node = old_schematic.data[old_index]
		
		if direction == "L" then
			new_pos = vector.new(old_pos.z, old_pos.y, old_size.x - old_pos.x + 1)
		elseif direction == "R" then
			new_pos = vector.new(old_size.z - old_pos.z + 1, old_pos.y, old_pos.x)
		elseif direction == "U" then
			new_pos = vector.new(old_pos.y, old_size.x - old_pos.x + 1, old_pos.z)
		elseif direction == "D" then
			new_pos = vector.new(old_size.y - old_pos.y + 1, old_pos.x, old_pos.z)
		end
		
		local new_index = new_voxel_area:indexp(new_pos)
		new_schematic.data[new_index] = node
	end
	delete_paste_preview(player)]]
end

function edit.schematic_to_map(pos, schematic)
	minetest.place_schematic(pos, schematic, tostring(schematic._rotation), nil, true)
	local size = schematic.size
	for hash, metadata in pairs(schematic._meta) do
		local offset = minetest.get_position_from_hash(hash)
		offset = vector.subtract(offset, 1)
		if schematic._rotation == 90 then
			offset = vector.new(offset.z, offset.y, size.x - offset.x - 1)
		elseif schematic._rotation == 180 then
			offset = vector.new(size.x - offset.x - 1, offset.y, size.z - offset.z - 1)
		elseif schematic._rotation == 270 then
			offset = vector.new(size.z - offset.z - 1, offset.y, offset.x)
		end
		local node_pos = vector.add(pos, offset)
		local meta = minetest.get_meta(node_pos)
		if meta then
			meta:from_table(metadata)
		end
	end

	for hash, timer_data in pairs(schematic._timers) do
		local offset = minetest.get_position_from_hash(hash)
		offset = vector.subtract(offset, 1)
		if schematic._rotation == 90 then
			offset = vector.new(offset.z, offset.y, size.x - offset.x - 1)
		elseif schematic._rotation == 180 then
			offset = vector.new(size.x - offset.x - 1, offset.y, size.z - offset.z - 1)
		elseif schematic._rotation == 270 then
			offset = vector.new(size.z - offset.z - 1, offset.y, offset.x)
		end
		local node_pos = vector.add(pos, offset)
		local timer = minetest.get_node_timer(node_pos)
		if timer then
			timer:set(timer_data[1], timer_data[2])
		end
	end
end
