local function player_select_item_formspec(player) edit.player_select_item(player, "Select item to use for fill", function(player, item_str) local d = edit.player_data[player] if not d.fill1 or not d.fill2 or not edit.has_privilege(player) then return end local p1 = d.fill1._pos local p2 = d.fill2._pos d.fill1.object:remove() local item = ItemStack(item_str) local name = item:get_name() if name == "" then return end local def = minetest.registered_items[name] if not def then return end local is_node = minetest.registered_nodes[name] local param2 if def.paramtype2 == "facedir" or def.paramtype2 == "colorfacedir" then param2 = minetest.dir_to_facedir(player:get_look_dir()) elseif def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" then param2 = minetest.dir_to_wallmounted(player:get_look_dir(), true) end local start = vector.new( math.min(p1.x, p2.x), math.min(p1.y, p2.y), math.min(p1.z, p2.z) ) local _end = vector.new( math.max(p1.x, p2.x), math.max(p1.y, p2.y), math.max(p1.z, p2.z) ) local size = vector.add(vector.subtract(_end, start), 1) d.undo_schematic = edit.schematic_from_map(start, size) local volume = size.x * size.y * size.z if is_node and volume >= edit.fast_node_fill_threshold then local voxel_manip = VoxelManip() local vm_start, vm_end = voxel_manip:read_from_map(start, _end) local param2s = voxel_manip:get_param2_data() local content_ids = voxel_manip:get_data() local content_id = minetest.get_content_id(name) local ones = vector.new(1, 1, 1) local vm_size = vector.add(vector.subtract(vm_end, vm_start), ones) local voxel_area = VoxelArea:new({MinEdge = ones, MaxEdge = vm_size}) local va_start = vector.add(vector.subtract(start, vm_start), ones) local va_end = vector.subtract(vector.add(va_start, size), ones) for i in voxel_area:iterp(va_start, va_end) do content_ids[i] = content_id param2s[i] = param2 end voxel_manip:set_data(content_ids) voxel_manip:set_param2_data(param2s) voxel_manip:write_to_map(true) voxel_manip:update_liquids() else local node = {name = item_str, param2 = param2} -- Work top to bottom so we can remove falling nodes for x = _end.x, start.x, -1 do for y = _end.y, start.y, -1 do for z = _end.z, start.z, -1 do local pos = vector.new(x, y, z) edit.place_item_like_player(player, node, pos) end end end end return end) end local function fill_on_place(itemstack, player, pointed_thing) if not edit.on_place_checks(player) then return end if not pointed_thing.above then pointed_thing = edit.get_pointed_thing_node(player) end local pos = edit.pointed_thing_to_pos(pointed_thing) local player_data = edit.player_data[player] if player_data.fill1 and pos then player_data.fill2 = edit.add_marker("edit:fill", pos, player) if not player_data.fill2 then return end local diff = vector.subtract(player_data.fill1._pos, pos) local volume = vector.add(vector.apply(diff, math.abs), 1) if volume.x * volume.y * volume.z > edit.max_operation_volume then edit.display_size_error(player) player_data.fill1.object:remove() return end player_select_item_formspec(player) elseif pos then player_data.fill1 = edit.add_marker("edit:fill", pos, player) end end minetest.register_tool("edit:fill", { description = "Edit Fill", tiles = {"edit_fill.png"}, inventory_image = "edit_fill.png", range = 10, groups = {edit_place_preview = 1, edit_box_select_preview = 1}, on_place = fill_on_place, on_secondary_use = fill_on_place, _edit_get_selection_points = function(player) local d = edit.player_data[player] return d.fill1 and d.fill1._pos, d.fill2 and d.fill2._pos end, }) minetest.register_entity("edit:fill", { initial_properties = { visual = "cube", visual_size = { x = 1.1, y = 1.1 }, physical = false, collide_with_objects = false, static_save = false, use_texture_alpha = true, glow = -1, backface_culling = false, hp_max = 1, textures = { "edit_fill.png", "edit_fill.png", "edit_fill.png", "edit_fill.png", "edit_fill.png", "edit_fill.png", }, }, on_deactivate = function(self) local player_data = edit.player_data[self._placer] self.remove_called = true if player_data then if player_data.fill1 and not player_data.fill1.remove_called then player_data.fill1.object:remove() end if player_data.fill2 and not player_data.fill2.remove_called then player_data.fill2.object:remove() end player_data.fill1 = nil player_data.fill2 = nil end end, })