minecraft-cc-tools/inferium-harvester.lua

450 lines
8.4 KiB
Lua

local turtleUtils = require('libs/turtle-utils')
local config = require('config/harvesting')
local VERSION = "0.5.0"
local IDLE_TIME = 2
local WAIT_ITEM_IDLE_TIME = 5
local MIN_FUEL_NEEDED = (100 + config.firstCropZ + config.length) * 2
local MIN_FREE_SLOTS_BEFORE_COMPACT = 4
local function mystical(essenceName)
return 'mysticalagriculture:' .. essenceName .. '_seeds'
end
local fakeRemotePlan = {
mystical('coal'),
mystical('diamond'),
mystical('quartz'),
mystical('dye'),
mystical('inferium'),
mystical('inferium'),
mystical('inferium'),
mystical('inferium')
}
-- a table with the list of current crops
local localPlan = nil
-- UTILS
local function difference(a, b)
local aa = {}
for k,v in pairs(a) do aa[v]=true end
for k,v in pairs(b) do aa[v]=nil end
local ret = {}
local n = 0
for k,v in pairs(a) do
if aa[v] then n=n+1 ret[n]=v end
end
return ret
end
local function shallowClone(t)
local res = {}
for k,v in pairs(t) do
res[k] = v
end
return res
end
local function removeFirst(t, x)
local res = {}
local removed = false
for k,v in pairs(t) do
if not removed and x == v then
removed = true
else
table.insert(res, v)
end
end
end
local function find(t, predicate)
for k,v in pairs(t) do
if predicate(v, k) then
return v, k
end
end
end
local function getIndexedCount(t)
local res = {}
for k,v in pairs(t) do
local count = res[v] or 0
res[v] = count + 1
end
return res
end
local function assertEnoughFuel()
if turtle.getFuelLevel() < MIN_FUEL_NEEDED then
error('Not enough fuel')
end
end
local function retrieveChestFuelOrientation()
local inventoryFound = false
for i=1, 4, 1 do
if turtleUtils.getInventory('front') then
inventoryFound = true
break
end
turtle.turnRight()
end
if not inventoryFound then
error('chest fuel not found')
end
end
local function getSeedNameFromCropName(cropName)
if not cropName then
return cropName
end
return string.gsub(cropName, 'crop', 'seeds')
end
function isSeed(item)
local tags = item.tags or {}
return tags['forge:seeds'] or tags['mysticalagriculture:seeds'] or false
end
-- Inventory utils
-- the slot of the item is returned
local function waitForItem(inventory, itemName, count, sleepTime)
sleepTime = sleepTime or 5 -- TODO: DEFAULT_IDLE_TIME
while true do
for slot, item in pairs(inventory.list()) do
if item.name == itemName and item.count >= count then
return slot
end
end
os.sleep(IDLE_TIME)
end
end
-- Implementations
local function retrieveHomePositionProcedure()
if turtleUtils.getInventory('bottom') then
retrieveChestFuelOrientation()
return
end
turtle.turnRight()
if turtle.inspect() then
turtle.turnRight()
end
while true do
if turtleUtils.getInventory('bottom') then
turtle.turnLeft()
return
end
if turtle.inspect() then
break
else
turtle.forward()
end
end
turtle.turnLeft()
turtle.turnLeft()
while true do
if turtleUtils.getInventory('bottom') then
break
end
if turtle.inspect() then
error('Cannot retrieve home position')
else
turtle.forward()
end
end
turtle.turnLeft()
end
local function dropAllProcedure()
for i=1, 16, 1 do
local count = turtle.getItemCount(i)
if count > 0 then
turtleUtils.waitForInventory('bottom', IDLE_TIME)
while not turtleUtils.dropSlot(i, turtle.dropDown) do
os.sleep(IDLE_TIME)
end
end
end
end
local function refuelProcedure()
local refuelOk, refuelErr = turtleUtils.refuelWithBuffer('bottom', 'front', MIN_FUEL_NEEDED, IDLE_TIME)
if not refuelOk then
error('Cannot refuel the turtle: "' .. refuelErr .. '"')
end
end
local function goToHarvestPoint()
turtle.turnLeft()
for i=1, config.firstCropZ, 1 do
turtle.forward()
end
end
local function goBackToHome()
for i=1, config.firstCropZ, 1 do
turtle.forward()
end
turtle.turnLeft()
end
local function compactIfNeeded()
if turtleUtils.countFreeSlots() < MIN_FREE_SLOTS_BEFORE_COMPACT then
turtleUtils.compactInventory()
end
end
local function harvestDown()
local cropName = turtleUtils.waitForMatureCrop(turtle.inspectDown, IDLE_TIME)
local seedName = getSeedNameFromCropName(cropName)
if not turtle.digDown() then
error('turtle cannot harvest crop')
end
if not turtleUtils.selectItemByName(seedName) then
error('turtle cannot find any crop to place')
end
if not turtle.placeDown() then
error('turtle cannot place crop')
end
compactIfNeeded()
end
local function forward()
if not turtle.forward() then
error('turtle is blocked')
end
end
local function harvestProcedure()
for i=1, config.length, 1 do
harvestDown()
if i ~= config.length then
forward()
end
end
turtle.turnLeft()
turtle.turnLeft()
for i=1, config.length, 1 do
if config.energySaving then
harvestDown()
end
if i ~= config.length then
forward()
end
end
end
local function retrieveLocalPlan()
goToHarvestPoint()
localPlan = {}
for i=1, config.length, 1 do
local ok, block = turtle.inspectDown()
local blockName = block and block.name
localPlan[i] = getSeedNameFromCropName(blockName)
if i ~= config.length then
forward()
end
end
turtle.turnLeft()
turtle.turnLeft()
for i=1, config.length, 1 do
if i ~= config.length then
forward()
end
end
goBackToHome()
end
local function fetchRemotePlan()
-- TODO
return fakeRemotePlan
end
local function removeSeeds(seeds)
goToHarvestPoint()
local stateSeeds = seeds
for i=1, config.length, 1 do
local ok, block = turtle.inspectDown()
local blockName = block and block.name
local found = find(stateSeeds, function(seedName) return seedName == getSeedNameFromCropName(blockName) end)
if found then
local digOk = turtle.digDown()
compactIfNeeded()
if not digOk then
error('cannot remove seed')
end
stateSeeds = removeFirst(stateSeeds, found)
end
if i ~= config.length then
forward()
end
end
turtle.turnLeft()
turtle.turnLeft()
for i=1, config.length, 1 do
if i ~= config.length then
forward()
end
end
goBackToHome()
dropAllProcedure()
end
local function retrieveSeeds(seeds)
local seedsCount = getIndexedCount(seeds)
local storageInventory = turtleUtils.waitForInventory('bottom', WAIT_ITEM_IDLE_TIME)
local bufferInventory = turtleUtils.waitForInventory('front', WAIT_ITEM_IDLE_TIME)
for seedName, count in pairs(seedsCount) do
local slot = waitForItem(storageInventory, seedName, count, WAIT_ITEM_IDLE_TIME)
local pushOk = storageInventory.pushItems(peripheral.getName(bufferInventory), slot, count)
if not pushOk then
error('retrieveSeeds error: cannot pushItems from storage to buffer')
end
local suckOk = turtle.suck()
if not suckOk then
error('retrieveSeeds error: cannot suck items from buffer')
end
end
end
local function replantSeeds()
goToHarvestPoint()
for i=1, config.length, 1 do
local ok, block = turtle.inspectDown()
if not ok then
turtleUtils.selectItemBy(function(slot)
local item = turtle.getItemDetail(slot, true)
return isSeed(item)
end)
turtle.placeDown()
end
if i ~= config.length then
forward()
end
end
turtle.turnLeft()
turtle.turnLeft()
for i=1, config.length, 1 do
if i ~= config.length then
forward()
end
end
goBackToHome()
end
local function replantProcedure()
if localPlan == nil then
retrieveLocalPlan()
end
local remotePlan = fetchRemotePlan()
if remotePlan == nil then
error('cannot fetch the remote plan')
end
local seedsToRemove = difference(localPlan, remotePlan)
local seedsToPlant = difference(remotePlan, localPlan)
if #seedsToRemove > 0 then
removeSeeds(seedsToRemove)
end
if #seedsToPlant > 0 then
retrieveSeeds(seedsToPlant)
replantSeeds()
end
end
-- Main procedure
local function main()
print("Starting Trap's inferium harvester v" .. VERSION)
turtleUtils.refuelAllFromInventory()
assertEnoughFuel()
print("> retrieving home position")
retrieveHomePositionProcedure()
print("> start the harvesting process")
while true do
dropAllProcedure()
refuelProcedure()
replantProcedure()
goToHarvestPoint()
harvestProcedure()
goBackToHome()
end
end
main()