Last active
December 14, 2020 21:11
-
-
Save ZeekDaGeek/1177c00e88695e2cd4395c25124d66c4 to your computer and use it in GitHub Desktop.
development_sync
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"development_sync","updated_at":"2020-12-14T21:11:54.457Z","files":["auto_mini.lua","autodownload.lua","bridge.lua","drone_bios.lua","drone_client.lua","geeklib.lua","gist_sync.lua","robot_controller.lua","robot_idle.lua","stair_down.lua","tree_farm.lua"]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local sides = require("sides") | |
local event = require("event") | |
---- Config | |
local miniSize = 3 | |
local AutoclickerName = "clickmachine:auto_clicker" | |
local AutoclickerAltName = "thermalexpansion:device" | |
local ChestName = "thermalexpansion:strongbox" | |
local DropperName = "minecraft:dropper" | |
---- Session Variables | |
local Autoclickers = {} | |
local Dropper = {} | |
---- Functions | |
function SetupTransposer(componentAddress) | |
local transposer = component.proxy(componentAddress) | |
local machineType = nil | |
local machineSide = nil | |
local chestSide = nil | |
--- Find the inventories. | |
for i = 0, 5, 1 do | |
local currentInv = transposer.getInventoryName(i) | |
--print(currentInv) | |
if (currentInv == AutoclickerName) then | |
machineType = 1 | |
machineSide = i | |
elseif (currentInv == AutoclickerAltName) then | |
machineType = 1 | |
machineSide = i | |
elseif (currentInv == DropperName) then | |
machineType = 2 | |
machineSide = i | |
elseif (currentInv == ChestName) then | |
chestSide = i | |
end | |
end | |
if (machineType ~= nil and machineSide ~= nil and chestSide ~= nil) then | |
-- Transposer is attatched to an autoclicker | |
if (machineType == 1) then | |
SetupAutoclicker(componentAddress, machineSide, chestSide) | |
elseif (machineType == 2) then | |
SetupDropper(componentAddress, machineSide, chestSide) | |
end | |
end | |
end | |
function SetupAutoclicker(transAddress, autoclickerSide, chestSide) | |
output = { address = transAddress, side = autoclickerSide, chest = chestSide } | |
table.insert(Autoclickers, output) | |
--print("Table is now:") | |
--for key, value in pairs(Autoclickers) do | |
-- print(" " .. key .. ": " .. value.side .. ", " .. value.chest) | |
--end | |
end | |
function SetupDropper(transAddress, dropperSide, chestSide) | |
Dropper = {} | |
Dropper = { address = transAddress, side = dropperSide, chest = chestSide } | |
end | |
function init() | |
-- Zero out states. | |
Autoclickers = {} | |
Dropper = {} | |
-- Look at all of the transposers and figure out which machine type they're | |
-- attached to. | |
componentList = component.list("transposer") | |
for address, componentType in component.list("transposer") do | |
--print("Setting up transposer " .. address) | |
SetupTransposer(address) | |
-- Debug for finding inventory names. | |
--[[ | |
if (not string.find(address, "52748")) then goto continue end | |
--SetupTransposer(address) | |
print(address) | |
print(" up: " .. component.proxy(address).getInventoryName(sides.east)) | |
print(" down: " .. component.proxy(address).getInventoryName(sides.down)) | |
::continue:: | |
]]-- | |
end | |
end | |
function Craft() | |
for _, transposerInfo in pairs(Autoclickers) do | |
transposer = component.proxy(transposerInfo.address) | |
local height = 1 | |
for height = 1, miniSize, 1 do | |
local currentSlot = height | |
local foundSlot = false | |
local result = transposer.transferItem(transposerInfo.chest, transposerInfo.side, 1, currentSlot, 1) | |
os.sleep(0.2) | |
--print("Attempt to move item: " .. result) | |
--while (foundSlot == false) do | |
-- transposer.getSlotStackSize(transposerInfo.chest, currentSlot) | |
--end | |
end | |
end | |
dropTrans = component.proxy(Dropper.address) | |
dropTrans.transferItem(Dropper.chest, Dropper.side, 1, 1) | |
rs = component.getPrimary("redstone") | |
rs.setOutput(sides.south, 15) | |
os.sleep(0.2) | |
rs.setOutput(sides.south, 0) | |
end | |
---- Main | |
init() | |
print("Place autoclicker and press a key...") | |
event.pull("key_down") | |
Craft() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local term = require("term") | |
local shell = require("shell") | |
local fs = require("filesystem") | |
if not component.isAvailable("internet") then | |
term.write("Internet Card is not available. Cannot download the script.\n") | |
return false | |
end | |
local args, options = shell.parse(...) | |
local url = tostring(args[1]) | |
local filename = fs.name(url) | |
term.write("Creating an auto-downloading version of " .. filename .. "\n") | |
if (not fs.isDirectory("/home/.autodownloader/cache")) then | |
fs.makeDirectory("/home/.autodownloader") | |
fs.makeDirectory("/home/.autodownloader/cache") | |
end | |
local cache_filename = "/home/.autodownloader/cache/" .. string.gsub(shell.getWorkingDirectory(), "/", ".") .. "." .. filename | |
local fh = fs.open(shell.getWorkingDirectory() .. "/" .. filename, "w") | |
fh:write(string.format([[ | |
local i = require("internet") | |
local fs = require("filesystem") | |
local buffer = "" | |
local ih = i.request("%s?" .. os.time(), {}, {}) | |
for chunk in ih do buffer = buffer..chunk end | |
local filepath = "%s" | |
local fh = fs.open(filepath, "w") | |
fh:write(buffer) | |
local args = table.concat({...}, " ") | |
os.execute(filepath .. " " .. args) | |
]], url, cache_filename)) | |
term.write("Run " .. filename .. " to automatically update and run the program each time.\n\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local robot = require("robot") | |
local sides = require("sides") | |
local shell = require("shell") | |
local InvSize = robot.inventorySize() | |
local args, options = shell.parse(...) | |
local BridgeAmount = tonumber(args[1]) | |
----- | |
function PlaceLike(slot, ...) | |
local args = table.pack(...) | |
local side = args[1] or sides.forward | |
if (robot.compareTo(slot) and (robot.count() > 1 or robot.select() ~= slot)) then | |
component.robot.place(side) | |
return true | |
end | |
robot.select(slot) | |
for i=1,InvSize do | |
if (robot.compareTo(i)) then | |
if (i ~= slot or robot.count(i) > 1) then | |
robot.select(i) | |
component.robot.place(side) | |
return true | |
end | |
end | |
end | |
print("Err: out of blocks") | |
os.exit() | |
end | |
----- | |
print("Attempting to bridge " .. tostring(BridgeAmount) .. " blocks.") | |
for i=1,BridgeAmount,1 do | |
print(" Placing block #" .. tostring(i) .. ".") | |
robot.forward() | |
result = PlaceLike(1, sides.down) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local m=component.proxy(component.list("modem")()) | |
m.open(2412) | |
local function respond(...) | |
local args=table.pack(...) | |
pcall(function() m.broadcast(2412, table.unpack(args)) end) | |
end | |
local function receive() | |
while true do | |
local evt,_,_,_,_,cmd=computer.pullSignal() | |
if evt=="modem_message" then return load(cmd) end | |
end | |
end | |
while true do | |
local result,reason=pcall(function() | |
local result,reason=receive() | |
if not result then return respond(reason) end | |
respond(result()) | |
end) | |
if not result then respond(reason) end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local event = require("event") | |
local modem = component.modem | |
modem.open(2412) | |
modem.broadcast(2412, "drone=component.proxy(component.list('drone')())") | |
while true do | |
local cmd=io.read() | |
if not cmd then return end | |
modem.broadcast(2412, cmd) | |
print(select(6, event.pull(5, "modem_message"))) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local robot = require("robot") | |
local fs = require("filesystem") | |
local serialization = require("serialization") | |
local geeklib = {} | |
local state = {} | |
----- State Management ----- | |
local state_directory = "/home/.state/" | |
function state.load(state_name) | |
if (state_name == '' or state_name == nil) then | |
error("No state name provided.") | |
end | |
local state_file = state_directory + state_name + ".dat" | |
local file | |
-- Check if the file exists, if not create it. | |
if (not(fs.exists(state_file))) then | |
file = io.open(state_file, "w") | |
file.write(serialization.serialize({})) | |
file.close() | |
end | |
file = io.open(state_file, "r") | |
state_object = serialization.unserialize(file.read("*a")) | |
file.close() | |
return state_object | |
end | |
function state.save(state_name, object) | |
if (state_name == '' or state_name == nil) then | |
error("No state name provided.") | |
end | |
local state_file = state_directory + state_name + ".dat" | |
local file | |
-- Check if the file exists, if not create it. | |
if (not(fs.exists(state_file))) then | |
file = io.open(state_file, "w") | |
file.write(serialization.serialize({})) | |
file.close() | |
else | |
file = io.open(state_file, "w") | |
file.write(serialization.serialize(object)) | |
file.close() | |
end | |
return true | |
end | |
function state.set(state_name, variable_name, value) | |
if (state_name == '' or state_name == nil) then | |
state_name = "general" | |
end | |
-- Check if there is a state file for this program. | |
local state_object = state.load(state_name) | |
state_object[variable_name] = value | |
state.save(state_object) | |
return state_object | |
end | |
function state.get(state_name, variable_name) | |
if (state_name == '' or state_name == nil) then | |
state_name = "general" | |
end | |
local state_object = state.load(state_name) | |
return state_object[variable_name] | |
end | |
geeklib.state = state | |
--------------- Common Robot functions --------------- | |
function geeklib.PlaceLike(slot, ...) | |
local args = table.pack(...) | |
local side = args[1] or sides.forward | |
if (robot.compareTo(slot) and (robot.count() > 1 or robot.select() ~= slot)) then | |
component.robot.place(side) | |
return true | |
end | |
robot.select(slot) | |
for i=1,InvSize do | |
if (robot.compareTo(i)) then | |
if (i ~= slot or robot.count(i) > 1) then | |
robot.select(i) | |
component.robot.place(side) | |
return true | |
end | |
end | |
end | |
print("Err: out of blocks") | |
os.exit() | |
end | |
return geeklib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Updated text... | |
local component = require("component") | |
local filesystem = require("filesystem") | |
local serialization = require("serialization") | |
local shell = require("shell") | |
local colors = require("colors") | |
local event = require("event") | |
local keyboard = require("keyboard") | |
local computer = require("computer") | |
local term = require("term") | |
local thread = require("thread") | |
local gpu = component.gpu | |
-- Configurations | |
local sleepDuration = 0.05 | |
local updateDelay = 10 | |
local githubAPIOAuthToken = "457f92b0cd4b616f71bd5c6f8115d82619340631" | |
local gistSyncID = "1177c00e88695e2cd4395c25124d66c4" | |
local gistUsername = "ZeekDaGeek" | |
local githubAPI = "https://api.github.com/" | |
local gistConentURI = "https://gist.githubusercontent.com/" | |
-- Internal variables | |
local updateTicks = updateDelay | |
local updateRunning = false | |
local localFiles = {} | |
local allFiles = {} | |
local defaultGpuDepth = 0 | |
local lastCycleTime = computer.uptime() | |
local gistInfo = {} | |
-- Check that there is an internet card. | |
if (not component.isAvailable("internet")) then | |
print("EXITING: Program Sync requires Internet Card to work.") | |
os.exit() | |
end | |
-- Check that HTTP requests are enabled in the config. | |
if (not component.internet.isHttpEnabled) then | |
print("EXITING: Program Sync requires HTTP requests enabled (config setting).") | |
os.exit() | |
end | |
local internet = require("internet") | |
local internetComp = component.internet | |
-- Load persistant program information. | |
if (not filesystem.exists("/etc/program_sync.dat")) then | |
if (not filesystem.exists("/etc")) then | |
filesystem.makeDirectory("/etc") | |
end | |
local defaultPersist = {} | |
defaultPersist.lastUpdated = false | |
defaultPersist.gistFiles = {} | |
defaultPersist.pointerIndex = 0 | |
defaultPersist.lastUpdatedOS = 0 | |
local file = io.open("/etc/program_sync.dat", "w") | |
file:write(serialization.serialize(defaultPersist)) | |
file:close() | |
end | |
local file = io.open("/etc/program_sync.dat", "r") | |
local persist = serialization.unserialize(file:read("*all")) | |
file:close() | |
-- Download the JSON API if it hasn't been downloaded yet | |
if (not filesystem.exists("/usr/lib/json.lua")) then | |
if (not filesystem.exists("/usr/lib")) then | |
filesystem.makeDirectory("/usr/lib") | |
end | |
local file = io.open("/usr/lib/json.lua", "w") | |
for chunk in internet.request("http://regex.info/code/JSON.lua") do | |
file:write(chunk) | |
end | |
file:close() | |
end | |
local JSON = loadfile("/usr/lib/json.lua")() | |
-- Internal functions | |
function savePersist () | |
if (not filesystem.exists("/etc")) then | |
filesystem.makeDirectory("/etc") | |
end | |
local file = io.open("/etc/program_sync.dat", "w") | |
file:write(serialization.serialize(persist)) | |
file:close() | |
end | |
function addTrailingSlash (uri) | |
if string.sub(uri, -1) == "/" then | |
return uri | |
else | |
return uri .. "/" | |
end | |
end | |
function gistAPI (callURI, args) | |
local gistURI = "" | |
-- Ensure that the Github API URI has a slash at the end. | |
gistURI = addTrailingSlash(githubAPI) | |
-- Check if the call URI has a slash at the beginning, if it does remove it. | |
if (string.sub(callURI, 1, 1) == "/") then | |
gistURI = gistURI .. addTrailingSlash(string.sub(callURI, 2)) | |
else | |
gistURI = gistURI .. addTrailingSlash(callURI) | |
end | |
-- Add all arguments to the end of the URI. | |
if (type(args) == "string") then | |
gistURI = gistURI .. addTrailingSlash(args) | |
elseif (type(args) == "table") then | |
for k, v in pairs(args) do | |
gistURI = gistURI .. addTrailingSlash(v) | |
end | |
end | |
-- Remove the trailing slash. | |
gistURI = string.sub(gistURI, 1, string.len(gistURI) - 1) | |
if (githubAPIOAuthToken) then | |
gistURI = gistURI .. "?access_token=" .. githubAPIOAuthToken | |
end | |
-- print("Requesting URI: " .. gistURI) -- Debug url display. | |
-- First check if there is an Index in the gist, if there is it'll be a lot faster to use that instead. | |
-- Build Gist Content URL | |
gistContentURI = addTrailingSlash(gistConentURI) .. addTrailingSlash(gistUsername) .. addTrailingSlash(gistSyncID) .. "raw/" | |
local gistResponse = "" | |
local result, response = pcall(internet.request, gistContentURI .. ".index.json") | |
if result then | |
for chunk in response do | |
gistResponse = gistResponse .. chunk | |
end | |
--[[ | |
The format of index.json is expected to be the same. | |
{ | |
"description": "Any description" | |
"updated_at": "<Any format as long as it increases with each update>", | |
"files": { | |
"filesnames.lua", | |
"that_exist.lua", | |
"in_this_gist.lua" | |
} | |
} | |
]]-- | |
local data = JSON:decode(gistResponse) | |
local files = {} | |
for _, filename in pairs(data.files) do | |
local result, response = pcall(internet.request, gistContentURI .. filename) | |
if result then | |
local fileContents = "" | |
for chunk in response do | |
fileContents = fileContents .. chunk | |
end | |
files[filename] = { | |
["content"] = fileContents | |
} | |
end | |
end | |
data["files"] = files | |
return data | |
else | |
-- If we can't find the file return the API response instead. | |
for chunk in internet.request(gistURI, nil, { ["User-Agent"] = "OpenComputers Gist Sync" }) do gistResponse = gistResponse .. chunk end | |
local data = JSON:decode(gistResponse) | |
return data | |
end | |
end | |
function updateLocalFiles () | |
localFiles = {} | |
for file in filesystem.list(shell.getWorkingDirectory()) do | |
table.insert(localFiles, file) | |
end | |
localFiles = localFiles | |
return localFiles | |
end | |
function updateFiles () | |
local fileList = {} | |
local listSize = 0 | |
for _, file in pairs(localFiles) do | |
fileList[file] = {} | |
fileList[file].existsLocally = true | |
fileList[file].existsOnGist = false | |
listSize = listSize + 1 | |
end | |
for _, file in pairs(persist.gistFiles) do | |
if (not fileList[file]) then | |
fileList[file] = {} | |
fileList[file].existsLocally = false | |
listSize = listSize + 1 | |
end | |
fileList[file].existsOnGist = true | |
end | |
allFiles = {} | |
allFiles = fileList | |
allFiles["_metadata"] = { size = listSize } | |
if (persist.pointerIndex > allFiles["_metadata"].size) then | |
persist.pointerIndex = allFiles["_metadata"].size | |
savePersist() | |
end | |
--print("localFiles: " .. serialization.serialize(localFiles)) | |
--print("gistFiles: " .. serialization.serialize(persist.gistFiles)) | |
--print("fileList: " .. serialization.serialize(fileList)) | |
--print("allFiles: " .. serialization.serialize(allFiles)) | |
return sortedFileList | |
end | |
function setForeground(newColor, pallete) | |
if gpu.getDepth() == 4 then | |
gpu.setForeground(newColor, pallete) | |
end | |
end | |
function setBackground(newColor, pallete) | |
if gpu.getDepth() == 4 then | |
gpu.setBackground(newColor, pallete) | |
end | |
end | |
function drawUI() | |
local w, h = gpu.getResolution() | |
-- Clear the screen | |
setBackground(colors.black, true) | |
gpu.fill(1, 1, w, h, " ") | |
-- Draw borders | |
setBackground(colors.silver, true) | |
gpu.fill(2, 2, w - 3, 1, " ") | |
gpu.fill(2, 3, 1, h - 3, " ") | |
gpu.fill(w - 2, 2, 1, h - 2, " ") | |
gpu.fill(3, h - 1, w - 4, 1, " ") | |
setForeground(colors.black, true) | |
updatedDelta = os.time() - persist.lastUpdatedOS | |
if updatedDelta < 0 then | |
if persist.lastUpdatedOS > -1 then | |
persist.lastUpdatedOS = -1 | |
savePersist() | |
end | |
updatedString = "" | |
else | |
updatedString = string.format("(Updated %.0fs ago)", math.floor(updatedDelta / 100)) | |
end | |
local loadingStates = {} | |
loadingStates[0] = "..." | |
loadingStates[1] = " .." | |
loadingStates[2] = " ." | |
loadingStates[3] = ". " | |
loadingStates[4] = ".. " | |
local updateIcon = loadingStates[math.floor(math.fmod(computer.uptime(), 5))] | |
-- Shorten title on smaller screens. | |
local programTitle = "Gist Program Sync" | |
if (w <= 60) then | |
programTitle = "GPSync" | |
end | |
gpu.set(3, 2, string.format("%s - %s %s %s", programTitle, gistInfo.desc or "", updatedString, updateIcon)) | |
local tmpString = "Keybinds: E(x)it (H)elp" | |
gpu.set(w - string.len(tmpString) - 2, h - 1, tmpString) | |
setForeground(colors.white, true) | |
setBackground(colors.black, true) | |
-- Help text. | |
helpPara = { | |
"Developing OpenComputer programs on a server is a pain in the butt, the " .. | |
"text console is not designed well for lag less text input and it gets " .. | |
"very annoying very quickly to develop. That's where Gist Program Sync " .. | |
"becomes useful.", | |
"Simply run Gist Program Sync from a directory you would like to " .. | |
"sync with a gist and it will automatically download updates when it finds them.", | |
"Run or download a program from Gist by simply pressing the corrisponding" .. | |
"number key or select the file with your arrow keys and hit enter.", | |
"Filename color key:" | |
} | |
local timeTillUpdate = updateDelay - updateTicks | |
if (timeTillUpdate <= 0) then | |
gpu.set(4, h-3, "Checking Gist...") | |
else | |
gpu.set(4, h-3, string.format("Checking Gist for updates in %.2f seconds.", timeTillUpdate)) | |
end | |
-- Combine the local file list with the gist file list. | |
updateFiles() | |
-- Sort the file list. | |
local sortedFileNames = {} | |
for file, _ in pairs(allFiles) do | |
if (file ~= "_metadata") then table.insert(sortedFileNames, file) end | |
end | |
table.sort(sortedFileNames) | |
-- Print out the list of files. | |
local listMax = h - 4 - 5 | |
local listMin = persist.pointerIndex - listMax + 3 | |
local currentLine, keybind, i = 4, 1, 0 | |
for _, fileName in pairs(sortedFileNames) do | |
if (fileName ~= "_metadata" and i >= listMin and (currentLine - 4) < listMax) then | |
fileInfo = allFiles[fileName] | |
if fileInfo.existsLocally and fileInfo.existsOnGist then | |
setForeground(colors.green, true) | |
debug = "green" | |
file_prefix = "[X] " | |
elseif fileInfo.existsLocally then | |
setForeground(colors.white, true) | |
debug = "white" | |
file_prefix = "[ ] " | |
else | |
setForeground(colors.gray, true) | |
debug = "grey" | |
file_prefix = "[-] " | |
end | |
local tmpPrefix = "" | |
if (keybind) then | |
allFiles[fileName].keybind = keybind + 1 | |
if (keybind == 10) then | |
tmpPrefix = " 0. " | |
else | |
tmpPrefix = string.format(" %s. ", keybind) | |
end | |
if (keybind < 10) then | |
keybind = keybind + 1 | |
else | |
keybind = nil | |
end | |
end | |
local swapForeground, swapForegroundRGB = gpu.getForeground() | |
local swapBackground, swapBackgroundRGB = gpu.getBackground() | |
if (persist.pointerIndex == i) then | |
setForeground(swapBackground, swapBackgroundRGB) | |
setBackground(swapForeground, swapForegroundRGB) | |
tmpPrefix = ">" .. tmpPrefix | |
else | |
tmpPrefix = " " .. tmpPrefix | |
end | |
if (gpu.getDepth() == 1) then | |
gpu.set(5, currentLine, tmpPrefix .. file_prefix .. fileName .. " ") | |
else | |
gpu.set(5, currentLine, tmpPrefix .. fileName .. " ") | |
end | |
setForeground(swapForeground, swapForegroundRGB) | |
setBackground(swapBackground, swapBackgroundRGB) | |
currentLine = currentLine + 1 | |
end | |
i = i + 1 | |
end | |
setForeground(colors.white, true) | |
local currentX, currentY = 2, 2 | |
gpu.set(2, 2, "") | |
term.setCursor(1, h) | |
end | |
-- Initialize. | |
defaultGpuDepth = gpu.getDepth() | |
if gpu.maxDepth() > 4 then | |
gpu.setDepth(4) | |
end | |
local currentlyUpdating = false | |
local updateThread = thread.create(function() | |
while true do | |
timeDiff = computer.uptime() - lastCycleTime | |
updateTicks = updateTicks + timeDiff | |
lastCycleTime = computer.uptime() | |
-- Check if we should do another update check. | |
if (updateTicks >= updateDelay and updateRunning == false) then | |
updateRunning = true | |
updateLocalFiles() | |
gistObject = gistAPI("/gists", { gistSyncID }) | |
gistInfo.desc = gistObject.description | |
-- Check if the gist has been updated since the last we checked. | |
if (persist.lastUpdated == false or gistObject.updated_at > persist.lastUpdated) then | |
persist.lastUpdatedOS = os.time() | |
persist.gistFiles = {} | |
for fileName, fileInfo in pairs(gistObject.files) do | |
table.insert(persist.gistFiles, fileName) | |
-- Check if the file exists in current directory, if it does then update it. | |
if (filesystem.exists(shell.getWorkingDirectory() .. "/" .. fileName)) then | |
local w,h = gpu.getResolution() | |
gpu.set(4, h-3, string.format("Updating %s/%s...", shell.getWorkingDirectory(), fileName)) | |
-- Rewrite the file. | |
local file = filesystem.open(shell.getWorkingDirectory() .. "/" .. fileName, "w") | |
file:write(fileInfo.content) | |
file:close() | |
end | |
end | |
persist.lastUpdated = gistObject.updated_at | |
savePersist() | |
end | |
updateRunning = false | |
lastCycleTime = computer.uptime() | |
updateTicks = 0 | |
end | |
os.sleep(sleepDuration) | |
end | |
end) | |
while true do | |
drawUI() | |
local eventId, keyboardId, char, code, player = event.pull(sleepDuration) | |
if (eventId == "key_down") then | |
if (code == keyboard.keys.f) then | |
persist.lastUpdated = false | |
lastCycleTime = 0 | |
savePersist() | |
drawUI() | |
elseif (code == keyboard.keys.x) then | |
local w, h = gpu.getResolution() | |
setBackground(colors.black, true) | |
setForeground(colors.white, true) | |
gpu.fill(1,1, w, h, " ") | |
gpu.setDepth(defaultGpuDepth) | |
term.setCursor(0, 0) | |
print("") | |
print("Exiting Gist program sync.") | |
os.exit() | |
elseif (code == keyboard.keys.up) then | |
persist.pointerIndex = persist.pointerIndex - 1 | |
if (persist.pointerIndex < 0) then | |
persist.pointerIndex = 0 | |
elseif (persist.pointerIndex > (allFiles["_metadata"].size - 1)) then | |
persist.pointerIndex = allFiles["_metadata"].size - 1 | |
end | |
savePersist() | |
drawUI() | |
elseif (code == keyboard.keys.down) then | |
persist.pointerIndex = persist.pointerIndex + 1 | |
if (persist.pointerIndex < 0) then | |
persist.pointerIndex = 0 | |
elseif (persist.pointerIndex > (allFiles["_metadata"].size - 1)) then | |
persist.pointerIndex = allFiles["_metadata"].size - 1 | |
end | |
savePersist() | |
drawUI() | |
-- Detect if a number hotkey is pressed. | |
elseif code >= 2 and code <= 11 then | |
for fileName, file in pairs(allFiles) do | |
if (file.keybind == code) then | |
if (file.existsLocally) then | |
print("") | |
print(string.format("Launching %s...", fileName)) | |
os.execute(shell.getWorkingDirectory() .. "/" .. fileName) | |
print("Press any key to continue Gist Program Sync...") | |
event.pull(100, "key_down") | |
elseif (not file.existsLocally and file.existsOnGist) then | |
print("") | |
print(string.format("Do you wish to download %s from Gist next cycle? [Y/n]", fileName)) | |
updateThread:suspend() | |
local userInput = io.read() | |
updateThread:resume() | |
if (userInput == "" or userInput == "y" or userInput == "yes") then | |
-- Rewrite the file. | |
local file = io.open(shell.getWorkingDirectory() .. "/" .. fileName, "w") | |
file:write() | |
file:close() | |
persist.lastUpdated = 0 | |
savePersist() | |
updateTicks = updateDelay | |
end | |
end | |
end | |
end | |
elseif (code == keyboard.keys.enter) then | |
local sortedFileNames = {} | |
for file, _ in pairs(allFiles) do | |
if (file ~= "_metadata") then table.insert(sortedFileNames, file) end | |
end | |
table.sort(sortedFileNames) | |
local i = 0 | |
for _, fileName in pairs(sortedFileNames) do | |
if (i == persist.pointerIndex) then | |
file = allFiles[fileName] | |
if (file.existsLocally) then | |
print("") | |
print("Launching " .. fileName .. "...") | |
os.execute(shell.getWorkingDirectory() .. "/" .. fileName) | |
print("Press any key to continue Gist Program Sync...") | |
event.pull(100, "key_down") | |
elseif (not file.existsLocally and file.existsOnGist) then | |
--[[ | |
print("") | |
print(string.format("Do you wish to download %s from Gist next cycle? [Y/n]", fileName)) | |
updateThread:suspend() | |
os.sleep(5) | |
local userInput = term.read() | |
updateThread:resume() | |
]]-- | |
--if (userInput == "" or userInput:lower() == "y" or userInput:lower() == "yes") then | |
-- Rewrite the file. | |
local file = io.open(shell.getWorkingDirectory() .. "/" .. fileName, "w") | |
file:write() | |
file:close() | |
persist.lastUpdated = false | |
savePersist() | |
updateTicks = updateDelay | |
--end | |
end | |
end | |
i = i + 1 | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- A (very (very!)) simple IRC client. Reference: | |
-- http://tools.ietf.org/html/rfc2812 | |
local component = require("component") | |
local computer = require("computer") | |
if not component.isAvailable("internet") then | |
io.stderr:write("This requires an Internet Card to run!\n") | |
return | |
end | |
if not component.isAvailable("modem") then | |
io.stderr:write("This requires a Modem to run!\n") | |
return | |
end | |
local event = require("event") | |
local internet = require("internet") | |
local term = require("term") | |
local text = require("text") | |
local serial = require("serialization") | |
local modem = component.modem | |
local modemPort = 1069 | |
modem.open(modemPort) | |
local nick = "justinfan6969" | |
local host = "irc.chat.twitch.tv" | |
local default_channel = "#zeekdageek" | |
if not host:find(":") then | |
host = host .. ":6667" | |
end | |
-- try to connect to server. | |
local sock, reason = internet.open(host) | |
if not sock then | |
io.stderr:write(reason .. "\n") | |
return | |
end | |
-- custom print that uses all except the last line for printing. | |
local function print(message, overwrite) | |
local w, h = component.gpu.getResolution() | |
local line | |
repeat | |
line, message = text.wrap(text.trim(message), w, w) | |
if not overwrite then | |
component.gpu.copy(1, 1, w, h - 1, 0, -1) | |
end | |
overwrite = false | |
component.gpu.fill(1, h - 1, w, 1, " ") | |
component.gpu.set(1, h - 1, line) | |
until not message or message == "" | |
end | |
-- utility method for reply tracking tables. | |
function autocreate(table, key) | |
table[key] = {} | |
return table[key] | |
end | |
-- extract nickname from identity. | |
local function name(identity) | |
return identity and identity:match("^[^!]+") or identity or "Anonymous" | |
end | |
-- user defined callback for messages (via `lua function(msg) ... end`) | |
local callback = nil | |
-- timer used to drive socket reading. | |
local timer | |
-- main command handling callback. | |
local function handleCommand(prefix, command, args, message) | |
--------------------------------------------------- | |
-- Keepalive | |
if command == "PING" then | |
sock:write(string.format("PONG :%s\r\n", message)) | |
sock:flush() | |
--------------------------------------------------- | |
-- General commands | |
elseif command == "PRIVMSG" then | |
local ctcp = message:match("^\1(.-)\1$") | |
if ctcp then | |
local orig_ctcp, param = ctcp:match("^(%S+) ?(.-)$") | |
ctcp = orig_ctcp:upper() | |
if ctcp == "PING" then | |
sock:write("NOTICE " .. name(prefix) .. " :\001PING " .. param .. "\001\r\n") | |
sock:flush() | |
elseif ctcp == "ACTION" then | |
print("[" .. args[1] .. "] * " .. name(prefix) .. string.gsub(string.gsub(message, "\001ACTION", ""), "\001", "")) | |
else | |
-- Here we print the CTCP message if it was unhandled... | |
print("[" .. name(prefix) .. "] CTCP " .. orig_ctcp) | |
end | |
else | |
if string.find(message, nick) then | |
computer.beep() | |
end | |
print("[" .. args[1] .. "] " .. name(prefix) .. ": " .. message) | |
end | |
elseif command == "NOTICE" then | |
print("[NOTICE] " .. message) | |
elseif command == "ERROR" then | |
print("[ERROR] " .. message) | |
-- MOTD end received, we can now join channels. | |
elseif command == "376" then -- ignore | |
sock:write("join " .. default_channel .. "\r\n") | |
sock:write("CAP REQ :twitch.tv/membership\r\n") | |
sock:write("CAP REQ :twitch.tv/tags\r\n") | |
sock:flush() | |
--------------------------------------------------- | |
-- Unhandled message. | |
end | |
end | |
-- catch errors to allow manual closing of socket and removal of timer. | |
local result, reason = pcall(function() | |
-- say hello. | |
term.clear() | |
--print("Welcome to OpenIRC!") | |
-- avoid sock:read locking up the computer. | |
sock:setTimeout(0.05) | |
-- http://tools.ietf.org/html/rfc2812#section-3.1 | |
sock:write(string.format("NICK %s\r\n", nick)) | |
sock:write(string.format("USER %s 0 * :%s [OpenComputers]\r\n", nick:lower(), nick)) | |
sock:flush() | |
-- socket reading logic (receive messages) driven by a timer. | |
timer = event.timer(0.5, function() | |
if not sock then | |
return false | |
end | |
repeat | |
local ok, line = pcall(sock.read, sock, 'l*') | |
if ok then | |
if not line then | |
print("Connection lost.") | |
sock:close() | |
sock = nil | |
return false | |
end | |
line = text.trim(line) -- get rid of trailing \r | |
-- #here | |
print("[RAW]" .. line) | |
local displaycolor = line:match("color=#([^;]+);"); | |
local displayname = line:match("display%-name=([^;]+);") | |
local subscriber = line:match("subscriber=(%d);") | |
local output = line:match("@.- :.- PRIVMSG #.- :(.+)") | |
local match, prefix = line:match("^(:(%S+) )") | |
if match then line = line:sub(#match + 1) end | |
local match, command = line:match("^(([^:]%S*))") | |
if match then line = line:sub(#match + 1) end | |
local args = {} | |
repeat | |
local match, arg = line:match("^( ([^:]%S*))") | |
if match then | |
line = line:sub(#match + 1) | |
table.insert(args, arg) | |
end | |
until not match | |
local message = line:match("^ :(.*)$") | |
if subscriber == "1" then | |
modem.broadcast(modemPort, displayname, displaycolor, output) | |
print("!! @" .. modemPort .. ":" .. displayname .. displaycolor .. output) | |
end | |
handleCommand(prefix, command, args, message) | |
end | |
until not ok | |
end, math.huge) | |
-- default target for messages, so we don't have to type /msg all the time. | |
local target = nil | |
-- command history. | |
local history = {} | |
repeat | |
local w, h = component.gpu.getResolution() | |
term.setCursor(1, h) | |
term.write((target or "?") .. "> ") | |
local line = term.read(history) | |
if sock and line and line ~= "" then | |
line = text.trim(line) | |
if line:lower():sub(1,4) == "/me " then | |
print("[" .. (target or "?") .. "] " .. nick .. " " .. line:sub(5), true) | |
elseif line~="" then | |
print("[" .. (target or "?") .. "] " .. nick .. ": " .. line, true) | |
end | |
if line:lower():sub(1, 5) == "/msg " then | |
local user, message = line:sub(6):match("^(%S+) (.+)$") | |
if message then | |
message = text.trim(message) | |
end | |
if not user or not message or message == "" then | |
print("Invalid use of /msg. Usage: /msg nick|channel message.") | |
line = "" | |
else | |
target = user | |
line = "PRIVMSG " .. target .. " :" .. message | |
end | |
elseif line:lower():sub(1, 6) == "/join " then | |
local channel = text.trim(line:sub(7)) | |
if not channel or channel == "" then | |
print("Invalid use of /join. Usage: /join channel.") | |
line = "" | |
else | |
target = channel | |
line = "JOIN " .. channel | |
end | |
elseif line:lower():sub(1, 5) == "/lua " then | |
local script = text.trim(line:sub(6)) | |
local result, reason = load(script, "=stdin", nil, setmetatable({print=print, socket=sock, nick=nick}, {__index=_G})) | |
if not result then | |
result, reason = load("return " .. script, "=stdin", nil, setmetatable({print=print, socket=sock, nick=nick}, {__index=_G})) | |
end | |
line = "" | |
if not result then | |
print("Error: " .. tostring(reason)) | |
else | |
result, reason = pcall(result) | |
if not result then | |
print("Error: " .. tostring(reason)) | |
elseif type(reason) == "function" then | |
callback = reason | |
elseif reason then | |
line = tostring(reason) | |
end | |
end | |
elseif line:lower():sub(1,4) == "/me " then | |
if not target then | |
print("No default target set. Use /msg or /join to set one.") | |
line = "" | |
else | |
line = "PRIVMSG " .. target .. " :\001ACTION " .. line:sub(5) .. "\001" | |
end | |
elseif line:sub(1, 1) == "/" then | |
line = line:sub(2) | |
elseif line ~= "" then | |
if not target then | |
print("No default target set. Use /msg or /join to set one.") | |
line = "" | |
else | |
line = "PRIVMSG " .. target .. " :" .. line | |
end | |
end | |
if line and line ~= "" then | |
sock:write(line .. "\r\n") | |
sock:flush() | |
end | |
end | |
until not sock or not line | |
end) | |
if sock then | |
sock:write("QUIT\r\n") | |
sock:close() | |
end | |
if timer then | |
event.cancel(timer) | |
end | |
if not result then | |
error(reason, 0) | |
end | |
return reason |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local event = require("event") | |
local serial = require("serialization") | |
local robot = component.robot | |
if not component.isAvailable("modem") then | |
io.stderr:write("Robot idle actions require a modem!\n") | |
return | |
end | |
local modem = component.modem | |
local modemPort = 1069 | |
modem.open(modemPort) | |
local beep = component.beep | |
repeat | |
local _, _, _, port, distance, robotName, color, message = event.pull(30, "modem_message") | |
if port == modemPort then | |
print("Received (" .. port .. "): " .. message) | |
messageObj = serial.unserialize(message) | |
if robotName == robot.name() then | |
local newcolor = tonumber("0x" .. color) | |
if robot.getLightColor ~= newcolor then | |
robot.setLightColor(newcolor) | |
end | |
for beepStr in string.gmatch(message, "[^%s]+") do | |
length = string.len(beepStr) / 2 * 0.1 | |
beep.beep({[400]=length}) | |
os.sleep(length) | |
if string.find("!?.,", string.sub(beepStr, -1)) then | |
os.sleep(0.1) | |
end | |
os.sleep(0.1) | |
end | |
end | |
end | |
until not true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local robot = require("robot") | |
local sides = require("sides") | |
local shell = require("shell") | |
local InvSize = robot.inventorySize() | |
local args, options = shell.parse(...) | |
local BridgeAmount = tonumber(args[1]) | |
----- | |
function PlaceLike(slot, ...) | |
local args = table.pack(...) | |
local side = args[1] or sides.forward | |
if (robot.compareTo(slot) and (robot.count() > 1 or robot.select() ~= slot)) then | |
component.robot.place(side) | |
return true | |
end | |
robot.select(slot) | |
for i=1,InvSize do | |
if (robot.compareTo(i)) then | |
if (i ~= slot or robot.count(i) > 1) then | |
robot.select(i) | |
component.robot.place(side) | |
return true | |
end | |
end | |
end | |
print("Err: out of blocks") | |
os.exit() | |
end | |
----- | |
print("Attempting to stair down " .. tostring(BridgeAmount) .. " blocks.") | |
for i=1,BridgeAmount,1 do | |
print(" Placing block #" .. tostring(i) .. ".") | |
robot.forward() | |
robot.down() | |
result = PlaceLike(1, sides.down) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local component = require("component") | |
local robot = require("robot") | |
local geek = require("geeklib") | |
local sides = require("sides") | |
local thread = require("thread") | |
local event = require("event") | |
local ic = component.inventory_controller | |
-- Configurations | |
local TreeSize = 2 -- 1 for oak, 2 for jungle type | |
local BonemealSide = sides.top | |
local SaplingSlot = 1 | |
local BonemealSlot = 2 | |
local LogSlot = 3 -- Used for comparisons. | |
-- Functions. | |
function PlaceSaplings(size) | |
-- Default to 1 if not specified. | |
if (size == nil) then | |
size = 1 | |
end | |
if (size == 2) then | |
-- Select the sapling slot. | |
if (robot.count(SaplingSlot) > 4) then | |
robot.select(SaplingSlot) | |
robot.forward() | |
robot.forward() | |
robot.turnRight() | |
robot.place() | |
robot.turnLeft() | |
robot.back() | |
robot.place() | |
robot.turnRight() | |
robot.place() | |
robot.turnLeft() | |
robot.back() | |
robot.place() | |
return true | |
else | |
error("Not enough saplings for a 2x2 tree.") | |
end | |
elseif (size == 1) then | |
if (robot.count(SaplingSlot) > 1) then | |
robot.select(SaplingSlot) | |
robot.place() | |
else | |
error("Not enough saplings for a 1x1 tree.") | |
end | |
return true | |
end | |
end | |
function RefillBonemeal(direction) | |
-- Default to refilling bonemeal from the front face. | |
if (direction == nil) then | |
direction = sides.front | |
end | |
if (direction ~= sides.front and direction ~= sides.top and direction ~= sides.bottom) then | |
error("Invalid side to refill bonemeal from.") | |
end | |
robot.select(BonemealSlot) | |
if (robot.space() == 0) then | |
return true | |
end | |
local CurrentBonemeal = robot.count() | |
local SuckResult = false | |
if (direction == sides.front) then | |
SuckResult = robot.suck(robot.space()) | |
elseif (direction == sides.top) then | |
SuckResult = robot.suckUp(robot.space()) | |
elseif (direction == sides.bottom) then | |
SuckResult = robot.suckDown(robot.space()) | |
end | |
return SuckResult | |
end | |
function UseBonemeal(direction) | |
-- Constantly attempt to bonemeal until you can't anymore. | |
-- Default side front. | |
if (direction == nil) then | |
direction = sides.front | |
end | |
if (direction ~= sides.front and direction ~= sides.top and direction ~= sides.bottom) then | |
error("Invalid side to bonemeal from.") | |
end | |
robot.select(BonemealSlot) | |
local PlaceAttempt = false | |
while (not(PlaceAttempt)) do | |
if (direction == sides.front) then | |
PlaceAttempt = robot.place() | |
elseif (direction == sides.top) then | |
PlaceAttempt = robot.placeUp() | |
elseif (direction == sides.bottom) then | |
PlaceAttempt = robot.placeDown() | |
end | |
end | |
end | |
-- Initialize | |
-- Main loop | |
local MainThread = thread.create(function() | |
print("Waiting...") | |
os.sleep(1000) | |
print("Done waiting.") | |
while (true) do | |
PlaceSaplings(TreeSize) | |
UseBonemeal(sides.front) | |
RefillBonemeal(BonemealSide) | |
end | |
end) | |
-- Close thread. | |
local InteruptTread = thread.create(function() | |
event.listen("key_down", function(event, address, char, keycode, player) | |
if (char == "x") then | |
MainThread:kill() | |
InteruptTread:kill() | |
end | |
end) | |
end) | |
thread.waitForAll({MainThread, InteruptTread}) | |
print("Exiting gracefully.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment