mirror of
https://github.com/osmarks/random-stuff
synced 2024-12-29 11:30:35 +00:00
243 lines
6.5 KiB
Lua
243 lines
6.5 KiB
Lua
|
local channel = 31415
|
||
|
|
||
|
local m = peripheral.find("modem", function(_, o) return o.isWireless() end)
|
||
|
if not m then error "Modem required!" end
|
||
|
|
||
|
local tele = peripheral.find "Teleporter"
|
||
|
if not tele then error "Teleporter (see Mekanism wiki) required!" end
|
||
|
|
||
|
local sign = peripheral.find "minecraft:sign"
|
||
|
|
||
|
local rift_ID = os.getComputerLabel():match "Rift:([A-Za-z0-9_-]+)"
|
||
|
|
||
|
if not rift_ID then error "Please relabel this computer `Rift:[unique rift identifier]`." end
|
||
|
|
||
|
m.open(channel)
|
||
|
|
||
|
local function display_status(...)
|
||
|
if sign then sign.setSignText(rift_ID, ...) end
|
||
|
end
|
||
|
|
||
|
local function split_at_spaces(s)
|
||
|
local t = {}
|
||
|
for i in string.gmatch(s, "%S+") do
|
||
|
table.insert(t, i)
|
||
|
end
|
||
|
return t
|
||
|
end
|
||
|
|
||
|
local function first_letter(s)
|
||
|
return string.sub(s, 1, 1)
|
||
|
end
|
||
|
|
||
|
local function update_self()
|
||
|
print "Downloading update."
|
||
|
local h = http.get "https://pastebin.com/raw/jta5puZL"
|
||
|
local t = h.readAll()
|
||
|
h.close()
|
||
|
|
||
|
local fn, err = load(t, "@rift")
|
||
|
if not fn then printError("Not updating: syntax error:\n" .. err) end
|
||
|
|
||
|
local f = fs.open("startup", "w")
|
||
|
f.write(t)
|
||
|
f.close()
|
||
|
os.reboot()
|
||
|
end
|
||
|
|
||
|
local teleporter_errors = {
|
||
|
[2] = "Frame invalid.",
|
||
|
[3] = "Pairing error.",
|
||
|
[4] = "Insufficient energy."
|
||
|
}
|
||
|
|
||
|
local function send_message(...)
|
||
|
m.transmit(channel, channel, { ... })
|
||
|
end
|
||
|
|
||
|
local function disconnect(remote)
|
||
|
display_status "Idle"
|
||
|
if not remote then send_message("command", "handle_disconnect", rift_ID) end
|
||
|
tele.setFrequency(("rift-%s-null"):format(rift_ID), true)
|
||
|
end
|
||
|
|
||
|
local connected_to = nil
|
||
|
|
||
|
local remote_commands = {
|
||
|
ping = function()
|
||
|
return { rift_ID }
|
||
|
end,
|
||
|
update = function()
|
||
|
update_self()
|
||
|
end,
|
||
|
dial = function(from, to)
|
||
|
if to ~= rift_ID then return end
|
||
|
if type(from) ~= "string" then error("Invalid or no originator specified!") end
|
||
|
local freq = ("rift-%s-%s"):format(from, to)
|
||
|
tele.setFrequency(freq, true)
|
||
|
local status = tele.canTeleport()
|
||
|
if status == 1 then
|
||
|
print(("Connection established from %s."):format(from))
|
||
|
display_status("Dialed from:", from)
|
||
|
connected_to = from
|
||
|
return { true }
|
||
|
else
|
||
|
local e = teleporter_errors[status] or "Unknown error."
|
||
|
display_status("Error:", e)
|
||
|
printError(("Error receiving connection from %s: %s"):format(from, e))
|
||
|
return { false, e }
|
||
|
end
|
||
|
end,
|
||
|
handle_disconnect = function(other_end)
|
||
|
if other_end == connected_to then disconnect(true) end
|
||
|
end
|
||
|
}
|
||
|
|
||
|
local function timeout(fn, time)
|
||
|
local timer = os.startTimer(time)
|
||
|
local co = coroutine.create(fn)
|
||
|
local filter
|
||
|
while true do
|
||
|
local ev = { os.pullEvent() }
|
||
|
if coroutine.status(co) == "dead" or ev[1] == "timer" and ev[2] == timer then return end
|
||
|
if not filter or filter == ev[1] then
|
||
|
local ok, res = coroutine.resume(co, unpack(ev))
|
||
|
if not ok then error(res)
|
||
|
else filter = res end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local usage =
|
||
|
[[Welcome to Rift. All listed commands are accessible by single-letter shortcuts.
|
||
|
dial [destination] - Open a connection to rift [destination].
|
||
|
scan - Scan for available rifts.
|
||
|
scan [filter] - Scan for available rifts whose names contain [filter].
|
||
|
help - Print this.
|
||
|
update - Update this.
|
||
|
disconnect - Disconnect from current paired rift.
|
||
|
id - Get the ID of the current rift.]]
|
||
|
|
||
|
local CLI_commands = {
|
||
|
help = function() textutils.pagedPrint(usage) end,
|
||
|
dial = function(dest)
|
||
|
if not dest then error "No destination rift specified." end
|
||
|
local freq = ("rift-%s-%s"):format(rift_ID, dest)
|
||
|
print(("Setting frequency to %s."):format(freq))
|
||
|
tele.setFrequency(freq, true)
|
||
|
print(("Sending dial request to %s."):format(dest))
|
||
|
send_message("command", "dial", rift_ID, dest)
|
||
|
|
||
|
local result
|
||
|
timeout(function()
|
||
|
while true do
|
||
|
local _, response_to, success, error_type = os.pullEvent "remote_result"
|
||
|
if response_to == "dial" then
|
||
|
if not success then
|
||
|
print(dest, "reports error:", error_type)
|
||
|
result = "remote_error"
|
||
|
else
|
||
|
print(dest, "reports success.")
|
||
|
local status = tele.canTeleport()
|
||
|
if status == 1 then
|
||
|
result = "success"
|
||
|
print "Link established."
|
||
|
display_status("Dialed to:", dest)
|
||
|
connected_to = dest
|
||
|
else
|
||
|
result = "local_error"
|
||
|
local e = teleporter_errors[status] or "Unknown error."
|
||
|
display_status("Error:", e)
|
||
|
print(e)
|
||
|
end
|
||
|
end
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end, 1)
|
||
|
|
||
|
if result == nil then error(dest .. " is unreachable or nonexistent.", 0) end
|
||
|
end,
|
||
|
update = function(what)
|
||
|
if what == "all" then
|
||
|
send_message("command", "update")
|
||
|
print "Update command broadcast"
|
||
|
end
|
||
|
update_self()
|
||
|
end,
|
||
|
scan = function(filter)
|
||
|
send_message("command", "ping")
|
||
|
print "Scanning..."
|
||
|
timeout(function()
|
||
|
while true do
|
||
|
local _, resp_to, from = os.pullEvent "remote_result"
|
||
|
if resp_to == "ping" and from and (not filter or from:match(filter)) then
|
||
|
print("Found:", from)
|
||
|
end
|
||
|
end
|
||
|
end, 1)
|
||
|
end,
|
||
|
disconnect = disconnect,
|
||
|
id = function()
|
||
|
print("Rift ID:", rift_ID)
|
||
|
end
|
||
|
}
|
||
|
|
||
|
local function command_prompt()
|
||
|
print "Welcome to Rift!"
|
||
|
local history = {}
|
||
|
while true do
|
||
|
write "|> "
|
||
|
local text = read(nil, history)
|
||
|
|
||
|
if text ~= "" then table.insert(history, text) end
|
||
|
|
||
|
local tokens = split_at_spaces(text)
|
||
|
local command = table.remove(tokens, 1)
|
||
|
local args = tokens
|
||
|
local fn = CLI_commands[command]
|
||
|
|
||
|
if not fn then
|
||
|
for command_name, func in pairs(CLI_commands) do
|
||
|
if command and first_letter(command_name) == first_letter(command) then fn = func end
|
||
|
end
|
||
|
end
|
||
|
if not fn then
|
||
|
print("Command", command, "not found.")
|
||
|
else
|
||
|
local ok, err = pcall(fn, table.unpack(args))
|
||
|
if not ok then printError(err) end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function message_handler()
|
||
|
while true do
|
||
|
local _, _, _, _, message = os.pullEvent "modem_message"
|
||
|
if type(message) == "table" then
|
||
|
local mtype = table.remove(message, 1)
|
||
|
if mtype == "command" then
|
||
|
local cmd = table.remove(message, 1)
|
||
|
local cmd_fn = remote_commands[cmd]
|
||
|
if cmd_fn then
|
||
|
local ok, res = pcall(cmd_fn, unpack(message))
|
||
|
if ok then
|
||
|
if type(res) == "table" then
|
||
|
send_message("result", cmd, unpack(res))
|
||
|
end
|
||
|
else
|
||
|
printError(res)
|
||
|
send_message("error", res)
|
||
|
end
|
||
|
end
|
||
|
elseif mtype == "result" then os.queueEvent("remote_result", unpack(message))
|
||
|
elseif mtype == "error" then os.queueEvent("remote_error", unpack(message)) end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if ... == "update" then update_self() end
|
||
|
|
||
|
disconnect()
|
||
|
|
||
|
parallel.waitForAny(message_handler, command_prompt)
|