-
Notifications
You must be signed in to change notification settings - Fork 8
/
fill.lua
159 lines (139 loc) · 4.54 KB
/
fill.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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,
})