· 6 years ago · Dec 21, 2019, 08:06 AM
1local brshift, blshift, band, bor = bit.blogic_rshift, bit.blshift, bit.band, bit.bor
2
3-- Written by funnbot on 12/20/19
4-- TODO: check if a modem is present and send display output through it
5
6--[[ Setup:
7 Place the turtle on the top-left in the area you are going to quarry.
8 Place a deposit chest behind the turtle.
9 Run the program with dimensions.
10
11 If you are reseting or moving a labelled turtle then you must run the reset command before starting again.
12]]
13
14--[[ Optional Setup:
15 Automatic restore
16 Write `edit startup` in the turtle cli, write `shell.run("quarry", "10", "10", "10")`, you can still use
17 optional arguments ie. `shell.run("quarry", "-whitelist", "-refuel", "10", "10", "10")`, This setup will allow
18 for automatic restores if the server is restarted or the chunk gets unloaded. Otherwise restore will still work if
19 you run the command yourself with the same dimensions.
20 -blacklist
21 The default blacklist is minecraft:stone minecraft:dirt
22 Create a file called blacklist.txt by writing `edit blacklist.txt` in the turtle cli,
23 then on each newline you can place a full block id ie. minecraft:stone,
24 Make sure you save the file.
25 The turtle will still have to mine any block that is in its way, however it will avoid blocks in the blacklist.
26 -whitelist
27 Create a file called whitelist.txt by writing `edit whitelist.txt` in the turtle cli,
28 then on each newline you can place a full block id ie. minecraft:stone,
29 Make sure you save the file.
30 The turtle will still have to mine any block that is in its way, however it will avoid blocks NOT in the whitelist.
31 -refuel
32 Place a refuel chest on the left side of the turtles starting position filled with coal.
33 -enderchest
34 The default whitelist is minecraft:stone
35 Place a ender chest (from ender storage) in the 16th item slot (bottom-right)
36 The turtle will place and break this block to unload its items, and does not require a chest placed behind its
37 starting position for usual unload
38]]
39
40--[[ Examples:
41 Quarry a 10x10x10 square> quarry 10 10 10
42 Quarry a 10x10x10 square and ignore block ids in the blacklist.txt file> quarry -blacklist 10 10 10
43 Quarry a 32x2x23 area, only mine block ids in the whitelist.txt file, and attempt to refuel from a chest to the left of the turtle
44 > quarry -whitelist -refuel 32 2 23
45 Quarry a 5x3x23 area, but place the turtle at the bottom and have it mine upwards
46 > quarry 5 -3 23
47]]
48
49-- Constants
50-- File names
51local stateFilename = "state.bin"
52local blacklistFilename = "blacklist.txt"
53local whitelistFilename = "whitelist.txt"
54
55-- Default tables
56local blacklist = { ["minecraft:stone"] = true, ["minecraft:dirt"] = true }
57local whitelist = { ["minecraft:stone"] = true }
58
59-- Global state
60-- Local position in relation to the starting position,
61-- dont want to require a GPS so no absolute positioning
62local pos = { x = 0, y = 0, z = 0 }
63-- Dimension parameters
64local dim = { x = 0, y = 0, z = 0 }
65-- optional parameters
66local optBlacklist, optWhitelist, optRefuel, optEnderChest = false,false,false,false
67
68-- {...} fills the args table with the arguments passed to the program
69local argv = { ... }
70local argc = #argv
71
72
73-- Print the usage for invalid commands
74if (argc ~= 1 and (argc < 3 or argc > 7)) or argv[1] == "help" then
75 print("Usage: "..shell.getRunningProgram().." [-blacklist] [-whitelist] [-refuel] [-enderchest] <width> <depth> <length>")
76 print(" [] - optional argument, <> - required argument. Do not include the brackets ([], <>) when actually running the command.")
77 print(" <width> - An int greater than zero, how far the quarry stretches to the right of the turtle")
78 print(" <depth> - An int greater than zero, how far the quarry stretches below the turtle. Make this value negative to quarry upwards.")
79 print(" -blacklist - Avoids breaking blocks in the blacklist.txt file, create this file in the root dir, and fill with block ids ie. minecraft:stone, each id on a newline.")
80 print(" -whitelist - Avoids breaking blocks NOT in the whitelist.txt file, creation and usage is the same as blacklist.txt except filename is whitelist.txt.")
81 print(" -refuel - Tries to pull fuel (coal) from a chest placed to the left of the turtles starting position.")
82 print("")
83 print("Reset Command: "..shell.getRunningProgram().." reset")
84 print(" Reset the saved state to start a new quarry, only necessary if the turtle is labelled")
85 return
86end
87
88if argv[1] == "reset" then
89 -- Deleting state file should be the only thing to reset
90 fs.delete(stateFilename)
91 print("Quarry state reset.")
92 return
93end
94
95-- Only gets run if there is no state to load, so the params are ignored.
96-- Return a bool for success
97local function loadAndValidateParameters()
98 -- Extra optional args to parse
99 if (argc - 3) > 0 then
100 -- loop from 1st element to argc-3
101 for i=1,argc-3 do
102 if argv[i] == "-blacklist" then optBlacklist = true
103 elseif argv[i] == "-whitelist" then optWhitelist = true
104 elseif argv[i] == "-refuel" then optRefuel = true
105 elseif argv[i] == "-enderchest" then optEnderChest = true
106 else
107 print("Invalid argument: "..argv[i]);
108 return false
109 end
110 end
111 end
112 -- Then parse the dimensions
113 dim.x = tonumber(argv[argc - 2])
114 dim.y = tonumber(argv[argc - 1])
115 dim.z = tonumber(argv[argc - 0])
116 -- validate dimensions
117 if dim.x <= 0 or dim.z <= 0 then
118 print("Invalid dimensions: must be greater than zero.")
119 return false
120 end
121
122 -- modf returns the int and fractional parts, ignore the int part, and test if fractional isnt zero
123 local _, xf, _, yf, _, zf = math.modf(dim.x), math.modf(dim.y), math.modf(dim.z)
124 if xf ~= 0 or yf ~= 0 or zf ~= 0 then
125 print("Invalid dimensions: floating point not allowed.")
126 return false
127 end
128 -- Success
129 return true
130end
131
132--# Read Text files
133
134-- Opens the file name, if it succeeds then it clears the outlist and writes new values = split(fileText, "\n")
135-- otherwise it won't edit the outList, so keep its default value
136local function readList(fileName, outList)
137
138end
139
140--# Restore State Functions
141
142-- writes num to filehandle
143local lowerByteMask = bit.bnot(255)
144local function writeInt(fileHandle, num)
145 -- cautionary, however its use in saveState means it will always be open
146 if fileHandle == nil then return end
147
148 -- Starting with the first 8 bits, mask then shift right
149 -- TEST: band might be unnecessary if the char function chops instead of wraps or something else wierd
150 local b1 = band(num, lowerByteMask)
151 num = brshift(num, 8)
152 local b2 = band(num, lowerByteMask)
153 num = brshift(num, 8)
154 local b3 = band(num, lowerByteMask)
155 num = brshift(num, 8)
156 local b4 = band(num, lowerByteMask)
157 num = brshift(num, 8)
158
159 fileHandle.write(string.char(b4, b3, b2, b1))
160end
161
162-- Save the current pos of the turtle, and the params given for a restore
163local function saveState()
164 -- w to overwrite if it exists or not
165 local stateFD = fs.open(stateFilename, "w");
166
167 if stateFD == nil then
168 print("Error: failed to create a file to save state. Filename: " .. stateFilename)
169 return
170 end
171
172 -- Order is constant and important
173 writeInt(stateFD, pos.x);
174 writeInt(stateFD, pos.y);
175 writeInt(stateFD, pos.z);
176 writeInt(stateFD, dim.x);
177 writeInt(stateFD, dim.y);
178 writeInt(stateFD, dim.z);
179
180 -- TEST: ternary operation is jank
181 local opts = 0
182 opts = bor(opts, optBlacklist and 0 or 2^0)
183 opts = bor(opts, optWhitelist and 0 or 2^1)
184 opts = bor(opts, optRefuel and 0 or 2^2)
185 opts = bor(opts, optEnderChest and 0 or 2^3)
186
187 -- Mask is just one byte
188 stateFD.write(opts)
189
190 stateFD.close()
191end
192
193-- Reads an int from the file handle (probably works for doubles aswell as they are both 64bit)
194local function readInt(fileHandle)
195 -- cautionary, however its use in loadState means it will always be open
196 if fileHandle == nil then return 0 end
197
198 -- TEST: first time working with lua bitwise no idea how funky it is
199 local b4, b3, b2, b1 = fileHandle.read(), fileHandle.read(), fileHandle.read(), fileHandle.read()
200 local num = blshift.byte(b4, 8 * 3)
201 num = bor(num, blshift(b3, 8* 2))
202 num = bor(num, blshift(b2, 8* 1))
203 num = bor(num, b1)
204
205 return num
206end
207
208-- Load the current pos and params from the state file if it exists
209-- Returns a boolean for success
210local function loadState()
211 -- Open file as read only to test if it exists
212 local stateFD = fs.open(stateFilename, "r")
213 -- Don't load state and instead keep pos at 0,0,0, and params as what was passed to the program
214 if stateFD == nil then return false end;
215
216 -- state ordering is constant
217 pos.x = readInt(stateFD)
218 pos.y = readInt(stateFD)
219 pos.z = readInt(stateFD)
220 dim.x = readInt(stateFD)
221 dim.y = readInt(stateFD)
222 dim.z = readInt(stateFD)
223
224 -- mask ordering is constant
225 local opts = stateFD.read();
226 optBlacklist = band(opts, 2^0)
227 optWhitelist = band(opts, 2^1)
228 optRefuel = band(opts, 2^2)
229 optEnderChest = band(opts, 2^3)
230
231 --TEST: is it necessary to close?
232 stateFD.close()
233 return true
234end
235
236--# Turtle Control Functions
237
238
239-- Main quarry section
240
241-- If no state to load then validate options provided
242--[[if not loadState() then
243 -- If validate fails then return early
244 if not loadAndValidateParameters() then return end
245end]]
246
247optEnderChest = true
248dim.x = 10
249saveState()
250optEnderChest = false
251dim.y = 10
252dim.x = 3
253optBlacklist = true
254loadState()
255print(optEnderChest)
256print(optBlacklist)
257print(dim.x)
258print(dim.y)