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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
|
local storage = minetest.get_mod_storage()
local pos1, pos2
local min, max = math.min, math.max
local building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks, last_good_block
local autodupe = rawget(_G, "autodupe")
local autoeat = rawget(_G, "autoeat")
minetest.register_chatcommand("pos1", {
description = "Set schematicas position 1 at your current location",
func = function()
pos1 = vector.round(minetest.localplayer:get_pos())
return true, "Position 1 set to " .. minetest.pos_to_string(pos1)
end
})
minetest.register_chatcommand("pos2", {
description = "Set schematicas position 2 at your current location",
func = function()
pos2 = vector.round(minetest.localplayer:get_pos())
return true, "Position 2 set to " .. minetest.pos_to_string(pos2)
end
})
minetest.register_chatcommand("schemesave", {
description = "Save a schematica",
param = "<name>",
func = function(name)
if not pos1 or not pos2 then
return false, "Position 1 or 2 not set."
end
local data = {}
local lx, ly, lz, hx, hy, hz = min(pos1.x, pos2.x), min(pos1.y, pos2.y), min(pos1.z, pos2.z), max(pos1.x, pos2.x), max(pos1.y, pos2.y), max(pos1.z, pos2.z)
for x = lx, hx do
local rx = x - lx
for y = ly, hy do
local ry = y - ly
for z = lz, hz do
local rz = z - lz
local node = minetest.get_node_or_nil({x = x, y = y, z = z})
if node and node.name ~= "air" then
table.insert(data, {pos = {x = rx, y = ry, z = rz}, node = node.name})
end
end
end
end
storage:set_string(name, minetest.serialize(data))
return true, "Scheme saved successfully as '" .. name .. "'."
end
})
minetest.register_chatcommand("schemebuild", {
description = "Build a schematica",
param = "<name>",
func = function(name)
if not pos1 then
return false, "Position 1 not set."
end
if building then
return false, "Still building a scheme. Use .schemeabort to stop it."
end
local rawdata = storage:get(name)
if not rawdata then
return false, "Schematica '" .. name .. "' not found."
end
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = true, 1, minetest.deserialize(rawdata), vector.new(pos1), false, 0, false
end
})
minetest.register_chatcommand("schemerecipe", {
description = "Print the recipe for a schematica",
param = "<name>",
func = function(name)
local rawdata = storage:get(name)
if not rawdata then
return false, "Schematica '" .. name .. "' not found."
end
local data = minetest.deserialize(rawdata)
local sorted = {}
for _, d in ipairs(data) do
end
end
})
minetest.register_chatcommand("schemeresume", {
description = "Resume constructing a schematica",
func = function()
if not build_data then
return false, "Currently not building a scheme."
end
building, out_of_blocks = true, false
return true, "Resumed."
end
})
minetest.register_chatcommand("schemepause", {
description = "Pause constructing a schematica",
func = function()
if not build_data then
return false, "Currently not building a scheme."
end
building = false
return true, "Paused."
end
})
minetest.register_chatcommand("schemeabort", {
description = "Abort constructing a schematica",
param = "<name>",
func = function()
if not build_data then
return false, "Currently not building a scheme."
end
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nilw
return true, "Aborted."
end
})
minetest.register_chatcommand("schemeskip", {
description = "Skip a step in constructing a schematica",
param = "<name>",
func = function()
if not build_data then
return false, "Currently not building a scheme."
end
building, build_index = true, build_index + 1
return true, "Skipped."
end
})
minetest.register_chatcommand("schemegetindex", {
description = "Output the build index of the schematica",
func = function()
return build_index and true or false, build_index
end
})
minetest.register_chatcommand("schemesetindex", {
description = "Set the build index of the schematica",
param = "<index>",
func = function(param)
local index = tonumber(param)
if not index then return false, "Invalid usage." end
build_index = index
last_good_block = index
return true, "Index Changed"
end
})
local function step(stack)
if building then
local data = build_data[build_index]
if not data then
building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nil
minetest.display_chat_message("Completed Schematica.")
return
end
if autoeat and autoeat.lock then
return
end
local player = minetest.localplayer
local pos, node = vector.add(build_pos, data.pos), data.node
local free_pos = minetest.find_node_near(pos, 4, {"air"}, false)
local player_pos = vector.subtract(free_pos or pos, vector.new(0, 1.5, 0))
local map_node = minetest.get_node_or_nil(pos)
if not map_node then
player:set_pos(player_pos)
minetest.interact("start_digging", {type = "node", under = pos, above = pos})
minetest.interact("stop_digging", {type = "node", under = pos, above = pos})
return
end
local map_node_name = map_node.name
local is_good = map_node_name == node
if not is_good then
local def = minetest.get_node_def(map_node_name)
if not def or not def.buildable_to then
player:set_pos(player_pos)
autotool.select_best_tool(map_node_name)
minetest.dig_node(pos)
return
end
end
if just_placed_node then
just_placed_node = false
if is_good or build_index % 50 == 0 then
local lgb = last_good_block or 0
if lgb < build_index - 1 then
build_index = lgb + 1
else
if is_good then
if build_index % 500 == 0 then
minetest.send_chat_message("[Schematicas] " .. build_index .. " of " .. #build_data .. " blocks placed")
end
last_good_block = build_index
build_index = build_index + 1
just_placed_node = true
if stack < 1000 then
step(stack + 1)
end
end
end
return
else
failed_count = failed_count + 1
end
if reliable and failed_count < 10 then
return
end
if not reliable and not map_node then
return
end
build_index = build_index + 1
end
failed_count = 0
local new_index
local item_count = 0
local item_name
local inventory = minetest.get_inventory("current_player").main
for index, stack in ipairs(inventory) do
local stackname = stack:get_name()
if minetest.get_item_def(stackname).node_placement_prediction == node then
new_index = new_index or index
item_name = item_name or stackname
item_count = item_count + 1
if item_count > 1 then
break
end
end
end
if item_count <= 1 then
if not out_of_blocks then
minetest.display_chat_message("Out of blocks for schematica. Missing ressource: '" .. node .. "' (You need at least two stacks of it). It will resume as soon as you got it or use .schemeskip to skip it.")
end
if autodupe and item_name then
autodupe.needed(new_index)
end
out_of_blocks = true
return
end
local was_out_of_blocks = out_of_blocks
out_of_blocks = out_of_blocks and autodupe and not autodupe.cleanup()
if out_of_blocks then
return
end
if was_out_of_blocks and not out_of_blocks then
minetest.display_chat_message("Resuming.")
end
out_of_blocks = false
player:set_wield_index(new_index)
player:set_pos(player_pos)
minetest.place_node(pos)
just_placed_node = true
end
end
minetest.register_globalstep(function()
step(0)
end)
|