SHOW:
|
|
- or go back to the newest paste.
1 | --[[ | |
2 | Copyright (c) 2019, David Moore | |
3 | All rights reserved. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are met: | |
7 | ||
8 | 1. Redistributions of source code must retain the above copyright notice, this | |
9 | list of conditions and the following disclaimer. | |
10 | 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 | this list of conditions and the following disclaimer in the documentation | |
12 | and/or other materials provided with the distribution. | |
13 | ||
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | ||
25 | The views and conclusions contained in the software and documentation are those | |
26 | of the authors and should not be interpreted as representing official policies, | |
27 | either expressed or implied, of the <project name> project. | |
28 | ]] | |
29 | ||
30 | -- Ladies and gentlemen, my killbot has Lotus Notes and a machine gun. It is the finest available. | |
31 | ||
32 | -- turn this on to enable debug logging | |
33 | logging = false | |
34 | -- where to write the things | |
35 | logfile = "/autocrafter9000.log" | |
36 | ||
37 | -- chest on the left of the computer, ME interface on the right | |
38 | chest = peripheral.wrap("left") | |
39 | interface = peripheral.wrap("right") | |
40 | ||
41 | -- time to sleep between checks | |
42 | sleepSeconds = 3 | |
43 | ||
44 | -- how frequently, in seconds, to print an error if something cannot be crafted | |
45 | -- due to missing components | |
46 | warningFreq = 120 | |
47 | ||
48 | function logEvent(str) | |
49 | if logging then | |
50 | f = fs.open(logfile, "a") | |
51 | f.writeLine(str) | |
52 | f.close() | |
53 | print(str) | |
54 | end | |
55 | end | |
56 | ||
57 | function newItemHolder(name,dmg,count,job) | |
58 | t = {} | |
59 | t["name"] = name | |
60 | t["dmg"] = 0 + dmg | |
61 | t["count"] = 0 + count | |
62 | t["job"] = job | |
63 | t["key"] = name .. "@" .. dmg | |
64 | return t | |
65 | end | |
66 | ||
67 | itemsPersistent = {} | |
68 | warnedItemTimes = {} | |
69 | ||
70 | -- get list of items in teh chest. This will return an entry for each stack | |
71 | -- so we need to process it further (for items that we want more than 64 of) | |
72 | while true do | |
73 | chestList = chest.list() | |
74 | chestTotals = {} | |
75 | for k,v in pairs(chestList) do | |
76 | theItem = newItemHolder(v.name,v.damage,v.count,nil) | |
77 | logEvent("Got chest stack " .. theItem["name"] .. "@" .. theItem["dmg"] .. " qty " .. theItem["count"]) | |
78 | -- we need to add the stacks together to get real totals | |
79 | if chestTotals[theItem["key"]] then | |
80 | chestTotals[theItem["key"]] = chestTotals[theItem["key"]] + theItem["count"] | |
81 | else | |
82 | chestTotals[theItem["key"]] = theItem["count"] | |
83 | end | |
84 | -- if our persistent item store (which contains in-progress crafting jobs) does not have this item, then add it | |
85 | -- the only way we can prevent multiple redundant crafting jobs, that i have found, is to save the job object | |
86 | -- and check if it is still in progress. I haven't found a way to interrogate the interface for jobs in-progress | |
87 | if not itemsPersistent[theItem["key"]] then | |
88 | itemsPersistent[theItem["key"]] = theItem | |
89 | end | |
90 | end | |
91 | ||
92 | for chestItemName,chestItemCount in pairs(chestTotals) do | |
93 | craftOkay = false | |
94 | logEvent("After chest item processing, got chest item " .. chestItemName .. " qty " .. chestItemCount) | |
95 | networkItemSearchResult = interface.findItems(chestItemName) | |
96 | --logEvent(networkItemSearchResult) | |
97 | if networkItemSearchResult[1] then | |
98 | metadata = networkItemSearchResult[1].getMetadata() | |
99 | networkItemCount = metadata.count | |
100 | logEvent("Got network item " .. chestItemName .. " qty " .. networkItemCount) | |
101 | ||
102 | -- if there is less in the network on the right than in the chest on the left | |
103 | if networkItemCount < chestItemCount then | |
104 | diff = chestItemCount - networkItemCount | |
105 | ||
106 | -- check if we have a crafting job stored for this item, and whether it's finished | |
107 | if itemsPersistent[chestItemName]["job"] then | |
108 | if itemsPersistent[chestItemName]["job"].isFinished() then | |
109 | okayToCraft = true | |
110 | itemsPersistent[chestItemName]["job"] = nil | |
111 | else | |
112 | okayToCraft = false | |
113 | end | |
114 | else | |
115 | okayToCraft = true | |
116 | end | |
117 | ||
118 | -- check if there is an available CPU | |
119 | availableCPU = false | |
120 | cpus = interface.getCraftingCPUs() | |
121 | for k,v in pairs(cpus) do | |
122 | if v.busy == false then | |
123 | availableCPU = true | |
124 | end | |
125 | end | |
126 | ||
127 | if not availableCPU then | |
128 | okayToCraft = false | |
129 | -- print("No CPUs available, skipping") | |
130 | end | |
131 | ||
132 | if okayToCraft then | |
133 | -- save the crafting job in the persistent store | |
134 | itemsPersistent[chestItemName]["job"] = networkItemSearchResult[1].craft(diff) | |
135 | if itemsPersistent[chestItemName]["job"].status() == "missing" then | |
136 | if warnedItemTimes[chestItemName] then | |
137 | if os.clock() - warnedItemTimes[chestItemName] > warningFreq then | |
138 | okayToPrint = true | |
139 | else | |
140 | okayToPrint = false | |
141 | end | |
142 | else | |
143 | okayToPrint = true | |
144 | end | |
145 | if okayToPrint then | |
146 | warnedItemTimes[chestItemName] = os.clock() | |
147 | print("Missing Components! Cannot craft " .. diff .. " of " .. chestItemName) | |
148 | end | |
149 | else | |
150 | craftOkay = true | |
151 | end | |
152 | -- check if the job failed. haven't bothered to test this functionality yet. | |
153 | -- it should kick in if all CPUs are in use or some such | |
154 | if not itemsPersistent[chestItemName]["job"] then | |
155 | print("Could not craft ".. diff .. " of " .. chestItemName) | |
156 | craftOkay = false | |
157 | end | |
158 | else | |
159 | logEvent("Not crafting " .. chestItemName .. " because of crafting job in progress") | |
160 | craftOkay = false | |
161 | end | |
162 | else | |
163 | warnedItemTimes[chestItemName] = nil | |
164 | end | |
165 | if craftOkay then | |
166 | warnedItemTimes[chestItemName] = nil | |
167 | logEvent("Submitted order for " .. diff .. " of " .. chestItemName) | |
168 | print("Submitted order for " .. diff .. " of " .. chestItemName) | |
169 | end | |
170 | end | |
171 | end | |
172 | os.sleep(sleepSeconds) | |
173 | end |