1 local storage = minetest.get_mod_storage()
3 local min, max = math.min, math.max
4 local building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks, last_good_block
5 local autodupe = rawget(_G, "autodupe")
6 local autoeat = rawget(_G, "autoeat")
8 minetest.register_chatcommand("pos1", {
9 description = "Set schematicas position 1 at your current location",
11 pos1 = vector.round(minetest.localplayer:get_pos())
12 return true, "Position 1 set to " .. minetest.pos_to_string(pos1)
16 minetest.register_chatcommand("pos2", {
17 description = "Set schematicas position 2 at your current location",
19 pos2 = vector.round(minetest.localplayer:get_pos())
20 return true, "Position 2 set to " .. minetest.pos_to_string(pos2)
25 minetest.register_chatcommand("schemesave", {
26 description = "Save a schematica",
29 if not pos1 or not pos2 then
30 return false, "Position 1 or 2 not set."
35 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)
43 local node = minetest.get_node_or_nil({x = x, y = y, z = z})
44 if node and node.name ~= "air" then
45 table.insert(data, {pos = {x = rx, y = ry, z = rz}, node = node.name})
51 storage:set_string(name, minetest.serialize(data))
52 return true, "Scheme saved successfully as '" .. name .. "'."
56 minetest.register_chatcommand("schemebuild", {
57 description = "Build a schematica",
61 return false, "Position 1 not set."
64 return false, "Still building a scheme. Use .schemeabort to stop it."
66 local rawdata = storage:get(name)
68 return false, "Schematica '" .. name .. "' not found."
70 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
74 minetest.register_chatcommand("schemerecipe", {
75 description = "Print the recipe for a schematica",
78 local rawdata = storage:get(name)
80 return false, "Schematica '" .. name .. "' not found."
82 local data = minetest.deserialize(rawdata)
84 for _, d in ipairs(data) do
89 minetest.register_chatcommand("schemeresume", {
90 description = "Resume constructing a schematica",
92 if not build_data then
93 return false, "Currently not building a scheme."
95 building, out_of_blocks = true, false
96 return true, "Resumed."
100 minetest.register_chatcommand("schemepause", {
101 description = "Pause constructing a schematica",
103 if not build_data then
104 return false, "Currently not building a scheme."
107 return true, "Paused."
111 minetest.register_chatcommand("schemeabort", {
112 description = "Abort constructing a schematica",
115 if not build_data then
116 return false, "Currently not building a scheme."
118 building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nilw
119 return true, "Aborted."
123 minetest.register_chatcommand("schemeskip", {
124 description = "Skip a step in constructing a schematica",
127 if not build_data then
128 return false, "Currently not building a scheme."
130 building, build_index = true, build_index + 1
131 return true, "Skipped."
135 minetest.register_chatcommand("schemegetindex", {
136 description = "Output the build index of the schematica",
138 return build_index and true or false, build_index
142 minetest.register_chatcommand("schemesetindex", {
143 description = "Set the build index of the schematica",
145 func = function(param)
146 local index = tonumber(param)
147 if not index then return false, "Invalid usage." end
149 last_good_block = index
150 return true, "Index Changed"
154 local function step(stack)
156 local data = build_data[build_index]
158 building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nil
159 minetest.display_chat_message("Completed Schematica.")
162 if autoeat and autoeat.lock then
165 local player = minetest.localplayer
166 local pos, node = vector.add(build_pos, data.pos), data.node
167 local free_pos = minetest.find_node_near(pos, 4, {"air"}, false)
168 local player_pos = vector.subtract(free_pos or pos, vector.new(0, 1.5, 0))
169 local map_node = minetest.get_node_or_nil(pos)
171 player:set_pos(player_pos)
172 minetest.interact("start_digging", {type = "node", under = pos, above = pos})
173 minetest.interact("stop_digging", {type = "node", under = pos, above = pos})
176 local map_node_name = map_node.name
177 local is_good = map_node_name == node
179 local def = minetest.get_node_def(map_node_name)
180 if not def or not def.buildable_to then
181 player:set_pos(player_pos)
182 autotool.select_best_tool(map_node_name)
183 minetest.dig_node(pos)
187 if just_placed_node then
188 just_placed_node = false
189 if is_good or build_index % 50 == 0 then
190 local lgb = last_good_block or 0
191 if lgb < build_index - 1 then
192 build_index = lgb + 1
195 if build_index % 500 == 0 then
196 minetest.send_chat_message("[Schematicas] " .. build_index .. " of " .. #build_data .. " blocks placed")
198 last_good_block = build_index
199 build_index = build_index + 1
200 just_placed_node = true
208 failed_count = failed_count + 1
210 if reliable and failed_count < 10 then
213 if not reliable and not map_node then
216 build_index = build_index + 1
222 local inventory = minetest.get_inventory("current_player").main
223 for index, stack in ipairs(inventory) do
224 local stackname = stack:get_name()
225 if minetest.get_item_def(stackname).node_placement_prediction == node then
226 new_index = new_index or index
227 item_name = item_name or stackname
228 item_count = item_count + 1
229 if item_count > 1 then
234 if item_count <= 1 then
235 if not out_of_blocks then
236 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.")
238 if autodupe and item_name then
239 autodupe.needed(new_index)
244 local was_out_of_blocks = out_of_blocks
245 out_of_blocks = out_of_blocks and autodupe and not autodupe.cleanup()
246 if out_of_blocks then
249 if was_out_of_blocks and not out_of_blocks then
250 minetest.display_chat_message("Resuming.")
252 out_of_blocks = false
253 player:set_wield_index(new_index)
254 player:set_pos(player_pos)
255 minetest.place_node(pos)
256 just_placed_node = true
260 minetest.register_globalstep(function()