feat(inferium-harvester)!: add replant procedure

This commit is contained in:
Guillaume ARM 2024-05-20 19:03:34 +02:00
parent 51e93081a1
commit 0b724c7334
2 changed files with 276 additions and 10 deletions

View File

@ -1,13 +1,88 @@
local turtleUtils = require('libs/turtle-utils')
local config = require('config/harvesting')
local VERSION = "0.4.2"
local VERSION = "0.5.0
local IDLE_TIME = 2
local MIN_FUEL_NEEDED = (10 + config.firstCropZ + config.length) * 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) do
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')
@ -32,9 +107,35 @@ local function retrieveChestFuelOrientation()
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
@ -65,7 +166,7 @@ local function retrieveHomePositionProcedure()
while true do
if turtleUtils.getInventory('bottom') then
return
break
end
if turtle.inspect() then
@ -74,6 +175,8 @@ local function retrieveHomePositionProcedure()
turtle.forward()
end
end
turtle.turnLeft()
end
local function dropAllProcedure()
@ -91,18 +194,16 @@ local function dropAllProcedure()
end
local function refuelProcedure()
turtle.turnLeft()
local refuelOk, refuelErr = turtleUtils.refuelWithBuffer('bottom', 'front', MIN_FUEL_NEEDED, IDLE_TIME)
if not refuelOk then
error('Cannot refuel the turtle: "' .. refuelErr .. '"')
end
turtle.turnLeft()
end
local function goToHarvestPoint()
turtle.turnLeft()
for i=1, config.firstCropZ, 1 do
turtle.forward()
end
@ -112,6 +213,14 @@ 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()
@ -130,11 +239,10 @@ local function harvestDown()
error('turtle cannot place crop')
end
if turtleUtils.countFreeSlots() < MIN_FREE_SLOTS_BEFORE_COMPACT then
turtleUtils.compactInventory()
end
compactIfNeeded()
end
local function forward()
if not turtle.forward() then
error('turtle is blocked')
@ -164,6 +272,151 @@ local function harvestProcedure()
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)
removeSeeds(seedsToRemove)
retrieveSeeds(seedsToPlant)
replantSeeds()
end
-- Main procedure
local function main()
print("Starting Trap's inferium harvester v" .. VERSION)
@ -180,6 +433,8 @@ local function main()
dropAllProcedure()
refuelProcedure()
replantProcedure()
goToHarvestPoint()
harvestProcedure()
goBackToHome()

View File

@ -181,6 +181,17 @@ turtleUtils.selectItemByName = function(itemName)
return false
end
turtleUtils.selectItemBy = function(predicate)
for i = 1, 16, 1 do
if predicate(i) then
turtle.select(i)
return true
end
end
return false
end
turtleUtils.refuel = function(minFuel, suckFn, sleepTime)
suckFn = suckFn or turtle.suck
sleepTime = sleepTime or DEFAULT_IDLE_TIME