Skip to content

Instantly share code, notes, and snippets.

@LexManos
Last active January 2, 2020 08:55
Show Gist options
  • Save LexManos/d75263abbd339c0e8d8bdfa817033b1c to your computer and use it in GitHub Desktop.
Save LexManos/d75263abbd339c0e8d8bdfa817033b1c to your computer and use it in GitHub Desktop.
Re-worked version of Computercraft control for Compact Machines.
-- APIs
local robot = require("robot")
local component = require("component")
local computer = require("computer")
local me = component.upgrade_me
local db = component.database
local event = require("event")
local filesystem = require("filesystem")
local sides = require("sides")
local tunnel = component.tunnel
local inventory = component.inventory_controller
local recipes = {
wall = {
name = "Wall",
items = {
catalyst = {name = "minecraft:redstone", friendly = "Redstone Dust"},
top = {name = "minecraft:redstone", friendly = "Redstone Dust"},
bottom = {name = "minecraft:iron_block", friendly = "Iron Block" }
},
style = "wall"
},
tunnel = {
name = "Tunnel",
items = {
catalyst = {name = "minecraft:redstone", friendly = "Redstone Dust"},
top = {name = "minecraft:hopper", friendly = "Hopper" },
bottom = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
dust = {name = "minecraft:redstone", friendly = "Redstone Dust"}
},
style = "tunnel"
},
redTunnel = {
name = "Redsone Tunnel",
items = {
catalyst = {name = "minecraft:redstone", friendly = "Redstone Dust" },
top = {name = "minecraft:redstone_block", friendly = "Redstone Block"},
bottom = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
dust = {name = "minecraft:redstone", friendly = "Redstone Dust" }
},
style = "tunnel"
},
machine3 = {
name = "3x3 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl"},
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" }
},
style = "cube3"
},
machine5 = {
name = "5x5 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl"},
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
core = {name = "minecraft:iron_block", friendly = "Iron Block" }
},
style = "cube3"
},
machine7 = {
name = "7x7 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl"},
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
core = {name = "minecraft:gold_block", friendly = "Gold Block" }
},
style = "cube3"
},
machine9 = {
name = "9x9 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl"},
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" }
},
style = "cube5"
},
machine11 = {
name = "11x11 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl" },
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
core = {name = "minecraft:diamond_block", friendly = "Diamond Block"}
},
style = "cube5"
},
machine13 = {
name = "13x13 Machine",
items = {
catalyst = {name = "minecraft:ender_pearl", friendly = "Ender Pearl" },
wall = {name = "compactmachines3:wallbreakable", friendly = "Wall" },
core = {name = "minecraft:emerald_block", friendly = "Emerald Block"}
},
style = "cube5"
}
}
-- Visuals
function skipLine(number)
for i = 1, number do
print("")
end
end
function printLoad(percent)
if percent == "0" then
os.execute("cls")
skipLine(8)
print(" Loading. 0%")
elseif percent == "25" then
os.execute("cls")
skipLine(8)
print(" Loading.. 25%")
elseif percent == "50" then
os.execute("cls")
skipLine(8)
print(" Loading.. 50%")
elseif percent == "75" then
os.execute("cls")
skipLine(8)
print(" Loading. 75%")
elseif percent == "100" then
os.execute("cls")
skipLine(8)
print(" Loading.. 100%")
end
end
function writeTitle()
print(" ███████████████████████████████████████")
print(" █_|___|___|___|___|___|___|___|___|___█")
print(" █___|__██████╗███╗___███╗██████╗_|___|█")
print(" █_|___██╔════╝████╗ ████║╚════██╗_|___█")
print(" █___|_██║___|_██╔████╔██║ █████╔╝|___|█")
print(" █_|___██║_|___██║╚██╔╝██║ ╚═══██╗_|___█")
print(" █___|_╚██████╗██║_╚═╝_██║██████╔╝|___|█")
print(" █_|___|╚═════╝╚═╝_|___╚═╝╚═════╝__|___█")
print(" █___A Compact Machines 3 Autobuilder_|█")
print(" █_|___|___|___By: Samir___|___|___|___█")
print(" ███████████████████████████████████████")
end
-- Wireless Mode
function getWirelessVariable()
local file = io.open("wirelessVariable","r")
if file:read() == "true" then
modeWireless = true
print("modeWireless = true")
else
modeWireless = nil
print("modeWireless = nil")
file:close()
end
end
function activateWireless()
local file=io.open("wirelessVariable","w")
file:write("true")
file:close()
end
function deactivateWireless()
local file=io.open("wirelessVariable","w")
file:write("nil")
file:close()
computer.shutdown(true)
end
-- Inventory Management
function totalItem(name)
local size = 0
for i = 1,16 do
local data=inventory.getStackInInternalSlot(i)
if (data and data.name == name) then
size = size + data.size
end
end
return size
end
function selectItem(item)
for i = 1,16 do
local data = inventory.getStackInInternalSlot(i)
if (data and data.name == item.name) then
robot.select(i)
return true
end
end
return false
end
function findPartial(name, skip)
skip = skip or -1
for i = 1,16 do
if (i ~= skip) then
local data = inventory.getStackInInternalSlot(i)
if (data and data.name == name and data.size ~= data.maxSize) then
return i
end
end
end
return -1
end
function selectEmpty()
for i = 1,16 do
local data=inventory.getStackInInternalSlot(i)
if data == nil then
robot.select(i)
return
end
end
end
function emptyIntoME()
for i = 1,16 do
local data = inventory.getStackInInternalSlot(i)
if (data ~= nil) then
robot.select(i)
me.sendItems()
if (inventory.getStackInInternalSlot(i) ~= nil) then
return "Failed to store item in slot " .. i
end
end
end
return nil
end
-- Request Items
function requestItem(item, count)
count = count or 64
local have = 0 --totalItem(item.name)
--[[
if (have == count) then
return nil
end
--Send any extra we have back
while(have > count)
do
selectItem(item.name)
extra = math.min(have - count, robot.count())
sent = me.sendItems(extra)
if (sent == 0) then
return "Could not store excess " .. item.friendly
end
have -= sent
end
--]]
while (have < count)
do
local slot = findPartial(item.name)
local request = math.min(count - have, 64)
if (slot == -1) then -- No Matching partial slot, so grab an empty
selectEmpty()
else
robot.select(slot)
local stack = inventory.getStackInInternalSlot(slot)
request = math.min(count - have, stack.maxSize - stack.size)
end
db.clear(1)
me.store({name = item.name}, db.address, 1)
local existing = me.getItemsInNetwork({name = item.name})
if (db.get(1) == nil or existing.n == 0 or existing[1].size == 0) then
if (not tryCraftItem(item.name, count - have)) then
if (item.name == "compactmachines3:wallbreakable") then -- We can craft walls, so pop up how many we need
return math.ceil((count - have) / 16)
end
return "Could not craft " .. item.friendly
end
me.store({name = item.name}, db.address, 1)
end
if (db.get(1) == nil) then -- Something went fucky
return "Crafting " .. item.friendly .. " failed.. but ME said success"
end
--print("Requesting " .. request .. " " .. item.name)
local fetched = math.floor(me.requestItems(db.address, 1, request))
if (fetched == 0) then -- We failed, bail out
return "Failed to fetch " .. item.friendly
end
have = have + fetched
--print("Got: " .. have .. "/" .. count .. " " .. item.friendly)
end
return nil
end
function tryCraftItem(name, count)
local crafts = me.getCraftables({name = name})
if (crafts.n == 0) then
return false
end
local request = crafts[1].request(count)
while (not request.isDone() and not request.isCanceled())
do
os.sleep(2)
end
return not request.isCanceled()
end
function requestWall(items)
local ret = requestItem(items.catalyst, 1)
ret = ret or requestItem(items.top, 1)
ret = ret or requestItem(items.bottom, 1)
return ret
end
function requestTunnel(items)
local ret = requestItem(items.catalyst, 1)
ret = ret or requestItem(items.dust, 8)
ret = ret or requestItem(items.top, 1)
ret = ret or requestItem(items.bottom, 1)
return ret
end
function requestMachine3(items)
local ret = requestItem(items.catalyst, 1)
ret = ret or requestItem(items.wall, 26)
if (ret == nil and items.core ~= nil) then
ret = requestItem(items.core, 1)
end
return ret
end
function requestMachine5(items)
local ret = requestItem(items.catalyst, 1)
ret = ret or requestItem(items.wall, 98)
if (ret == nil and items.core ~= nil) then
ret = requestItem(items.core, 1)
end
return ret
end
-- Movement Functions
function forward(dist, place)
for i = 1, dist do
if (not robot.forward()) then
if (i > 1) then
backSimple(i - 1)
end
return "Ran into something solid"
end
if (place ~= nil) then
if (not selectItem(place)) then
backSimple(i)
return "Ran out of " .. place.friendly
end
if (not robot.placeDown()) then
return "Failed to place " .. place.friendly
end
end
end
end
function forwardSimple(dist)
for i = 1, dist do
robot.forward()
end
end
function back(dist, place)
for i = 1, dist do
if (not robot.back()) then
if (i > 1) then
forwardSimple(i - 1)
end
return "Ran into something solid"
end
if (place ~= nil) then
if (not selectItem(place)) then
forward(i)
return "Ran out of " .. place.friendly
end
if (not robot.placeDown()) then
return "Failed to place " .. place.friendly
end
end
end
end
function backSimple(dist)
for i = 1, dist do
robot.back()
end
end
function up(dist, place)
for i = 1, dist do
if (not robot.up()) then
if (i > 1) then
downSimple(i - 1)
end
return "Ran into something solid"
end
end
end
function upSimple(dist)
for i = 1, dist do
robot.up()
end
end
function down(dist)
for i = 1, dist do
if (not robot.down()) then
if (i > 1) then
upSimple(i - 1)
end
return "Ran into something solid"
end
end
end
function downSimple(dist)
for i = 1, dist do
robot.down()
end
end
function right(dist, place)
robot.turnRight()
ret = forward(dist, place)
if (ret ~= nil) then
robot.turnLeft()
end
return ret
end
function left(dist, place)
robot.turnLeft()
ret = forward(dist, place)
if (ret ~= nil) then
robot.turnRight()
end
return ret
end
-- Craft Functions
function place(place)
if (place ~= nil) then
if (not selectItem(place)) then
return "Ran out of " .. place.friendly
end
if (not robot.placeDown()) then
return "Failed to place " .. place.friendly
end
end
return nil
end
function pickupResults(delay)
os.sleep(delay) -- Sleep during animation
down(6)
robot.suck()
forward(7)
robot.turnRight()
robot.turnRight()
return nil
end
function craftWall(name, items, verbose)
local ret = requestWall(items)
if (ret ~= nil) then
return ret
end
if (verbose ~= false) then
display("Constructing " .. name)
end
-- Move forward 6, so we don't go over the hopper in the center, in case people build it with a auto-collector
forward(6)
up(1)
forward(1, items.bottom)
up(1)
place(items.top)
up(4)
selectItem(items.catalyst)
robot.drop(1)
robot.turnRight()
robot.turnRight()
return pickupResults(5)
end
function craftMachine3(name, items)
local ret = requestMachine3(items)
if (ret ~= nil) then
if (tonumber(ret) ~= nil) then
local extra = tonumber(ret)
for i = 1,extra do
emptyIntoME()
if (extra >= 1) then
display("Crafting extra walls " .. i .. "/" .. extra)
end
ret = craftWall(recipes.wall.name, recipes.wall.items, false)
if (ret ~= nil) then
return ret
end
end
ret = requestMachine3(items)
if (ret ~= nil) then
return ret
end
else
return ret
end
end
display("Constructing " .. name)
-- Move into place, bottom left just outside of range, facing up
forward(5)
left(1)
robot.turnRight()
up(1)
-- Layer 1, Ends center facing up
forward(3, items.wall)
right(2, items.wall)
right(2, items.wall)
right(1, items.wall)
right(1, items.wall)
-- Layer 2, Ends top left facing up
up(1)
place(items.core)
forward(1, items.wall)
right(1, items.wall)
right(2, items.wall)
right(2, items.wall)
right(3, items.wall)
-- Layer 3, Ends center, facing right
up(1)
place(items.wall)
right(2, items.wall)
right(2, items.wall)
right(2, items.wall)
right(1, items.wall)
right(1, items.wall)
-- Fly out of region
up(3)
selectItem(items.catalyst)
robot.drop(1)
robot.turnRight()
return pickupResults(24)
end
function craftMachine5(name, items)
local ret = requestMachine5(items)
if (ret ~= nil) then
if (tonumber(ret) ~= nil) then
local extra = tonumber(ret)
for i = 1,extra do
emptyIntoME()
if (extra >= 1) then
display("Crafting extra walls " .. i .. "/" .. extra)
end
ret = craftWall(recipes.wall.name, recipes.wall.items, false)
if (ret ~= nil) then
return ret
end
end
ret = requestMachine5(items)
if (ret ~= nil) then
return ret
end
else
return ret
end
end
display("Constructing " .. name)
-- Move into place, bottom left just outside of range, facing up
forward(4)
robot.turnLeft()
forward(2)
robot.turnRight()
up(1)
-- Layer 1, Ends top right facing up
forward(5, items.wall)
right(1, items.wall)
right(4, items.wall)
left(1, items.wall)
left(4, items.wall)
right(1, items.wall)
right(4, items.wall)
left(1, items.wall)
left(4, items.wall)
-- Layer 2, Ends top right facing up
up(1)
place(items.wall)
left(4, items.wall)
left(4, items.wall)
left(4, items.wall)
left(3, items.wall)
forward(1)
-- Layer 3, Ends top right facing up
up(1)
place(items.wall)
left(2, items.wall)
if (items.core ~= nil) then
left(2)
place(items.core)
robot.turnLeft()
robot.turnLeft()
forward(2)
robot.turnLeft()
end
forward(2, items.wall)
left(4, items.wall)
left(4, items.wall)
left(3, items.wall)
forward(1)
-- Layer 4, Ends top right facing up
up(1)
place(items.wall)
left(4, items.wall)
left(4, items.wall)
left(4, items.wall)
left(3, items.wall)
forward(1)
-- Layer 5, Ends center facing left
up(1)
place(items.wall)
left(4, items.wall)
left(4, items.wall)
left(4, items.wall)
left(3, items.wall)
left(3, items.wall)
left(2, items.wall)
left(2, items.wall)
left(1, items.wall)
left(1, items.wall)
-- Go out of region, and toss catalyst
up(1)
selectItem(items.catalyst)
robot.drop(1)
robot.turnLeft()
return pickupResults(33)
end
function craftTunnel(name, items)
local ret = requestTunnel(items)
if (ret ~= nil) then
if (tonumber(ret) ~= nil) then
local extra = tonumber(ret)
for i = 1,extra do
emptyIntoME()
if (extra >= 1) then
display("Crafting extra walls " .. i .. "/" .. extra)
end
ret = craftWall(recipes.wall.name, recipes.wall.items, false)
if (ret ~= nil) then
return ret
end
end
ret = requestTunnel(items)
if (ret ~= nil) then
return ret
end
else
return ret
end
end
display("Constructing " .. name)
--Move into place, Bottom left, just outside, facing up
forward(5)
left(1)
robot.turnRight()
up(1)
-- Layer 1, Center facing up
forward(3, items.dust)
right(2, items.dust)
right(2, items.dust)
right(1, items.dust)
right(1, items.bottom)
--Place Top, But can be hopper so can't move above it, as it'll steal our catalyst
back(1)
selectItem(items.top)
robot.place(sides.down)
--Fly out of region
up(5)
forward(1)
selectItem(items.catalyst)
robot.drop(1)
robot.turnRight()
robot.turnRight()
return pickupResults(10)
end
-- Command Line Arguments
function validRecipes()
local tmp = {}
local n = 0
for k,v in pairs(recipes) do
n = n + 1
tmp[n] = k
end
table.sort(tmp)
local ret = ""
for k,v in pairs(recipes) do
ret = ret .. k .. ", "
end
if (ret ~= "") then
ret = ret:sub(1, ret:len() - 2)
end
return ret
end
function commandLineArgs()
local continue = true
while(continue) do
skipLine(1)
print(" What would you like to build?")
print(validRecipes())
continue = process(string.lower(io.read()))
end
end
function wirelessArgs()
local continue = true
while(continue) do
skipLine(1)
print(" Wireless Mode")
_, _, _, _, _, message = event.pull("modem_message")
continue = process(string.lower(message))
end
end
function process(cmd)
local words = {}
local size = 0
for word in cmd:gmatch("%S+") do
table.insert(words, word)
size = size + 1
end
local count = 1
local recipe = recipes[words[1]]
if (size == 2 and tonumber(words[2]) ~= nil and recipe ~= nil) then
count = tonumber(words[2])
display("Creating " .. count .. " " .. recipe.name)
end
for i = 1,count do
if (count ~= 1) then
display("Run " .. i .. "/" .. count)
end
local ret = nil
if (recipe == nil) then
if (words[1] == "wirelesson") then
activateWireless()
elseif (words[1] == "wirelessoff") then
deactivateWireless()
end
elseif (recipe.style == "wall") then
ret = craftWall(recipe.name, recipe.items)
elseif (recipe.style == "tunnel") then
ret = craftTunnel(recipe.name, recipe.items)
elseif (recipe.style == "cube3") then
ret = craftMachine3(recipe.name, recipe.items)
elseif (recipe.style == "cube5") then
ret = craftMachine5(recipe.name, recipe.items)
else
ret = "Invalid recipe style: " .. recipe.style
end
emptyIntoME()
if (ret ~= nil) then
display(ret)
return false
end
end
return true
end
-- Start Program
function writeShell()
local shell = io.open(".shrc","w")
shell:write("/home/CM3.lua")
shell:close()
end
function createWirelessVariable()
if not filesystem.exists("/home/wirelessVariable") then
local file = io.open("wirelessVariable","w")
file:write("")
file:close()
end
end
function startProgram()
os.execute("cls")
local ret = emptyIntoME()
if (ret ~= nil) then
display(ret)
return
end
writeTitle()
if (modeWireless) then
tunnel.send("on")
--wirelessArgs()
commandLineArgs()
else
tunnel.send("off")
commandLineArgs()
end
end
function display(message)
print(message)
if (modeWireless) then
tunnel.send("print " .. message)
end
end
writeShell()
createWirelessVariable()
getWirelessVariable()
startProgram()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment