]> git.lizzy.rs Git - schematicas.git/blob - init.lua
Integrate with autodupe and autoeat
[schematicas.git] / init.lua
1 local storage = minetest.get_mod_storage()
2 local pos1, pos2
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")
7
8 minetest.register_chatcommand("pos1", {
9         description = "Set schematicas position 1 at your current location",
10         func = function()
11                 pos1 = vector.round(minetest.localplayer:get_pos())
12                 return true, "Position 1 set to " .. minetest.pos_to_string(pos1)
13         end
14 })
15
16 minetest.register_chatcommand("pos2", {
17         description = "Set schematicas position 2 at your current location",
18         func = function()
19                 pos2 = vector.round(minetest.localplayer:get_pos())
20                 return true, "Position 2 set to " .. minetest.pos_to_string(pos2)
21         end
22 })
23
24
25 minetest.register_chatcommand("schemesave", {
26         description = "Save a schematica",
27         param = "<name>",
28         func = function(name)
29                 if not pos1 or not pos2 then
30                         return false, "Position 1 or 2 not set."
31                 end
32
33                 local data = {}
34
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)
36
37                 for x = lx, hx do
38                         local rx = x - lx
39                         for y = ly, hy do
40                                 local ry = y - ly
41                                 for z = lz, hz do
42                                         local rz = z - lz
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})
46                                         end
47                                 end
48                         end
49                 end
50
51                 storage:set_string(name, minetest.serialize(data))
52                 return true, "Scheme saved successfully as '" .. name .. "'."
53         end
54 })
55
56 minetest.register_chatcommand("schemebuild", {
57         description = "Build a schematica",
58         param = "<name>",
59         func = function(name)
60                 if not pos1 then
61                         return false, "Position 1 not set."
62                 end
63                 if building then
64                         return false, "Still building a scheme. Use .schemeabort to stop it."
65                 end
66                 local rawdata = storage:get(name)
67                 if not rawdata then
68                         return false, "Schematica '" .. name .. "' not found."
69                 end
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
71         end
72 })
73
74 minetest.register_chatcommand("schemerecipe", {
75         description = "Print the recipe for a schematica",
76         param = "<name>",
77         func = function(name)
78                 local rawdata = storage:get(name)
79                 if not rawdata then
80                         return false, "Schematica '" .. name .. "' not found."
81                 end
82                 local data = minetest.deserialize(rawdata)
83                 local sorted = {}
84                 for _, d in ipairs(data) do
85                 end
86         end
87 })
88
89 minetest.register_chatcommand("schemeresume", {
90         description = "Resume constructing a schematica",
91         func = function()
92                 if not build_data then
93                         return false, "Currently not building a scheme."
94                 end
95                 building, out_of_blocks = true, false
96                 return true, "Resumed."
97         end
98 })
99
100 minetest.register_chatcommand("schemepause", {
101         description = "Pause constructing a schematica",
102         func = function()
103                 if not build_data then
104                         return false, "Currently not building a scheme."
105                 end
106                 building = false
107                 return true, "Paused."
108         end
109 })
110
111 minetest.register_chatcommand("schemeabort", {
112         description = "Abort constructing a schematica",
113         param = "<name>",
114         func = function()
115                 if not build_data then
116                         return false, "Currently not building a scheme."
117                 end
118                 building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nilw
119                 return true, "Aborted."
120         end
121 })
122
123 minetest.register_chatcommand("schemeskip", {
124         description = "Skip a step in constructing a schematica",
125         param = "<name>",
126         func = function()
127                 if not build_data then
128                         return false, "Currently not building a scheme."
129                 end
130                 building, build_index = true, build_index + 1
131                 return true, "Skipped."
132         end
133 })
134
135 minetest.register_chatcommand("schemegetindex", {
136         description = "Output the build index of the schematica",
137         func = function()
138                 return build_index and true or false, build_index
139         end
140 })
141
142 minetest.register_chatcommand("schemesetindex", {
143         description = "Set the build index of the schematica",
144         param = "<index>",
145         func = function(param)
146                 local index = tonumber(param)
147                 if not index then return false, "Invalid usage." end
148                 build_index = index
149                 last_good_block = index
150                 return true, "Index Changed"
151         end
152 })
153
154 local function step(stack)
155         if building then
156                 local data = build_data[build_index]
157                 if not data then
158                         building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nil
159                         minetest.display_chat_message("Completed Schematica.")
160                         return
161                 end
162                 if autoeat and autoeat.lock then
163                         return
164                 end
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)
170                 if not map_node then
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})
174                         return
175                 end
176                 local map_node_name = map_node.name
177                 local is_good = map_node_name == node
178                 if not is_good then
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)
184                                 return
185                         end
186                 end
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
193                                 else
194                                         if is_good then
195                                                 if build_index % 500 == 0 then
196                                                         minetest.send_chat_message("[Schematicas] " .. build_index .. " of " .. #build_data .. " blocks placed")
197                                                 end
198                                                 last_good_block = build_index
199                                                 build_index = build_index + 1
200                                                 just_placed_node = true
201                                                 if stack < 1000 then
202                                                         step(stack + 1)
203                                                 end
204                                         end
205                                 end
206                                 return
207                         else
208                                 failed_count = failed_count + 1
209                         end
210                         if reliable and failed_count < 10 then
211                                 return
212                         end
213                         if not reliable and not map_node then
214                                 return
215                         end
216                         build_index = build_index + 1
217                 end
218                 failed_count = 0
219                 local new_index
220                 local item_count = 0
221                 local item_name
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
230                                         break
231                                 end
232                         end
233                 end
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.")
237                         end
238                         if autodupe and item_name then
239                                 autodupe.needed(new_index)
240                         end
241                         out_of_blocks = true
242                         return
243                 end
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
247                         return
248                 end
249                 if was_out_of_blocks and not out_of_blocks then
250                         minetest.display_chat_message("Resuming.")
251                 end
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
257         end
258 end
259
260 minetest.register_globalstep(function()
261         step(0)
262 end)
263