· 7 years ago · Feb 17, 2019, 01:06 AM
1--[[
2Valvates library for cordanite management and stuff.
3If you have an idea for feature make an issue or
4Create a pull request if you're a coder.
5A lot of stuff here is unfinished so
6Be careful and tell me how to make it better :DD
7
8WARNING!
9Since the turtle writes his coordanites to a file you should
10run fs.delete(t.coordsfile) when your program finishes!
11if you don't then his coords will get all screwed up if he moved without updating his coords
12
13If you're using gps you can manually set coords and then update them
14heres some untested example code
15
16t = require("val_api")
17t.x, t.y, t.z = gps.locate(0.5)
18In this example orientation is still set to north by default,
19if you want to find orientation you'll need code that compares coords
20after you move, i might add this later but for now its up to you! ;)
21
22TODO:
23 Write saved positions to a file and read from it on startup.
24 Add automatic gps support, maybe with a bool config variable to turn it on or off.
25
26--]]
27local t = {}
28
29t.debug_level = 3
30
31t.logfile = "val_lib.log"
32t.coordsfile = "coords"
33t.posfile = "savedPositions"
34
35local file -- Used for file management lower down
36t.saved_positions = {}
37
38t.selectedSlot = turtle.getSelectedSlot()
39t.blocks_dug = 0
40
41-- How to increment depending on the orientation
42local zDiff = {
43 [0] = -1,
44 [1] = 0,
45 [2] = 1,
46 [3] = 0
47}
48
49local xDiff = {
50 [0] = 0,
51 [1] = 1,
52 [2] = 0,
53 [3] = -1
54}
55
56-- Needed for human readable input/output
57t.orientations = {
58 [0] = "north",
59 [1] = "east",
60 [2] = "south",
61 [3] = "west"
62}
63
64-- Unwanted items for clean inventory function.
65t.unWantedItems = {
66 "minecraft:cobblestone",
67 "minecraft:stone",
68 "minecraft:flint",
69 "minecraft:dirt",
70 "minecraft:sandstone",
71 "minecraft:gravel",
72 "minecraft:sand",
73 "minecraft:torch",
74 "minecraft:netherrack",
75 "minecraft:nether_brick",
76 "biomesoplenty:dirt",
77 "biomesoplenty:grass",
78 "biomesoplenty:flower_1",
79}
80
81function t.dumpCoords()
82 return {
83 x = t.x,
84 y = t.y,
85 z = t.z,
86 orientation = t.orientation,
87 }
88end
89
90function t.select(i)
91 t.selectedSlot = i
92 turtle.select(i)
93end
94
95function t.inTable(value, table)
96 for key, keyValue in pairs(table) do
97 if value == keyValue then
98 return true
99 end
100 end
101 return false
102end
103
104function t.cleanInventory()
105 local item
106 local prevSlot = turtle.getSelectedSlot()
107
108 for i=1,16 do
109 item = turtle.getItemDetail(i)
110 -- Makes sure item exists to avoid nil errors.
111 if item and t.inTable(item.name, t.unWantedItems) then
112 turtle.select(i)
113 turtle.dropDown(item.count) -- Drops all of the unwanted item
114 end
115 end
116 turtle.select(prevSlot) -- Leave no trace!
117end
118
119function t.writeToFile(msg, fileName, mode)
120 -- Function used by logging function.
121 -- i felt it was cleaner this way.
122 if mode == nil then
123 mode = "a" -- By default append
124 end
125
126 if fileName == nil then
127 t.log("[DEBUG] file to write to is nil, defaulting to "..t.logfile, 4)
128 file = t.logfile -- default
129 end
130
131 if msg == nil then
132 t.log("[ERROR] msg is nil in function t.writeToFile", 1)
133 return
134 end
135
136 file = fs.open(fileName, mode)
137
138 if not file then
139 t.log("[ERROR] Failed to open "..fileName, 0)
140 return
141 end
142
143 file.write(msg.."\n") -- Adds newline
144 file.close()
145end
146
147function t.log(msg, msg_debug_level)
148 -- Logging function
149
150 if msg_debug_level == nil then
151 t.writeToFile("[WARNING] msg_debug_level is nil, defaulting to level 3 message info.", t.logfile)
152 -- As a param this is already local.
153 msg_debug_level = 3
154 end
155
156 if msg_debug_level <= t.debug_level then
157 t.writeToFile(msg, t.logfile)
158 end
159 -- Terminate the program if the message level is fatal.
160 if msg_debug_level == 0 then
161 print(msg)
162 error()
163 end
164end
165
166-- Get coords from file if file does not exist create one and set coords to 0,0,0,0
167function t.init()
168 local coords
169 local contents
170 if t.coordsfile == nil then
171 t.log("[ERROR] t.coordsfile is nil", 1)
172 t.log("[WARNING] Without a coords file persistance will fail", 2)
173 return -- Breaks from this function
174 end
175
176 if not fs.exists(t.coordsfile) then
177 t.log("[WARNING] t.coordsfile does not exist", 2)
178 t.log("[INFO] Creating coordsfile...", 3)
179 -- Creates coords file with 0,0,0,0 as values.
180 t.writeToFile(textutils.serialize(
181 {
182 x = 0,
183 y = 0,
184 z = 0,
185 orientation = 0
186 }),
187 t.coordsfile,
188 "w")
189
190 if not fs.exists(t.coordsfile) then
191 t.log("[FATAL] Failed to create "..t.coordsfile, 0)
192 end
193 end
194
195 file = fs.open(t.coordsfile, "r") -- Opens coordsfile for reading.
196 if file == nil then
197 t.log("[FATAL] Failed to open coordsfile, file is nil", 0)
198 end
199
200 contents = file.readAll()
201 file.close()
202
203 if contents == nil then
204 t.log("[FATAL] Failed to read file contents", 0)
205 end
206
207 t.log("[DEBUG] Read file contents, trying to unserialize it", 4)
208 coords = textutils.unserialize(contents)
209 if type(coords) ~= "table" then
210 t.log("[FATAL] failed to unserialize contents, coords is not a table, it is a "..type(coords), 0)
211 end
212
213 -- Sets coordanites
214 t.log("[DEBUG] Got coordanites from file, they are\n"..textutils.serialize(coords), 4)
215 t.x = coords.x
216 t.y = coords.y
217 t.z = coords.z
218
219 -- Sets orientation
220 t.orientation = coords.orientation
221
222 -- Gets saved positions
223 t.getSavedPositions()
224 -- Not going to return a value since i'll just change the varables.
225end
226
227-- Saves coordanites to file
228function t.saveCoords()
229 local c = {
230 x = t.x,
231 y = t.y,
232 z = t.z,
233 orientation = t.orientation
234 }
235 c = textutils.serialize(c)
236
237 t.log("[DEBUG] Updating "..t.coordsfile.."\n"..c, 4)
238 t.writeToFile(c, t.coordsfile, "w")
239end
240
241local function orientationToNumber(orientationStr)
242 -- Turns an orientation string into an Orientation number.
243 for i=0,#t.orientations do
244 if orientationStr == t.orientations[i] then
245 return i
246 end
247 end
248end
249
250-- Turns an orientation number into an t.orientation string.
251local function orientationToString(orientationInt)
252 -- Checks to see if orientationInt is a number
253 if type(orientationInt) ~= "number" then
254 t.log("[FATAL] orientationInt is not a number", 0)
255 end
256 if orientations[orientationInt] then
257 return t.orientations[orientationInt]
258 else
259 print("[FATAL] orientation is invalid", 0)
260 print("orientationInt = "..orientationInt)
261 end
262end
263
264-- Turning functions
265function t.turnRight()
266 turtle.turnRight()
267 -- This "magic" math adds one to t.orientation unless t.orientation is 3, then it moves to 0.
268 -- This could also be done with an if statement but this is cleaner imo
269 t.orientation = (t.orientation + 1) % 4
270 t.saveCoords()
271end
272
273function t.turnLeft()
274 turtle.turnLeft()
275 t.orientation = (t.orientation - 1) % 4
276 t.saveCoords()
277end
278
279-- Looks to a direction, can be passed a string or a number
280function t.look(direction)
281 -- makes sure the value passed is valid.
282 if type(direction) == "string" then
283 direction = orientationToNumber(direction)
284 elseif type(direction) ~= "number" then
285 error("Direction is not a number")
286 end
287
288 -- Thanks to Incin for this bit of code :)
289 if direction == t.orientation then return end
290
291 if (direction - t.orientation) % 2 == 0 then
292 t.turnLeft()
293 t.turnLeft()
294 elseif (direction - t.orientation) % 4 == 1 then
295 t.turnRight()
296 else
297 t.turnLeft()
298 end
299end
300
301function t.forward()
302 if turtle.forward() then
303 -- Change t.x and t.z coords
304 t.x = t.x + xDiff[t.orientation]
305 t.z = t.z + zDiff[t.orientation]
306
307 t.saveCoords()
308 return true
309 else
310 -- If he failed to move return false and don't change the coords.
311 return false
312 end
313end
314
315function t.up()
316 t.log("[DEBUG] t.up function called", 4)
317 if turtle.up() then
318 t.y = t.y + 1
319 t.log("[DEBUG] Trying to save coords to file after going up", 4)
320 t.saveCoords()
321 return true
322 else
323 return false
324 end
325end
326
327function t.down()
328 if turtle.down() then
329 t.y = t.y - 1
330 t.saveCoords()
331 return true
332 else
333 return false
334 end
335end
336
337function t.digDown()
338 if turtle.digDown() then
339 t.blocks_dug = t.blocks_dug + 1
340 return true
341 else
342 return false
343 end
344end
345function t.dig()
346 if turtle.dig() then
347 t.blocks_dug = t.blocks_dug + 1
348 return true
349 else
350 return false
351 end
352end
353function t.digUp()
354 if turtle.digUp() then
355 t.blocks_dug = t.blocks_dug + 1
356 return true
357 else
358 return false
359 end
360end
361
362-- This function saves the turtles position so it can be returned to later.
363function t.saveCurrentPos(name)
364 if type(name) ~= "string" then
365 error("Position name must be a string.")
366 end
367
368 -- Creates a new table entry with "name" key
369 t.saved_positions[name] = {
370 x = t.x,
371 y = t.y,
372 z = t.z,
373 orientation = t.orientation
374 }
375 t.savePositionsToFile()
376end
377
378function t.savePositionsToFile()
379 t.writeToFile(textutils.serialize(t.saved_positions), t.posfile, "w")
380end
381
382function t.getSavedPositions()
383 if fs.exists(t.posfile) then
384 file = fs.open(t.posfile, "r")
385 local data = file.readAll()
386 file.close()
387
388 local positions = textutils.unserialize(data)
389 if type(positions) ~= "table" then
390 t.log("[ERROR] Failed to unserialize positions", 1)
391 return nil
392 end
393
394 return positions
395 else
396 -- Create one
397 local positions = {}
398 t.writeToFile(textutils.serialize(positions), t.posfile, "w")
399 return positions
400 end
401end
402
403function t.getPos()
404 if fs.exists(t.posfile) then
405 file = fs.open(t.posfile, "r")
406 t.saved_positions = textutils.unserialize(file.readAll())
407 file.close()
408 else
409 error("No file to get positions from.")
410 end
411end
412
413function t.gotoPos(name)
414 if t.saved_positions[name] == nil then error("[ERROR] t.saved_positions["..name.."] is nil") end
415 for i,v in ipairs(t.saved_positions[name]) do print(i,v) end -- temp
416
417 t.goto(t.saved_positions[name].x, t.saved_positions[name].y, t.saved_positions[name].z, t.saved_positions[name].orientation)
418end
419
420-- Careful this breaks blocks.
421function t.goto(xTarget, yTarget, zTarget, orientationTarget)
422 if not xTarget or not yTarget or not zTarget or not orientationTarget then
423 t.log('[DEBUG] Here are all the params for the goto function:', 4)
424 t.log('xTarget='..xTarget..'yTarget='..yTarget..'zTarget='..zTarget..'orientationTarget='..orientationTarget, 4)
425 error('t.goto Can\'t travel to nil!, read logs for more info')
426 end
427 -- Moves to t.y
428 while yTarget < t.y do
429 t.digDown()
430 t.down()
431 while turtle.attackDown() do end
432 end
433
434 while yTarget > t.y do
435 t.digUp()
436 t.up()
437 while turtle.attackUp() do end
438 end
439
440 -- Turns to correct t.orientation then moves forward until its at the right t.x cord
441 if xTarget < t.x then
442 t.look('west')
443 while xTarget < t.x do
444 t.dig()
445 t.forward()
446 while turtle.attack() do end
447 end
448 end
449
450 if xTarget > t.x then
451 t.look('east')
452 while xTarget > t.x do
453 t.dig()
454 t.forward()
455 while turtle.attack() do end
456 end
457 end
458
459 -- Turns to correct t.orientation then moves forward until its at the right t.z cord
460 if zTarget < t.z then
461 t.look('north')
462 while zTarget < t.z do
463 t.dig()
464 t.forward()
465 while turtle.attack() do end
466 end
467 end
468 if zTarget > t.z then
469 t.look('south')
470 while zTarget > t.z do
471 t.dig()
472 t.forward()
473 while turtle.attack() do end
474 end
475 end
476 -- Look to correct orientation
477 t.look(orientationTarget)
478end
479
480function t.calcFuelForPos(posName)
481 if posName == nil then
482 t.log("[FATAL] pos is nil in t.calcFuelForPos", 0)
483 elseif not t.saved_positions[posName] then
484 t.log("[FATAL] t.saved_positions["..tostring(posName).."] Does not exist", 0)
485 else
486 local fuelNeeded = 0
487 pos = t.saved_positions[posName]
488
489 fuelNeeded = fuelNeeded + (math.abs(pos.x) - math.abs(t.x))
490 fuelNeeded = fuelNeeded + (math.abs(pos.y) - math.abs(t.y))
491 fuelNeeded = fuelNeeded + (math.abs(pos.z) - math.abs(t.z))
492
493 t.log("[INFO] "..tostring(fuelNeeded).." Fuel needed to go to "..posName.." From "..textutils.serialize(t.dumpCoords()))
494 return math.abs(fuelNeeded)
495 end
496end
497t.init()
498return t