Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
iovoid

iovoid's Farming Drone

Recommended Posts

Once I wanted to automatically farm using OpenComputers. First I made robot, but 1.7.10's block update stutter made active robot annihilate framerate. Thus I opted for entity-based agent and made code to operate drone for autonomous farming.

And now I decided to release the code for everyone to enjoy my work. Feel free to improve upon it, or use as is.

Example setup:

example_drone_farming_setup.png.fc8985710e0369e7956aa52c27e7cd49.png

Inventory of active drone:

example_drone_farming_inventory.png.e3bece7ec56bd17faa450d877b873347.png

Drone minimum components:

  • Drone Case (Tier 1)
  • Geolyzer
  • Inventory Upgrade
  • Central Processing Unit (CPU) (Tier 1)
  • Memory (Tier 1)
  • EEPROM with code provided

How to setup:

Drone never changes altitude and operates on single square area that may not be permanently obstructed. You must till farm plot manually. Drones always use global axes for movement, there's no rotation to keep track of. Adjust localX and localZ variables at start of code to designate dock area, drone must always boot up at dock, on top of charger with my example setup. If drone starts beeping upon bootup, you messed up the setup, drone is unable to locate inventory (or it's full). Drone also will start beeping at dock if output is full, just collect your obscene amount of produce when that occurs. minX/minZ/maxX/maxZ similarly define corners of farm plot. On my example setup screenshot player is facing north-west (towards negative X and negative Z), dock is at (15, 15), while most remote corner of farm plot is (0, 0). no_farm table contains exceptions where no farming operation should ever occur, using same local coordinate system. keep_seeds should allow for few missing plants to be replanted (but drone won't be able to deal with trampled fields automatically due to inability to use tools), you might want higher value if plant you are working with has chance to not drop seeds. ensure_space should be set to maximum amount of item types mature plant yields on breaking (2 being value for wheat or potatoes), otherwise you will suffer minor item loss if drone overflows. If two outputs are common (wheat), either use value of 1 or add another inventory upgrade. As I understand Minecraft farming mechanics, monoculture farming would not be faster than farming two plant types at once with plants being in lines. plant() contains logic for seed slot selection, adjust if you want to farm more than two types at single plot, but beware inventory constraints of drone and multiple outputs.

Code, goes into EEPROM of drone:

local d = component.proxy(component.list("drone", true)())
local g = component.proxy(component.list("geolyzer", true)())
local c = computer

d.setLightColor(0xff00ff)

local no_farm = {
[15] = { [15] = true, },
[12] = { [3] = true, [12] = true, },
[3] = { [3] = true, [12] = true, },
}
local to_collect = {
["minecraft:potatoes"] = true,
["minecraft:carrots"] = true,
}
local seed_slot = {
[1] = true,
[2] = true,
}
local keep_seeds = 4
local ensure_space = 2
local localX = 15
local localZ = 15
local minX = 0
local minZ = 0
local maxX = 15
local maxZ = 15
local inv_side = 1
local inv_name = "minecraft:chest"

local startX = localX
local startZ = localZ

local function sleep(sec)
  local dl = c.uptime() + sec
  repeat
    c.pullSignal(dl - computer.uptime())
  until c.uptime() >= dl
end

local function attn()
  c.beep(1500, 0.2)
  c.beep(1700, 0.2)
  c.beep(1300, 0.2)
  sleep(3)
end

local function plant()
  local slot = localX % 2 + 1
  if d.count(slot) > 1 then
    d.select(slot)
    if not d.place(0) then attn() end
  else
    attn()
  end
end

local first_free

local function got_free_slots(wanted, no_heur)
  local found = 0
  for slot = first_free or 1, d.inventorySize() do
    if d.count(slot) == 0 then
      found = found + 1
      first_free = first_free or slot
    end
    if found >= wanted then
      return true
    end
  end
  if first_free and not no_heur then
    first_free = nil
    return got_free_slots(wanted, true)
  end
  return false
end

local function farm()
  local found, desc = d.detect(0)
  if not found and desc == "air" then
    plant()
  elseif found and desc == "passable" then
    local block = g.analyze(0)
    if block ~= nil and block.growth ~= nil then
      if block.growth == 1 and to_collect[block.name] then
        d.select(1)
        d.swing(0)
        plant()
      end
    else
      attn()
    end
  else
    attn()
  end
end

local function put_away_excess()
  while true do
    local found, desc = d.detect(inv_side)
    if found and desc == "solid" then
      local block = g.analyze(inv_side)
      if block ~= nil and block.name == inv_name then break end
    end
    attn()
  end
  repeat
    local done = true
    for slot = 1, d.inventorySize() do
      local amt = d.count(slot)
      if amt > 0 then
        d.select(slot)
        local to_drop = math.huge
        if seed_slot[slot] then to_drop = amt - keep_seeds end
        if to_drop > 0 and not d.drop(inv_side, to_drop) then done = false attn() break end
      end
    end
  until done
  first_free = nil
end

local function vec_len(oX, oZ)
  return math.sqrt(oX*oX + oZ*oZ)
end

local function move_to(tgtX, tgtZ, precise)
  local offX = tgtX - localX
  local offZ = tgtZ - localZ
  if offX == 0 and offZ == 0 then return end
  d.move(offX, 0, offZ)
  local moved
  local goaldist = 0.45
  local goalvel = 2
  local timemult = 1
  if precise then
    goaldist = 0.1
    goalvel = 0.1
    timemult = timemult * 2
  end
  local dl = c.uptime() + vec_len(offX, offZ) * timemult
  repeat
    moved = d.getOffset() <= goaldist and d.getVelocity() <= goalvel
    if c.uptime() >= dl then break end
  until moved
  if moved then
    localX = localX + offX
    localZ = localZ + offZ
  else
    d.move(-offX, 0, -offZ)
    attn()
  end
end

local workX = startX
local workZ = startZ

local function next_spot()
  if workX < maxX then
    workX = workX + 1
  else
    workX = minX
    if workZ < maxZ then
      workZ = workZ + 1
    else
      workZ = minZ
    end
  end
  if no_farm[workX] ~= nil and no_farm[workX][workZ] then
    next_spot()
  end
  return workX, workZ
end

local function dock(optional)
  if optional and c.energy() >= 500 and got_free_slots(ensure_space) then return end
  move_to(startX, startZ, true)
  put_away_excess()
  while c.energy() < c.maxEnergy() - 500 do sleep(3) end
end

dock(false)

while true do
  dock(true)
  move_to(next_spot())
  farm()
end

License terms for my code:

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <https://unlicense.org/>

Ideas for improvement:

  • More robust detection of drone actually being at new position without slowing down operation. I've been adjusting goaldist and goalvel until drone stopped failing farm(), with no strong theory for what should be ideal values;
  • Change scanlines pattern into zig-zag pattern for minor increase in farming speed;
  • Have companion robot craft away wheat and similar things into cubes and/or fix trampled field;
  • Handling of plants not exposing "growth" to geolyzer, like Immersive Engineering's hemp;
  • Handling of multi-tile plants, like said hemp;
  • Rotating between many plant types with just few being planted at given time;
  • Melon and pumpkin farming (will likely release drone for that soon, as I already got stutter-inducing robot doing this).
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.