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