random-stuff/computercraft/spatial_tp.lua

160 lines
4.6 KiB
Lua

local m = peripheral.find("modem", function(_, o) return o.isWireless() end)
local ec_oc = peripheral.find "ender_chest"
local ec_cc = peripheral.find "minecraft:ender chest"
local spatial = "back"
local spatialp = peripheral.wrap(spatial)
local name = os.getComputerLabel()
local channel = 236
local spatial_ec_loc = settings.get "spatial_ec_loc" or "east"
local busy = false
local needed_energy = 34000
local function send(x)
print("->", unpack(x))
m.transmit(channel, channel, x)
end
local function recv_filter(fn)
while true do
local _, _, c, rc, msg = os.pullEvent "modem_message"
print("<-", unpack(msg))
if type(msg) == "table" and fn(msg) then return msg end
end
end
local function pick_channel()
return math.random(0xA00, 0xC00)
end
local function run_spatial()
rs.setOutput(spatial, true)
sleep(0.1)
rs.setOutput(spatial, false)
sleep(0.1)
print "Run spatial"
end
local function run_transfer(trg)
busy = true
local function run_transfer_internal()
if spatialp.getNetworkEnergyStored() < needed_energy then print "Insufficient energy" return end
print "Pinging"
send { "ping", trg }
if (recv_filter(function(m) return m[1] == "pong" and m[2] == trg end))[3] then print "Remote busy" return end
print "Destination available"
local ec_channel = pick_channel()
ec_oc.setFrequency(ec_channel)
send { "transfer", trg, ec_channel }
if not (recv_filter(function(m) return m[1] == "transfer_ack" and m[2] == trg end))[3] then print "Remote denied transfer" return end
print "Ack received"
run_spatial()
spatialp.pushItems(spatial_ec_loc, 2, 1, 1)
print "Sent item to remote"
repeat
sleep(0.1)
until ec_cc.getItemMeta(27) ~= nil
print("Remote sent item")
spatialp.pullItems(spatial_ec_loc, 27, 1, 1)
run_spatial()
spatialp.pullItems("self", 2, 1, 1)
print "Done"
end
parallel.waitForAny(run_transfer_internal, function() sleep(5) print "Transfer timed out" end)
busy = false
end
local pings_timer = nil
local function list_all()
pings_timer = os.startTimer(1)
send { "ping" }
end
local function inbound()
local function run_transfer_recv(msg)
print("Transfer request from", msg[2])
if spatialp.getNetworkEnergyStored() < needed_energy then print "Insufficient energy" send { "transfer_ack", msg[2], false } return end
if busy then print "Already busy, cannot accept transfer" send { "transfer_ack", msg[2], false } return end
busy = true
send { "transfer_ack", msg[2], true }
print("Accepting transfer from", msg[2])
ec_oc.setFrequency(msg[3])
repeat
sleep(0.1)
until ec_cc.getItemMeta(1) ~= nil
print "Remote sent item"
run_spatial()
spatialp.pullItems(spatial_ec_loc, 1, 1, 1)
spatialp.pushItems(spatial_ec_loc, 2, 1, 27)
print "Sent item to remote"
run_spatial()
spatialp.pullItems("self", 2, 1, 1)
print "Done"
end
local function process(msg)
local cmd = msg[1]
if cmd == "ping" and (msg[2] == nil or msg[2] == name) then
send { "pong", name, busy }
elseif pings_timer and cmd == "pong" then
print(msg[2])
elseif cmd == "transfer" and msg[2] == name and type(msg[3]) == "number" then
parallel.waitForAny(function() run_transfer_recv(msg) end, function() sleep(5) print "Inbound transfer timed out" end)
busy = false
end
end
m.open(channel)
while true do
local ev, timer, c, rc, msg = os.pullEvent()
if ev == "modem_message" and c == channel and rc == channel and type(msg) == "table" then
local ok, err = pcall(process, msg)
if not ok then printError(err) end
elseif ev == "timer" and timer == pings_timer then
pings_timer = nil
end
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 update_self()
print "Downloading update."
local h = http.get "https://pastebin.com/raw/R4HrijSg"
local t = h.readAll()
h.close()
local fn, err = load(t, "@program")
if not fn then printError("Not updating: syntax error in new version:\n" .. err) return end
local f = fs.open("startup", "w")
f.write(t)
f.close()
os.reboot()
end
local function ui()
local history = {}
while true do
write "|> "
local input = read(nil, history)
table.insert(history, input)
local tokens = split_at_spaces(input)
if tokens[1] == "list" then
list_all()
sleep(1)
elseif tokens[1] == "update" then
update_self()
elseif tokens[1] == "tp" then
table.remove(tokens, 1)
run_transfer(table.concat(tokens, " "))
else
printError "Not found"
end
end
end
parallel.waitForAll(ui, inbound)