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 |