├── test ├── temp.txt ├── reportRednetMessages.lua ├── temp_2.lua ├── pathfinder.lua ├── temp_1.lua ├── files.lua ├── autogeneratestations.lua ├── turtle │ ├── testMine.lua │ └── testPerformance.lua ├── tables.lua ├── debuginfo.lua ├── loop_chars.lua ├── inventory.lua ├── lists.lua ├── autoplaceturtles.lua ├── serialize_consistency.lua ├── bluenet_performance_receive.lua ├── classes.lua ├── startupDownload.lua ├── serialization.lua ├── temp.lua ├── message_meta.lua ├── testMonitor.lua └── bluenet_local_instance.lua ├── storage ├── standalone │ ├── global.lua │ ├── main.lua │ ├── initialize.lua │ ├── startup.lua │ ├── receive.lua │ └── update.lua └── test.lua ├── old ├── initRednet.lua ├── classMonitorPrivate.lua ├── pocket │ ├── initialize.lua │ ├── startup.lua │ └── update.lua ├── classNetworkHost.lua ├── classListOld.lua ├── bluenet.lua ├── classNetworkClient.lua ├── classMap.lua ├── requireBluenetTable.lua └── pathFindingOld.lua ├── config_changes.txt ├── pocket └── shellDisplay.lua ├── general ├── classLogger.lua ├── classQueue.lua ├── killRednet.lua ├── classSimpleVector.lua ├── classHeap.lua ├── classList.lua └── bluenet.lua ├── turtle ├── testMine.lua ├── startup.lua ├── initialize.lua ├── global.lua ├── main.lua ├── testPerformance.lua ├── classCheckPointer.lua ├── send.lua ├── update.lua └── receive.lua ├── gui ├── classLabel.lua ├── classFrame.lua ├── classCheckBox.lua ├── classToggleButton.lua ├── classChoiceSelector.lua ├── classBox.lua ├── classGPU.lua ├── classButton.lua ├── classStorageDisplay.lua └── classTaskSelector.lua ├── host ├── display.lua ├── initialize.lua ├── startup.lua ├── send.lua ├── receive.lua └── hostTransfer.lua ├── startup.lua ├── mon.lua ├── install.lua └── README.md /test/temp.txt: -------------------------------------------------------------------------------- 1 | { 2 | minecraft = 1, 3 | } -------------------------------------------------------------------------------- /storage/standalone/global.lua: -------------------------------------------------------------------------------- 1 | 2 | running = true 3 | storage = nil 4 | pos = {} -------------------------------------------------------------------------------- /test/reportRednetMessages.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | while true do 4 | local event, p1, p2, p3, p4, p5 = os.pullEvent("rednet_message") 5 | print(event, p1, p2, p3, p4, p5) 6 | end -------------------------------------------------------------------------------- /storage/standalone/main.lua: -------------------------------------------------------------------------------- 1 | 2 | local global = global 3 | local nodeStorage = global.storage.node 4 | 5 | while global.running do 6 | 7 | nodeStorage:checkMessages() 8 | sleep(0) 9 | end 10 | 11 | print("eeeh how", global.running) -------------------------------------------------------------------------------- /old/initRednet.lua: -------------------------------------------------------------------------------- 1 | 2 | require("classNetworkNode") 3 | 4 | local node = NetworkNode:new("miner",true) 5 | 6 | while true do 7 | local msg = node:broadcast({"RUN","testMine"},true) 8 | if msg then 9 | print(msg.data[1]) 10 | end 11 | print("sent") 12 | sleep(1) 13 | end 14 | -------------------------------------------------------------------------------- /test/temp_2.lua: -------------------------------------------------------------------------------- 1 | 2 | --require("runtime/global") 3 | local glob = global 4 | 5 | while true do 6 | 7 | local event, time = os.pullEvent() 8 | if event == "test" then 9 | print(event,time) 10 | elseif event == "timer" then 11 | --print(event,time) 12 | end 13 | 14 | -- global.running = ( glob.running == false ) 15 | -- print(os.epoch("local"), glob.running) 16 | -- sleep(0.2) 17 | end -------------------------------------------------------------------------------- /test/pathfinder.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- add to classMiner 4 | function Miner:testPathfinding(distance) 5 | 6 | local goal = vector.new(self.pos.x + distance, self.pos.y, self.pos.z) 7 | self.map:setMaxChunks(800) 8 | local pathFinder = PathFinder() 9 | pathFinder.checkValid = checkSafe 10 | local path = pathFinder:aStarPart(self.pos, self.orientation, goal , self.map, 10000) 11 | end 12 | 13 | -- execute in terminal 14 | global.miner:testPathfinding(50) -------------------------------------------------------------------------------- /config_changes.txt: -------------------------------------------------------------------------------- 1 | server: 2 | 3 | --space limit > 100 MB per computer 4 | computer_space_limit = 100000000 5 | 6 | -- enable http 7 | #Enable the "http" API on Computers. This also disables the "pastebin" and "wget" 8 | #programs, that many users rely on. It's recommended to leave this on and use the 9 | #"rules" config option to impose more fine-grained control. 10 | enabled = true 11 | #Enable use of http websockets. This requires the "http_enable" option to also be true. 12 | websocket_enabled = true -------------------------------------------------------------------------------- /storage/standalone/initialize.lua: -------------------------------------------------------------------------------- 1 | 2 | local RemoteStorage = require("classRemoteStorage") 3 | 4 | 5 | local function initPosition() 6 | local x,y,z = gps.locate() 7 | if x and y and z then 8 | x, y, z = math.floor(x), math.floor(y), math.floor(z) 9 | global.pos = vector.new(x,y,z) 10 | else 11 | print("gps not working") 12 | global.pos = vector.new(0,70,0) -- this is bad for turtles especially 13 | end 14 | print("position:",global.pos.x,global.pos.y,global.pos.z) 15 | end 16 | 17 | initPosition() 18 | 19 | global.storage = RemoteStorage:new() -------------------------------------------------------------------------------- /test/temp_1.lua: -------------------------------------------------------------------------------- 1 | 2 | -- require("general/classBluenetNode") 3 | 4 | -- local node = NetworkNode:new("test") 5 | print(bluenet, global) 6 | local global = global 7 | 8 | while true do 9 | local event, time = os.pullEvent() 10 | if event == "test" then 11 | print(event,time,global.running) 12 | elseif event == "timer" then 13 | --print(event,time) 14 | end 15 | end 16 | 17 | 18 | 19 | 20 | m = global.miner; m.map:findNextBlock(m.pos, m.checkOreBlock, 8) 21 | 22 | m = global.miner; s = vector.new(2229, 68, -2651); e = vector.new(2226, 69, -2647); m:excavateArea(s,e) -------------------------------------------------------------------------------- /storage/test.lua: -------------------------------------------------------------------------------- 1 | 2 | local storage = global.storage 3 | 4 | if os.getComputerID() == 68 then 5 | storage.providerPos = vector.new(2214, 69, -2673) 6 | else 7 | storage.providerPos = vector.new(2220, 69, -2660) 8 | end 9 | storage.requestingPos = storage.providerPos 10 | 11 | storage:getInventories() 12 | storage:indexInventories() 13 | 14 | --storage:pingTurtles() 15 | --local availableTurtles = storage:getNearestAvailableTurtles() 16 | 17 | --for i, turtle in ipairs(availableTurtles) do 18 | -- print("Available turtle:", turtle.id, "Distance:", turtle.dist) 19 | --end 20 | 21 | -- global.storage:requestReserveItems("minecraft:cobblestone", 200) -------------------------------------------------------------------------------- /old/classMonitorPrivate.lua: -------------------------------------------------------------------------------- 1 | function newMonitor(m) 2 | self = { 3 | width = 0, 4 | height = 0, 5 | } 6 | 7 | setmetatable(self, m) 8 | m.__index = m 9 | 10 | local updateSize = function() 11 | self.width, height = self.getSize() 12 | end 13 | local getWidth = function() 14 | updateSize() 15 | return self.width 16 | end 17 | local getHeight = function() 18 | updateSize() 19 | return self.height 20 | end 21 | return { 22 | width = self.width, 23 | height = self.height, 24 | self = self, 25 | getWidth = getWidth, 26 | getHeight = getHeight 27 | } 28 | end 29 | -------------------------------------------------------------------------------- /test/files.lua: -------------------------------------------------------------------------------- 1 | 2 | -- test how fast files can be written to 3 | 4 | local fileName = "filetest.txt" 5 | 6 | 7 | local f 8 | local function createFile() 9 | --if fs.exists(fileName) then 10 | --fs.delete(fileName) -- extremely slow 11 | --end 12 | 13 | f.write(textutils.serialize(debug.traceback())) 14 | f.flush() 15 | --f.write("jooooooooo") 16 | 17 | end 18 | 19 | local function testFiles() 20 | local start = os.epoch("local") 21 | f = fs.open(fileName, "w") 22 | for i = 1, 1000 do 23 | createFile() 24 | end 25 | f.close() 26 | print(os.epoch("local")-start) 27 | end 28 | testFiles() 29 | 30 | 31 | -- delete is very slow (600ms) 32 | -- keeping file open is fastest (6ms) 33 | -- reopening file (200ms) 34 | -- flush (6ms) -------------------------------------------------------------------------------- /storage/standalone/startup.lua: -------------------------------------------------------------------------------- 1 | -- startup file for standalone storage computer 2 | 3 | if rednet then 4 | os.loadAPI("/runtime/bluenet.lua") 5 | shell.run("/runtime/update.lua") 6 | 7 | shell.run("runtime/killRednet.lua") 8 | return 9 | end 10 | 11 | -- add runtime as default environment 12 | package.path = package.path ..";../runtime/?.lua" 13 | 14 | 15 | 16 | os.loadAPI("/runtime/global.lua") 17 | os.loadAPI("/runtime/bluenet.lua") 18 | 19 | shell.run("runtime/initialize.lua") 20 | 21 | 22 | if pocket then 23 | -- eerm only for viewing storage i guess? 24 | -- perhaps deliver items to current position? 25 | end 26 | 27 | shell.openTab("runtime/main.lua") 28 | shell.openTab("runtime/receive.lua") 29 | -------------------------------------------------------------------------------- /pocket/shellDisplay.lua: -------------------------------------------------------------------------------- 1 | 2 | local Monitor = require("classMonitor") 3 | local HostDisplay = require("classHostDisplay") 4 | 5 | local global = global 6 | 7 | global.monitor = Monitor:new(term.current()) 8 | global.display = HostDisplay:new(1,1,global.monitor:getWidth(),global.monitor:getHeight()) 9 | local monitor = global.monitor 10 | 11 | while global.running do 12 | local event, p1, p2, p3, msg, p5 = os.pullEventRaw() 13 | if event == "mouse_up" then -- or event == "mouse_click" or event == "monitor_resize" then 14 | monitor:addEvent({event,p1,p2,p3,msg,p5}) 15 | elseif event == "input_request" then 16 | local input = read() 17 | os.queueEvent("input_response", input) 18 | elseif event == "terminate" then 19 | error("Terminated",0) 20 | end 21 | end -------------------------------------------------------------------------------- /general/classLogger.lua: -------------------------------------------------------------------------------- 1 | local default = { 2 | fileName = "log.txt", 3 | } 4 | 5 | Logger = {} 6 | 7 | function Logger:new(fileName) 8 | local o = o or {} 9 | setmetatable(o,self) 10 | self.__index = self 11 | 12 | self.fileName = fileName or default.fileName 13 | self.entries = {} 14 | 15 | return self 16 | end 17 | 18 | function Logger:initialize() 19 | 20 | end 21 | 22 | function Logger:save(fileName) 23 | fileName = fileName or self.fileName 24 | local f = fs.open(fileName, "w") 25 | f.write(textutils.serialize(self.entries)) 26 | f.close() 27 | end 28 | 29 | function Logger:addFirst(entry) 30 | table.insert(self.entries, entry) 31 | end 32 | 33 | function Logger:print() 34 | for _,entry in ipairs(self.entries) do 35 | print(textutils.serialize(entry)) 36 | end 37 | end -------------------------------------------------------------------------------- /test/autogeneratestations.lua: -------------------------------------------------------------------------------- 1 | 2 | local g = global 3 | 4 | local function createStations(sx,sy,sz, amountPerRow, rows, rowDistance) 5 | config.stations.turtles = {} 6 | 7 | -- minus x direction 8 | 9 | for row = 1, rows do 10 | for k = 1, amountPerRow do 11 | local x = sx - (k - 1) 12 | local y = sy + (row - 1) * rowDistance 13 | g.addStation(x, y, sz, "north", "turtle") 14 | end 15 | end 16 | end 17 | 18 | local function createStationsDiagonal(sx,sy,sz, amountPerRow, rows, rowDistance) 19 | config.stations.turtles = {} 20 | 21 | -- minus x direction 22 | 23 | for row = 1, rows do 24 | for k = 1, amountPerRow do 25 | local x = sx - (k - 1) 26 | local y = sy + (row - 1) * rowDistance 27 | local z = sz - (row - 1) * rowDistance 28 | g.addStation(x, y, z, "north", "turtle") 29 | end 30 | end 31 | end 32 | 33 | createStationsDiagonal(60, 66, -12, 25, 10, 2) 34 | -------------------------------------------------------------------------------- /general/classQueue.lua: -------------------------------------------------------------------------------- 1 | Queue = {} 2 | 3 | function Queue:new(o) 4 | local o = o or {} 5 | setmetatable(o, {__index = self}) 6 | self.__index = self 7 | o.first = 0 8 | o.last = -1 9 | return o 10 | end 11 | 12 | function Queue:pushLeft(value) 13 | local first = self.first - 1 14 | self.first = first 15 | self[first] = value 16 | end 17 | 18 | function Queue:pushRight(value) 19 | local last = self.last + 1 20 | self.last = last 21 | self[last] = value 22 | end 23 | 24 | function Queue:popLeft() 25 | local first = self.first 26 | if first > self.last then return nil end 27 | local value = self[first] 28 | self[first] = nil -- to allow garbage collection 29 | self.first = first + 1 30 | return value 31 | end 32 | 33 | function Queue:popRight() 34 | local last = self.last 35 | if self.first > last then return nil end 36 | local value = self[last] 37 | self[last] = nil -- to allow garbage collection 38 | self.last = last - 1 39 | return value 40 | end 41 | -------------------------------------------------------------------------------- /turtle/testMine.lua: -------------------------------------------------------------------------------- 1 | require("classMiner") 2 | 3 | args = {...} 4 | 5 | 6 | --error({real=false,text="test",func="lul"}) 7 | 8 | local monitors = {peripheral.find("monitor")} 9 | local monitor = monitors[1] 10 | if monitor then 11 | assert(monitor, "no monitor found") 12 | monitor.clear() 13 | monitor.setCursorPos(1,1) 14 | monitor.write("myID: " .. os.getComputerID()) 15 | monitor.setCursorPos(1,2) 16 | monitor.write("status: working") 17 | end 18 | 19 | miner = global.miner 20 | 21 | --miner:setHome(miner.pos.x, miner.pos.y, miner.pos.z) 22 | --miner:mineVein("minecraft:iron_ore") 23 | 24 | 25 | miner:navigateToPos(275, 70, -177) 26 | --miner:stripMine(miner.pos.y, 3, 3) 27 | miner:returnHome() 28 | miner:condenseInventory() 29 | miner:dumpBadItems() 30 | miner:transferItems() 31 | --miner:returnHome() 32 | miner.map:save() 33 | 34 | print("DONE") 35 | sleep(30) 36 | 37 | if monitor then 38 | monitor.clear() 39 | 40 | monitor.setCursorPos(1,1) 41 | monitor.write("myID: " .. os.getComputerID()) 42 | monitor.setCursorPos(1,2) 43 | monitor.write("status: ready") 44 | end -------------------------------------------------------------------------------- /test/turtle/testMine.lua: -------------------------------------------------------------------------------- 1 | require("classMiner") 2 | 3 | args = {...} 4 | 5 | 6 | --error({real=false,text="test",func="lul"}) 7 | 8 | local monitors = {peripheral.find("monitor")} 9 | local monitor = monitors[1] 10 | if monitor then 11 | assert(monitor, "no monitor found") 12 | monitor.clear() 13 | monitor.setCursorPos(1,1) 14 | monitor.write("myID: " .. os.getComputerID()) 15 | monitor.setCursorPos(1,2) 16 | monitor.write("status: working") 17 | end 18 | 19 | miner = global.miner 20 | 21 | --miner:setHome(miner.pos.x, miner.pos.y, miner.pos.z) 22 | --miner:mineVein("minecraft:iron_ore") 23 | 24 | 25 | miner:navigateToPos(275, 70, -177) 26 | --miner:stripMine(miner.pos.y, 3, 3) 27 | miner:returnHome() 28 | miner:condenseInventory() 29 | miner:dumpBadItems() 30 | miner:transferItems() 31 | --miner:returnHome() 32 | miner.map:save() 33 | 34 | print("DONE") 35 | sleep(30) 36 | 37 | if monitor then 38 | monitor.clear() 39 | 40 | monitor.setCursorPos(1,1) 41 | monitor.write("myID: " .. os.getComputerID()) 42 | monitor.setCursorPos(1,2) 43 | monitor.write("status: ready") 44 | end -------------------------------------------------------------------------------- /test/tables.lua: -------------------------------------------------------------------------------- 1 | local tinsert = table.insert 2 | 3 | function testInsertPerformance() 4 | local iterations = 10000000 -- Number of insertions to test 5 | local data = 1 -- Example data to insert 6 | 7 | -- Test table.insert 8 | local buf1 = {} 9 | local start = os.epoch("utc") 10 | for i = 1, iterations do 11 | table.insert(buf1, data) 12 | end 13 | local timeTableInsert = os.epoch("utc") - start 14 | print("table.insert:", timeTableInsert, "ms") 15 | 16 | -- Test local tinsert = table.insert 17 | local buf2 = {} 18 | 19 | start = os.epoch("utc") 20 | for i = 1, iterations do 21 | tinsert(buf2, data) 22 | end 23 | local timeLocalTInsert = os.epoch("utc") - start 24 | print("local tinsert:", timeLocalTInsert, "ms") 25 | 26 | -- Test buf[#buf+1] = data 27 | local buf3 = {} 28 | start = os.epoch("utc") 29 | for i = 1, iterations do 30 | buf3[#buf3 + 1] = data 31 | end 32 | local timeDirectInsert = os.epoch("utc") - start 33 | print("buf[#buf+1]:", timeDirectInsert, "ms") 34 | end 35 | 36 | testInsertPerformance() -------------------------------------------------------------------------------- /turtle/startup.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | if rednet then 4 | os.loadAPI("/runtime/bluenet.lua") 5 | shell.run("runtime/update.lua") 6 | 7 | shell.run("runtime/killRednet.lua") 8 | return 9 | end 10 | 11 | 12 | os.loadAPI("/runtime/global.lua") 13 | os.loadAPI("/runtime/config.lua") 14 | 15 | 16 | shell.run("runtime/initialize.lua") 17 | 18 | 19 | -- initialize miner should run before openTab 20 | -- otherwise turtle.forward can get stuck indefinetely 21 | 22 | tabMain = shell.openTab("runtime/main.lua") 23 | tabReceive = shell.openTab("runtime/receive.lua") 24 | tabSend = shell.openTab("runtime/send.lua") 25 | 26 | 27 | multishell.setTitle(tabMain, "main") 28 | multishell.setTitle(tabReceive, "receive") 29 | multishell.setTitle(tabSend, "send") 30 | 31 | if global.miner then 32 | local status,err = pcall(function() 33 | global.miner:finishInitialization() 34 | end ) 35 | global.handleError(err,status) 36 | end 37 | 38 | -- MultiShell tests: 39 | -- shell.openTab("/multi/multi_1.lua") 40 | -- shell.openTab("multi/multi_2") 41 | 42 | --shell.openTab better than multishell.launch because it does not disable some global functionalities like require() -------------------------------------------------------------------------------- /turtle/initialize.lua: -------------------------------------------------------------------------------- 1 | 2 | -- initialize the required globals 3 | 4 | require("classList") 5 | require("classMiner") 6 | require("classBluenetNode") 7 | --require("classNetworkNode") 8 | 9 | tasks = {} 10 | global.list = List:new() 11 | -- global.defaultHost = 0 12 | 13 | local function createLabel() 14 | if os.getComputerLabel() == "" or not os.getComputerLabel() then 15 | os.setComputerLabel(tostring(os.getComputerID())) 16 | end 17 | end 18 | 19 | local function initNode() 20 | global.node = NetworkNode:new("miner") 21 | end 22 | local function initStream() 23 | global.nodeStream = NetworkNode:new("miner_stream") 24 | end 25 | local function initRefuel() 26 | global.nodeRefuel = NetworkNode:new("refuel", false, true) 27 | end 28 | local function initStorage() 29 | global.nodeStorage = NetworkNode:new("storage",false, true) 30 | end 31 | 32 | createLabel() 33 | parallel.waitForAll(initNode,initStream, initRefuel, initStorage) 34 | 35 | if not global.node.host then 36 | error(global.node.host, 0) 37 | else 38 | local status,err = pcall(function() 39 | global.miner = Miner:new() 40 | global.map = global.miner.map 41 | end ) 42 | global.handleError(err,status) 43 | 44 | end -------------------------------------------------------------------------------- /gui/classLabel.lua: -------------------------------------------------------------------------------- 1 | local default = { 2 | textColor = colors.white, 3 | backgroundColor = colors.black, 4 | } 5 | 6 | local Label = {} 7 | 8 | function Label:new(text,x,y,textColor, backgroundColor) 9 | local o = o or {} 10 | setmetatable(o, self) 11 | self.__index = self 12 | 13 | o.backgroundColor = backgroundColor 14 | o.text = tostring(text) or "" 15 | o.x = x or 0 16 | o.y = y or 0 17 | o.textColor = textColor or default.textColor 18 | 19 | return o 20 | end 21 | 22 | function Label:getTextColor() 23 | return self.textColor 24 | end 25 | 26 | function Label:setTextColor(color) 27 | self.textColor = color 28 | end 29 | function Label:setBackgroundColor(color) 30 | self.backgroundColor = color 31 | end 32 | function Label:getBackgroundColor() 33 | return self.backgroundColor 34 | end 35 | function Label:setPos(x,y) 36 | self.x = x 37 | self.y = y 38 | end 39 | 40 | function Label:setText(text) 41 | self.text = tostring(text) 42 | end 43 | function Label:getText() 44 | return self.text 45 | end 46 | function Label:redraw() 47 | if self.parent and self.visible then 48 | self.parent:drawText(self.x, self.y, self:getText(), self.textColor, self.backgroundColor) 49 | end 50 | end 51 | 52 | return Label -------------------------------------------------------------------------------- /host/display.lua: -------------------------------------------------------------------------------- 1 | 2 | local global = global 3 | local display = global.display 4 | local monitor = global.monitor 5 | 6 | monitor:addObject(display) 7 | monitor:redraw() 8 | 9 | local frame = 0 10 | 11 | local function catchEvents() 12 | local event, p1, p2, p3, msg, p5 = os.pullEvent("mouse_up") 13 | if event == "mouse_up" or event == "mouse_click" or event == "monitor_resize" then 14 | monitor:addEvent({event,p1,p2,p3,msg,p5}) 15 | end 16 | end 17 | 18 | 19 | while global.running and global.displaying do 20 | --local start = os.epoch("local") 21 | monitor:checkEvents() 22 | --local t1 = os.epoch("local")-start 23 | --start = os.epoch("local") 24 | if frame%5 == 0 then 25 | display:refresh() 26 | 27 | end 28 | -- display:refresh() 29 | -- local t2 = os.epoch("local")-start 30 | -- start = os.epoch("local") 31 | 32 | monitor:update() 33 | 34 | -- local t3 = os.epoch("local")-start 35 | -- print("events", t1, "refresh",t2, "update",t3) 36 | frame = frame + 1 37 | sleep(0.05) 38 | end 39 | 40 | print("display stopped, how?", global.running, global.displaying) 41 | --if pocket then 42 | -- -- if on pocket, pull events 43 | -- parallel.waitForAny( 44 | -- update(), 45 | -- catchEvents() 46 | -- 47 | -- ) 48 | --else 49 | -- update() 50 | --end 51 | -------------------------------------------------------------------------------- /test/debuginfo.lua: -------------------------------------------------------------------------------- 1 | 2 | package.path = package.path ..";../runtime/?.lua" 3 | 4 | require("classList") 5 | local list = List:new() 6 | local debuginfo = debug.getinfo 7 | 8 | local function addTask(task) 9 | return list:addFirst(task) 10 | end 11 | 12 | local function testInfo() 13 | for j = 1, 5 do 14 | list = List:new() 15 | local start = os.epoch("local") 16 | for k = 1, 100000 do 17 | local info = addTask(debug.getinfo(1,"n")) 18 | end 19 | local t = os.epoch("local")-start 20 | print(t,"debug.getinfo") 21 | end 22 | end 23 | 24 | local function testChar() 25 | for j = 1, 5 do 26 | list = List:new() 27 | local start = os.epoch("local") 28 | for k = 1, 100000 do 29 | local info = addTask(debuginfo(1,"n")) 30 | --list:addFirst(debuginfo(1,"n")) 31 | 32 | end 33 | local t = os.epoch("local")-start 34 | print(t,"debuginfo") 35 | end 36 | end 37 | 38 | local function testPreset() 39 | for j = 1, 5 do 40 | list = List:new() 41 | local start = os.epoch("local") 42 | for k = 1, 100000 do 43 | local info = addTask({"preset"}) 44 | end 45 | local t = os.epoch("local")-start 46 | print(t,"preset") 47 | end 48 | end 49 | 50 | -- without addTask with 51 | testInfo() --115 340 52 | testChar() --90 310 53 | testPreset() --15 200 -------------------------------------------------------------------------------- /turtle/global.lua: -------------------------------------------------------------------------------- 1 | 2 | -- global variables 3 | 4 | tasks = {} 5 | list = {} 6 | miner = nil 7 | err = nil 8 | node = nil 9 | nodeStream = nil 10 | nodeRefuel = nil 11 | nodeStorage = nil 12 | 13 | handleError = function(err,status) 14 | if not status then 15 | if err.real == nil then 16 | -- unknown error 17 | global.err = {} 18 | global.err.text = err 19 | global.err.func = "" 20 | elseif err.real == false then 21 | -- error on purpose to cancel running programs 22 | -- global.err = err 23 | global.err = nil 24 | else 25 | -- real error 26 | global.err = err 27 | end 28 | if global.err then 29 | print(global.err.real, global.err.func, global.err.text) 30 | end 31 | else 32 | -- clear previous errors 33 | global.err = nil 34 | end 35 | end 36 | 37 | 38 | requestStation = function() 39 | if global.node then 40 | if not global.node.host then global.node.host = 0 end 41 | -- global.node.onNoAnswer = function(forMsg) 42 | -- print("no answer", forMsg.id) 43 | -- end 44 | -- global.node.onAnswer = function(answer,forMsg) 45 | -- print(answer) 46 | -- print("b", os.epoch("ingame"),answer.id, answer.time) 47 | -- end 48 | local answer, forMsg = global.node:send(global.node.host,{"REQUEST_STATION"},true,true) 49 | if answer then 50 | print("a", os.epoch("ingame"),answer.data[1]) 51 | end 52 | end 53 | end -------------------------------------------------------------------------------- /gui/classFrame.lua: -------------------------------------------------------------------------------- 1 | local Box = require("classBox") 2 | 3 | local default = { 4 | borderColor = colors.gray, 5 | backgroundColor = colors.black, 6 | textColor = colors.white 7 | } 8 | local Frame = Box:new() 9 | 10 | function Frame:new(text,x,y,width,height,borderColor) 11 | local o = o or Box:new(x,y,width,height,default.backgroundColor) 12 | setmetatable(o, self) 13 | self.__index = self 14 | 15 | o.backgroundColor = default.backgroundColor 16 | o.borderColor = borderColor or default.borderColor 17 | o.textColor = default.textColor 18 | o.text = text or "" 19 | --o.area = Area:new(o.x-1, o.y-1, o.width-2, o.height-2) 20 | 21 | return o 22 | end 23 | 24 | function Frame:setText(text) 25 | self.text = tostring(text) 26 | end 27 | 28 | function Frame:getText() 29 | return self.text 30 | end 31 | function Frame:setBorderColor(color) 32 | self.borderColor = color 33 | end 34 | function Frame:getBorderColor() 35 | return self.borderColor 36 | end 37 | function Frame:setTextColor(color) 38 | self.textColor = color 39 | end 40 | function Frame:getTextColor() 41 | return self.textColor 42 | end 43 | function Frame:redraw() 44 | --super 45 | Box.redraw(self) 46 | 47 | --Label 48 | if self.parent and self.visible then 49 | self.parent:drawText(self.x+3, self.y, " " .. self:getText() .. " ", self.textColor, self.backgroundColor) 50 | end 51 | end 52 | 53 | return Frame -------------------------------------------------------------------------------- /test/loop_chars.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | local sub = string.sub 4 | local char = string.char 5 | local byte = string.byte 6 | 7 | local str = "aasdfasdfasdfadfkuahdpqzu8jhdöfkajshdfoauiszdflaksdfhöladshfalsdhf" 8 | local x = 100 9 | 10 | local function subs(str) 11 | local chars = {} 12 | --local sub = string.sub 13 | local y = x-1 14 | for i = x, #str+y do 15 | local p = i-y 16 | chars[i] = sub(str,p,p) 17 | chars[i] = sub(str,p,p) 18 | chars[i] = sub(str,p,p) 19 | end 20 | return chars 21 | end 22 | 23 | 24 | local function chart(str) 25 | --local char = string.char 26 | local y = x-1 27 | local chars = {} 28 | local bytes = {byte(str, 1, #str)} 29 | for i = x, #bytes+y do 30 | local p = i-y 31 | chars[i] = char(bytes[p]) 32 | chars[i] = char(bytes[p]) 33 | chars[i] = char(bytes[p]) 34 | end 35 | return chars 36 | end 37 | 38 | local function testSub() 39 | for j = 1, 5 do 40 | local start = os.epoch("local") 41 | for k = 1, 20000 do 42 | local chars = subs("hallo") 43 | end 44 | local t = os.epoch("local")-start 45 | print(t,"sub") 46 | sleep(0) 47 | end 48 | end 49 | 50 | local function testChar() 51 | for j = 1, 5 do 52 | local start = os.epoch("local") 53 | for k = 1, 20000 do 54 | local chars = chart("hallo") 55 | end 56 | local t = os.epoch("local")-start 57 | print(t,"char") 58 | sleep(0) 59 | end 60 | end 61 | 62 | testSub() -- 350 long string -- 41 short string 63 | testChar() -- 305 long string -- 48 short string -------------------------------------------------------------------------------- /general/killRednet.lua: -------------------------------------------------------------------------------- 1 | 2 | local function biosWithoutRednet() 3 | -- run the shell without rednet 4 | 5 | os.unloadAPI("rednet") -- optional 6 | 7 | local ok, err = pcall( 8 | function() 9 | local sShell 10 | if term.isColour() and settings.get("bios.use_multishell") then 11 | sShell = "rom/programs/advanced/multishell.lua" 12 | else 13 | sShell = "rom/programs/shell.lua" 14 | end 15 | os.run({}, sShell) 16 | os.run({}, "rom/programs/shutdown.lua") 17 | end 18 | ) 19 | -- [...]error handling shutdown etc. see bios.lua 20 | 21 | -- If the shell errored, let the user read it. 22 | term.redirect(term.native()) 23 | if not ok then 24 | printError(err) 25 | pcall(function() 26 | term.setCursorBlink(false) 27 | print("Press any key to continue") 28 | os.pullEvent("key") 29 | end) 30 | end 31 | 32 | -- End 33 | os.shutdown() 34 | 35 | end 36 | 37 | if rednet then 38 | 39 | setfenv(biosWithoutRednet, _G) 40 | 41 | -- trigger pullEventRaw in rednet.run to fail 42 | -- ignore the error and go to os.reboot 43 | local originalError = _G.error 44 | local originalShutdown = _G.os.shutdown 45 | local originalPullEventRaw = _G.os.pullEventRaw 46 | 47 | _G.error = function() end 48 | _G.os.pullEventRaw = nil 49 | _G.os.shutdown = function() 50 | -- intercept shutdown and restore functions 51 | _G.error = originalError 52 | _G.os.pullEventRaw = originalPullEventRaw 53 | _G.os.shutdown = originalShutdown 54 | -- start the shell again, without rednet 55 | return biosWithoutRednet() 56 | end 57 | end -------------------------------------------------------------------------------- /storage/standalone/receive.lua: -------------------------------------------------------------------------------- 1 | local bluenet = require("bluenet") 2 | local ownChannel = bluenet.ownChannel 3 | local channelBroadcast = bluenet.default.channels.broadcast 4 | local channelStorage = bluenet.default.channels.storage 5 | local computerId = os.getComputerID() 6 | 7 | local global = global 8 | if not global.storage then 9 | error("NO GLOBAL STORAGE AVAILABLE",0) 10 | end 11 | local nodeStorage = global.storage.node 12 | 13 | local pullEventRaw = os.pullEventRaw 14 | local type = type 15 | while global.running do 16 | 17 | -- !! none of the functions called here can use os.pullEvent !! 18 | local event, p1, p2, p3, msg, p5 = pullEventRaw() 19 | if event == "modem_message" 20 | --and ( p2 == ownChannel or p2 == channelBroadcast or p2 == channelHost ) 21 | and type(msg) == "table" 22 | and ( type(msg.recipient) == "number" and msg.recipient 23 | and ( msg.recipient == computerId or msg.recipient == channelBroadcast 24 | or msg.recipient == channelStorage) ) 25 | -- just to make sure its a bluenet message 26 | then 27 | -- event, modem, channel, replyChannel, message, distance 28 | msg.distance = p5 29 | local protocol = msg.protocol 30 | if protocol == "storage" then 31 | print("received", msg.data[1], msg.sender) 32 | nodeStorage:addMessage(msg) 33 | elseif protocol == "storage_priority" then 34 | print("priority", msg.data[1], msg.sender) 35 | nodeStorage:handleMessage(msg) 36 | end 37 | 38 | elseif event == "terminate" then 39 | error("Terminated",0) 40 | end 41 | end -------------------------------------------------------------------------------- /gui/classCheckBox.lua: -------------------------------------------------------------------------------- 1 | local Button = require("classButton") 2 | 3 | local defaultBackgroundColor = colors.black 4 | local defaultHeight = 1 5 | local defaultTextOn = "[X]" 6 | local defaultTextOff = "[ ]" 7 | 8 | local CheckBox = Button:new() 9 | 10 | function CheckBox:new(x,y,text,active, width,height,color) 11 | local o = o or Button:new(text, x,y,width ,height or defaultHeight, color or defaultBackgroundColor) 12 | setmetatable(o, self) 13 | self.__index = self 14 | o.textOn = defaultTextOn 15 | o.textOff = defaultTextOff 16 | o.midX = o.x 17 | o.active = active or false 18 | o.text = text or "" 19 | o:initialize() 20 | return o 21 | end 22 | 23 | function CheckBox:initialize() 24 | self:setText(self.text or "") 25 | self.width = width or string.len(self.labelText) + string.len(self.textOn) + 1 26 | end 27 | 28 | function CheckBox:handleClick() 29 | self:toggle() 30 | --super 31 | Button.handleClick(self) 32 | 33 | self:redraw() 34 | end 35 | 36 | function CheckBox:toggle() 37 | self.active = (self.active == false) 38 | self:refresh() 39 | end 40 | 41 | function CheckBox:setText(text) 42 | --override 43 | self.labelText = tostring(text) 44 | self:refresh() 45 | end 46 | 47 | function CheckBox:refresh() 48 | if self.active then 49 | self.text = self.textOn .. " " .. self.labelText 50 | else 51 | self.text = self.textOff .. " " .. self.labelText 52 | end 53 | end 54 | 55 | function CheckBox:setTextOn(text) 56 | self.textOn = tostring(text) 57 | self:refresh() 58 | end 59 | 60 | function CheckBox:setTextOff(text) 61 | self.textOff = tostring(text) 62 | self:refresh() 63 | end 64 | 65 | return CheckBox -------------------------------------------------------------------------------- /gui/classToggleButton.lua: -------------------------------------------------------------------------------- 1 | local Button = require("classButton") 2 | 3 | local defaultColorOn = colors.green 4 | local defaultColorOff = colors.red 5 | local defaultTextOn = "ON" 6 | local defaultTextOff = "OFF" 7 | 8 | local ToggleBtn = Button:new() 9 | 10 | function ToggleBtn:new(x,y,width,height,colorOn,colorOff) 11 | local o = o or Button:new(defaultTextOn, x,y,width ,height, colorOn or defaultColorOn) 12 | setmetatable(o, self) 13 | self.__index = self 14 | o.colorOn = colorOn or defaultColorOn 15 | o.colorOff = colorOff or defaultColorOff 16 | o.textOn = defaultTextOn 17 | o.textOff = defaultTextOff 18 | o.active = true 19 | return o 20 | end 21 | 22 | function ToggleBtn:handleClick() 23 | --super 24 | Button.handleClick(self) 25 | --toggle 26 | self:toggle() 27 | self:redraw() 28 | end 29 | function ToggleBtn:toggle() 30 | self.active = (self.active == false) 31 | self:refresh() 32 | end 33 | 34 | function ToggleBtn:refresh() 35 | if self.active then 36 | self.backgroundColor = self.colorOn 37 | self:setText(self.textOn) 38 | else 39 | self.backgroundColor = self.colorOff 40 | self:setText(self.textOff) 41 | end 42 | end 43 | function ToggleBtn:setColorOn(color) 44 | self.colorOn = color 45 | self:refresh() 46 | end 47 | function ToggleBtn:setColorOff(color) 48 | self.colorOff = color 49 | self:refresh() 50 | end 51 | function ToggleBtn:setColor(colorOn,colorOff) 52 | self:setColorOn(colorOn) 53 | self:setColorOff(colorOff) 54 | end 55 | function ToggleBtn:setTextOn(text) 56 | self.textOn = tostring(text) 57 | self:refresh() 58 | end 59 | function ToggleBtn:setTextOff(text) 60 | self.textOff = tostring(text) 61 | self:refresh() 62 | end 63 | 64 | return ToggleBtn -------------------------------------------------------------------------------- /turtle/main.lua: -------------------------------------------------------------------------------- 1 | 2 | local tasks = global.tasks 3 | local list = global.list 4 | local miner = global.miner 5 | 6 | function openTab(task_2, task_3) 7 | --TODO: error handling has to be done by the file itself 8 | if not task_3 then 9 | shell.openTab("runtime/"..task_2) 10 | else 11 | shell.openTab("runtime/"..task_2, unpack(task_3)) 12 | end 13 | end 14 | function callMiner(task_2, task_3) 15 | if miner then 16 | if not task_3 then 17 | local func = "return function(miner,task_2) miner:"..task_2.."() end" 18 | loadstring(func)()(miner,task_2) 19 | --miner[task_2](miner) 20 | else 21 | -- debug.getinfo not working when using miner[functionName]() 22 | --miner[task_2](miner, unpack(task_3)) 23 | local func = "return function(miner,task_2,task_3) miner:"..task_2.."(unpack(task_3)) end" 24 | loadstring(func)()(miner,task_2,task_3) 25 | end 26 | end 27 | end 28 | function shellRun(task_2, task_3) 29 | --TODO: error handling has to be done by the file itself 30 | if not task_3 then 31 | shell.run("runtime/"..task_2) 32 | else 33 | shell.run("runtime/"..task_2, unpack(task_3)) 34 | end 35 | end 36 | print("waiting for tasks...") 37 | while true do 38 | while #tasks > 0 do 39 | local status,err = nil,nil 40 | task = table.remove(tasks, 1) 41 | if task[1] == "RUN" then 42 | --status,err = pcall(shellRun,task[2],task[3]) 43 | global.err = nil 44 | openTab(task[2],task[3]) 45 | elseif task[1] == "DO" then 46 | global.err = nil 47 | status,err = pcall(callMiner,task[2],task[3]) 48 | global.handleError(err,status) 49 | 50 | elseif task[1] == "UPDATE" then 51 | shell.run("update.lua") 52 | else 53 | print("something else") 54 | end 55 | end 56 | sleep(0.2) 57 | end -------------------------------------------------------------------------------- /gui/classChoiceSelector.lua: -------------------------------------------------------------------------------- 1 | local Button = require("classButton") 2 | local Window = require("classWindow") 3 | 4 | 5 | -- simple multiple choice selector 6 | 7 | local default = { 8 | colors = { 9 | background = colors.black, 10 | border = colors.gray 11 | }, 12 | width = 10, 13 | height = 4, 14 | } 15 | 16 | local ChoiceSelector = Window:new() 17 | 18 | function ChoiceSelector:new(x,y,width,height,choices) 19 | local o = o or Window:new(x,y,width or default.width ,height or default.height ) or {} 20 | setmetatable(o, self) 21 | self.__index = self 22 | 23 | o.backgroundColor = default.colors.background 24 | o.borderColor = default.colors.border 25 | o.choice = nil 26 | o.choices = {} 27 | o.longestChoice = 0 28 | 29 | o:initialize(choices) 30 | return o 31 | end 32 | 33 | function ChoiceSelector:initialize(choices) 34 | if choices and #choices > 0 then 35 | self:addChoices(choices) 36 | end 37 | end 38 | 39 | function ChoiceSelector:addChoice(text) 40 | table.insert(self.choices, text) 41 | if #text > self.longestChoice then 42 | self.longestChoice = #text 43 | end 44 | self["btn"..text] = Button:new(text,3,1+ (#self.choices * 2),self.width-6,1) 45 | self["btn"..text].click = function() self:selectChoice(text) end 46 | 47 | self["btn"..text].onResize = function() 48 | self["btn"..text]:setWidth(self.width-6) 49 | end 50 | 51 | self:addObject(self["btn"..text]) 52 | self:setSize(math.max(self.width, self.longestChoice + 6),4 + (#self.choices * 2)) 53 | end 54 | 55 | function ChoiceSelector:addChoices(choices) 56 | for i=1,#choices do 57 | self:addChoice(choices[i]) 58 | end 59 | end 60 | 61 | -- pseudo callback 62 | -- function ChoiceSelector.onChoiceSelected(choice) 63 | 64 | function ChoiceSelector:selectChoice(text) 65 | self.choice = text 66 | self:close() 67 | if self.onChoiceSelected then 68 | self.onChoiceSelected(self.choice) 69 | end 70 | end 71 | 72 | return ChoiceSelector -------------------------------------------------------------------------------- /turtle/testPerformance.lua: -------------------------------------------------------------------------------- 1 | sleepTime = 3 2 | moves = 5 3 | 4 | function redo(func) 5 | sleep(sleepTime) 6 | start = os.epoch("ingame") 7 | for i = 1, moves do 8 | func() 9 | end 10 | return os.epoch("ingame")-start 11 | end 12 | 13 | function minerBack() 14 | for i = 1, moves do 15 | global.miner:back() 16 | end 17 | end 18 | 19 | function back() 20 | for i = 1, moves do 21 | turtle.back() 22 | end 23 | end 24 | 25 | function test_general() 26 | diff_1 = redo(turtle.inspect) 27 | diff_2 = redo(turtle.detect) 28 | print("inspect vs detect", diff_1, diff_2) 29 | 30 | diff_3 = redo( function() 31 | turtle.inspect() 32 | turtle.forward() 33 | end) 34 | back() 35 | diff_4 = redo( function() 36 | turtle.detect() 37 | turtle.forward() 38 | end) 39 | back() 40 | sleep(sleepTime) 41 | diff_5 = redo( function() 42 | turtle.forward() 43 | end) 44 | back() 45 | sleep(sleepTime) 46 | diff_5_2 = redo(function() 47 | global.miner:inspect(true) 48 | global.miner:forward() 49 | end) 50 | print("movement",diff_3, diff_4, diff_5, diff_5_2) 51 | 52 | sleep(sleepTime) 53 | start = os.epoch() 54 | turtle.inspect() 55 | turtle.forward() 56 | diff_6 = os.epoch()-start 57 | sleep(sleepTime) 58 | start = os.epoch() 59 | turtle.detect() 60 | turtle.forward() 61 | diff_7 = os.epoch()-start 62 | sleep(sleepTime) 63 | start = os.epoch() 64 | turtle.forward() 65 | diff_8 = os.epoch()-start 66 | print("single",diff_6, diff_7, diff_8) 67 | sleep(sleepTime) 68 | back() 69 | back() 70 | end 71 | 72 | -- dig then move vs digMove 73 | diff_1 = redo( function() 74 | global.miner:inspect() 75 | global.miner:dig() 76 | global.miner:forward() 77 | end) 78 | back() 79 | global.miner:inspect() 80 | moves = 1000000 81 | diff_2 = redo( function() 82 | --print(os.epoch("ingame")) 83 | global.miner:inspect() 84 | --global.miner:digMove(true) 85 | end) 86 | --back() 87 | print("dig vs move", diff_1, diff_2) -------------------------------------------------------------------------------- /test/turtle/testPerformance.lua: -------------------------------------------------------------------------------- 1 | sleepTime = 3 2 | moves = 5 3 | 4 | function redo(func) 5 | sleep(sleepTime) 6 | start = os.epoch("ingame") 7 | for i = 1, moves do 8 | func() 9 | end 10 | return os.epoch("ingame")-start 11 | end 12 | 13 | function minerBack() 14 | for i = 1, moves do 15 | global.miner:back() 16 | end 17 | end 18 | 19 | function back() 20 | for i = 1, moves do 21 | turtle.back() 22 | end 23 | end 24 | 25 | function test_general() 26 | diff_1 = redo(turtle.inspect) 27 | diff_2 = redo(turtle.detect) 28 | print("inspect vs detect", diff_1, diff_2) 29 | 30 | diff_3 = redo( function() 31 | turtle.inspect() 32 | turtle.forward() 33 | end) 34 | back() 35 | diff_4 = redo( function() 36 | turtle.detect() 37 | turtle.forward() 38 | end) 39 | back() 40 | sleep(sleepTime) 41 | diff_5 = redo( function() 42 | turtle.forward() 43 | end) 44 | back() 45 | sleep(sleepTime) 46 | diff_5_2 = redo(function() 47 | global.miner:inspect(true) 48 | global.miner:forward() 49 | end) 50 | print("movement",diff_3, diff_4, diff_5, diff_5_2) 51 | 52 | sleep(sleepTime) 53 | start = os.epoch() 54 | turtle.inspect() 55 | turtle.forward() 56 | diff_6 = os.epoch()-start 57 | sleep(sleepTime) 58 | start = os.epoch() 59 | turtle.detect() 60 | turtle.forward() 61 | diff_7 = os.epoch()-start 62 | sleep(sleepTime) 63 | start = os.epoch() 64 | turtle.forward() 65 | diff_8 = os.epoch()-start 66 | print("single",diff_6, diff_7, diff_8) 67 | sleep(sleepTime) 68 | back() 69 | back() 70 | end 71 | 72 | -- dig then move vs digMove 73 | diff_1 = redo( function() 74 | global.miner:inspect() 75 | global.miner:dig() 76 | global.miner:forward() 77 | end) 78 | back() 79 | global.miner:inspect() 80 | moves = 1000000 81 | diff_2 = redo( function() 82 | --print(os.epoch("ingame")) 83 | global.miner:inspect() 84 | --global.miner:digMove(true) 85 | end) 86 | --back() 87 | print("dig vs move", diff_1, diff_2) -------------------------------------------------------------------------------- /old/pocket/initialize.lua: -------------------------------------------------------------------------------- 1 | 2 | --require("classNetworkNode") 3 | require("classBluenetNode") 4 | local Monitor = require("classMonitor") 5 | local HostDisplay = require("classHostDisplay") 6 | --require("classMap") 7 | require("classChunkyMap") 8 | require("classTaskGroup") 9 | 10 | local function initNode() 11 | global.node = NetworkNode:new("miner",true) 12 | end 13 | local function initStream() 14 | global.nodeStream = NetworkNode:new("miner_stream",true) 15 | end 16 | local function initUpdate() 17 | global.nodeUpdate = NetworkNode:new("update",true) 18 | end 19 | 20 | local function initPosition() 21 | local x,y,z = gps.locate() 22 | if x and y and z then 23 | x, y, z = math.floor(x), math.floor(y), math.floor(z) 24 | global.pos = vector.new(x,y,z) 25 | else 26 | print("gps not working") 27 | global.pos = vector.new(0,70,0) 28 | end 29 | print("position:",global.pos.x,global.pos.y,global.pos.z) 30 | end 31 | 32 | local function loadGroups(fileName) 33 | if not fileName then fileName = "runtime/taskGroups.txt" end 34 | local f = fs.open(fileName,"r") 35 | local groups = nil 36 | if f then 37 | groups = textutils.unserialize( f.readAll() ) 38 | f.close() 39 | else 40 | -- no problem if this file does not exist yet 41 | -- print("FILE DOES NOT EXIST", fileName) 42 | end 43 | if groups then 44 | for _,group in pairs(groups) do 45 | local taskGroup = TaskGroup:new(global.turtles,nil,group) 46 | global.taskGroups[taskGroup.id] = taskGroup 47 | end 48 | else 49 | global.taskGroups = {} 50 | end 51 | end 52 | 53 | -- quick boot 54 | parallel.waitForAll(initNode,initStream,initUpdate) 55 | 56 | initPosition() 57 | global.map = ChunkyMap:new(false) 58 | global.map:setMaxChunks(2048) --256 for operational use 59 | global.map:setLifeTime(-1) 60 | global.map:load() 61 | global.loadTurtles() 62 | global.loadStations() 63 | global.loadAlerts() 64 | loadGroups() 65 | 66 | --global.monitor = Monitor:new(term.current()) 67 | --global.display = HostDisplay:new(1,1,global.monitor:getWidth(),global.monitor:getHeight()) 68 | 69 | -------------------------------------------------------------------------------- /general/classSimpleVector.lua: -------------------------------------------------------------------------------- 1 | local SimpleVector = {} 2 | SimpleVector.__index = SimpleVector 3 | 4 | local function newVector( x, y, z ) 5 | return setmetatable( { x = x or 0, y = y or 0, z = z or 0 }, SimpleVector ) 6 | end 7 | 8 | function isvector( vTbl ) 9 | return getmetatable( vTbl ) == SimpleVector 10 | end 11 | 12 | function SimpleVector.__unm( vTbl ) 13 | return newVector( -vTbl.x, -vTbl.y, -vTbl.z ) 14 | end 15 | 16 | function SimpleVector.__add( a, b ) 17 | return newVector( a.x + b.x, a.y + b.y, a.z + b.z ) 18 | end 19 | 20 | function SimpleVector.__sub( a, b ) 21 | return newVector( a.x - b.x, a.y - b.y, a.z - b.z ) 22 | end 23 | 24 | function SimpleVector.__mul( a, b ) 25 | if type( a ) == "number" then 26 | return newVector( a * b.x, a * b.y, a * b.z ) 27 | elseif type( b ) == "number" then 28 | return newVector( a.x * b, a.y * b, a.z * b ) 29 | else 30 | return newVector( a.x * b.x, a.y * b.y, a.z * b.z ) 31 | end 32 | end 33 | 34 | function SimpleVector.__div( a, b ) 35 | return newVector( a.x / b, a.y / b, a.z /b ) 36 | end 37 | 38 | function SimpleVector.__eq( a, b ) 39 | return a.x == b.x and a.y == b.y and a.z == b.z 40 | end 41 | 42 | function SimpleVector:__tostring() 43 | return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")" 44 | end 45 | 46 | function SimpleVector:getId() 47 | if self._ID == nil then 48 | local x, y, z = self.x, self.y, self.z 49 | if x < 0 then 50 | x = -x 51 | y = y + 448 52 | end 53 | if z < 0 then 54 | z = -z 55 | y = y + 896 56 | end 57 | y = y + 64 -- default.minHeight 58 | -------------------------------------------------------- 59 | local temp = 0.5 * ( x + y ) * ( x + y + 1 ) + y 60 | self._ID = 0.5 * ( temp + z ) * ( temp + z + 1 ) + z 61 | -------------------------------------------------------- 62 | end 63 | 64 | return self._ID 65 | end 66 | 67 | function SimpleVector:toVector() 68 | return vector.new(self.x, self.y, self.z) 69 | end 70 | 71 | return setmetatable( SimpleVector, { __call = function( _, ... ) return newVector( ... ) end } ) -------------------------------------------------------------------------------- /test/inventory.lua: -------------------------------------------------------------------------------- 1 | 2 | --https://github.com/SquidDev-CC/artist/blob/vnext/src/artist/core/items.lua#L596 3 | 4 | 5 | package.path = package.path ..";../storage/?.lua" 6 | local ItemStorage = require("classItemStorage") 7 | local call = peripheral.call 8 | 9 | 10 | 11 | function findWiredModem() 12 | for _,modem in ipairs(peripheral.getNames()) do 13 | local modemType, subType = peripheral.getType(modem) 14 | print(modem, "modemType", modemType, subType) 15 | if modemType == "modem" and subType == "peripheral_hub" then 16 | return modem 17 | end 18 | end 19 | end 20 | 21 | local modem = findWiredModem() 22 | 23 | 24 | function getConnectedInventories(modem) 25 | local connected = call(modem, "getNamesRemote") 26 | local inventories = {} 27 | for _,name in ipairs(connected) do 28 | local mainType, subType = call(modem, "getTypeRemote", name) 29 | if subType == "inventory" then 30 | inventories[#inventories+1] = name 31 | print("Found inventory:", name) 32 | end 33 | end 34 | return inventories 35 | end 36 | 37 | local connected = getConnectedInventories(modem) 38 | 39 | function pushItems(fromInv, toInv, fromSlot, count, toSlot) 40 | 41 | 42 | local moved = call(fromInv, "pushItems", toInv, fromSlot, count, toSlot) 43 | print("moved", moved) 44 | end 45 | 46 | 47 | 48 | local storage = ItemStorage:new() 49 | storage:getInventories() 50 | storage:indexInventories() 51 | storage:printIndex() 52 | 53 | 54 | storage:extract("minecraft:stripped_spruce_wood", 65, "minecraft:chest_6") 55 | storage:input("minecraft:chest_6") 56 | storage:extract("minecraft:stripped_spruce_wood", 65, "minecraft:chest_6") 57 | 58 | 59 | local time = os.epoch("utc") 60 | pushItems("minecraft:hopper_0", "minecraft:chest_5", 1, 64, 1) 61 | print("Time taken:", os.epoch("utc") - time) 62 | pushItems("minecraft:hopper_0", "minecraft:chest_5", 2, 64, 4) 63 | print("Time taken:", os.epoch("utc") - time) 64 | pushItems("minecraft:hopper_0", "minecraft:chest_5", 3, 64, 6) 65 | print("Time taken:", os.epoch("utc") - time) -------------------------------------------------------------------------------- /old/pocket/startup.lua: -------------------------------------------------------------------------------- 1 | 2 | os.loadAPI("/runtime/bluenet.lua") 3 | shell.run("runtime/update.lua") 4 | 5 | -- add runtime as default environment 6 | package.path = package.path ..";../runtime/?.lua" 7 | --package.path = package.path .. ";../?.lua" .. ";../runtime/?.lua" 8 | --require("classMonitor") 9 | --require("../runtime/classMonitor") 10 | --require("runtime/classMonitor") 11 | 12 | if rednet then 13 | shell.run("runtime/killRednet.lua") 14 | return 15 | end 16 | 17 | os.loadAPI("/runtime/global.lua") 18 | os.loadAPI("/runtime/config.lua") 19 | 20 | shell.run("runtime/initialize.lua") 21 | 22 | shell.openTab("runtime/shellDisplay.lua") 23 | shell.openTab("runtime/display.lua") 24 | shell.openTab("runtime/main.lua") 25 | shell.openTab("runtime/receive.lua") 26 | shell.openTab("runtime/send.lua") 27 | --shell.openTab("runtime/send.lua") 28 | --shell.openTab("runtime/update.lua") 29 | 30 | --shell.run("runtime/testMonitor") 31 | 32 | 33 | 34 | -- TODO: 35 | -- check if other host ist online 36 | -- request host transfer ( or "teamviewer" mode ) 37 | -- if no host available, become host ( after asking user ) 38 | -- current host: stop receiving messages from turtles 39 | -- transfer all files/states ( config, turtles, stations, taskGroups, alerts etc. ) 40 | -- optionally: transfer all chunks from map 41 | -- shut down host 42 | -- reboot pocket as host 43 | 44 | -- basically as if rebooting the host but instead all files were transferred to pocket 45 | -- vice versa when changing back from pocket to host 46 | 47 | -- important: when transferring, turtles must be made aware of the new host 48 | -- reboot does the trick in theory but thats not very elegant 49 | -- "hostProtocol(hijack)" -> send: "NEW_HOST", newHostAddress 50 | -- either hijack the protocol forcefully or the current host gives its ok by sending out the new host id 51 | -- wait for turtles to confirm new host, to ensure all switched over before old host is not longer available 52 | -- maybe have a "grace period" where both hosts are online to ensure smooth transition 53 | -- -> mmhna only keep old host as dns around to redirect turtles to new host 54 | -- or maybe keep it online to enable switching back remotely from pocket to host 55 | -------------------------------------------------------------------------------- /test/lists.lua: -------------------------------------------------------------------------------- 1 | package.path = package.path ..";../?/?.lua" .. ";../general/?.lua" 2 | 3 | require("classList") 4 | --require("classListNew") 5 | 6 | 7 | -- local list = List:new() 8 | 9 | -- local function addTask(task) 10 | -- return list:addFirst(task) 11 | -- end 12 | local runs = 5 13 | 14 | -- local function testList() 15 | -- local sum = 0 16 | -- for j = 1, runs do 17 | -- local list = List:new() 18 | -- local start = os.epoch("local") 19 | -- for k = 1, 100000 do 20 | -- local n = list:addFirst({"preset"}) 21 | -- --list:remove(n) 22 | -- end 23 | 24 | -- local n = list:getLast() 25 | -- while n do 26 | -- local tmp = list:getPrev(n) 27 | -- list:remove(n) 28 | 29 | -- n = tmp 30 | -- end 31 | 32 | -- local t = os.epoch("local")-start 33 | -- print(t,"List") 34 | -- sum = sum + t 35 | -- sleep(0) 36 | -- end 37 | -- print("avg", sum/runs) 38 | -- end 39 | 40 | local function testListNew() 41 | local sum = 0 42 | for j = 1, runs do 43 | local list = List:new() 44 | local start = os.epoch("local") 45 | for k = 1, 100000 do 46 | local n = list:addFirst({"preset"}) 47 | --list:remove(n) 48 | end 49 | 50 | -- local n = list.last 51 | -- while n do 52 | -- --local tmp = n._prev 53 | -- list:remove(n) -- does not set ._prev to nil 54 | -- n = n._prev 55 | -- end 56 | local n = list.last 57 | while n do 58 | --local prv = n._prev 59 | -- if prv then 60 | -- prv._next = nil 61 | -- list.last = prv 62 | -- else 63 | -- list.first = nil 64 | -- list.last = nil 65 | -- end 66 | -- list.count = list.count - 1 67 | -- n = prv 68 | local prv = list:removeLast(n) 69 | n = prv 70 | -- local prv = n._prev 71 | -- list:remove(n) 72 | -- n = prv 73 | end 74 | 75 | -- local n = list.last 76 | -- for i = 1, list.count do 77 | -- -- stuff 78 | -- n = n._prev 79 | -- end 80 | -- list:clear() 81 | 82 | local t = os.epoch("local")-start 83 | print(t,"ListNew") 84 | sum = sum + t 85 | sleep(0) 86 | end 87 | print("avg", sum/runs) 88 | end 89 | 90 | -- prepend remove assert if count,clear 91 | --testList() -- 128 320 92 | testListNew() -- 118 212 247 222 135 93 | 94 | 95 | -- 58.4 -------------------------------------------------------------------------------- /gui/classBox.lua: -------------------------------------------------------------------------------- 1 | local defaultBackgroundColor = colors.gray 2 | 3 | local Box = {} 4 | 5 | function Box:new(x,y,width,height,color) 6 | local o = o or {} 7 | setmetatable(o,self) 8 | self.__index = self 9 | o.x = x or 0 10 | o.y = y or 0 11 | o.width = width or 0 12 | o.height = height or 0 13 | o.backgroundColor = color or defaultBackgroundColor 14 | o.borderColor = o.backgroundColor 15 | o.borderWidth = 2 16 | o:initialize() 17 | return o 18 | end 19 | 20 | function Box:initialize() 21 | self:calculateMid() 22 | end 23 | function Box:setX(x) 24 | self.x = x 25 | self:calculateMid() 26 | end 27 | function Box:setY(y) 28 | self.y = y 29 | self:calculateMid() 30 | end 31 | function Box:setPos(x,y) 32 | self:setX(x) 33 | self:setY(y) 34 | end 35 | function Box:calculateMid() 36 | self.midWidth = math.floor(self.width/2) 37 | self.midHeight = math.floor(self.height/2) 38 | self.midX = self.x + self.midWidth 39 | self.midY = self.y + self.midHeight 40 | end 41 | 42 | function Box:setBorderColor(color) 43 | if color == nil then 44 | color = self.backgroundColor 45 | end 46 | self.borderColor = color 47 | end 48 | 49 | function Box:setBackgroundColor(color) 50 | self.prvBackgroundColor = self.backgroundColor 51 | if color == nil then 52 | color = defaultBackgroundColor 53 | end 54 | self.backgroundColor = color 55 | end 56 | function Box:getBackgroundColor() 57 | --TODO: check if border is clicked 58 | return self.backgroundColor 59 | end 60 | 61 | function Box:restoreBackgroundColor() 62 | local color = self.prvBackgroundColor 63 | if not color then 64 | color = defaultBackgroundColor 65 | end 66 | self.backgroundColor = color 67 | end 68 | 69 | function Box:setWidth(width) 70 | self.width = width 71 | end 72 | 73 | function Box:setHeight(height) 74 | self.height = height 75 | end 76 | 77 | function Box:redraw() 78 | if self.parent and self.visible then 79 | self.parent:drawFilledBox(self.x,self.y,self.width,self.height, self.backgroundColor) 80 | if self.borderColor ~= self.backgroundColor then 81 | self.parent:drawBox(self.x, self.y, self.width, self.height, self.borderColor, self.borderWidth, self.backgroundColor) 82 | end 83 | end 84 | end 85 | 86 | return Box -------------------------------------------------------------------------------- /general/classHeap.lua: -------------------------------------------------------------------------------- 1 | 2 | local Heap = {} 3 | Heap.__index = Heap 4 | 5 | local function findLowest( a, b ) 6 | return a < b 7 | end 8 | 9 | local function newHeap( template, compare ) 10 | return setmetatable( { 11 | Data = {}, 12 | Compare = compare or findLowest, 13 | Size = 0 14 | }, template ) 15 | end 16 | 17 | local function sortUp( heap, index ) 18 | if index <= 1 then return end 19 | local pIndex = index % 2 == 0 and index / 2 or ( index - 1 ) / 2 20 | 21 | if not heap.Compare( heap.Data[pIndex], heap.Data[index] ) then 22 | heap.Data[pIndex], heap.Data[index] = heap.Data[index], heap.Data[pIndex] 23 | sortUp( heap, pIndex ) 24 | end 25 | end 26 | 27 | local function sortDown( heap, index ) 28 | local leftIndex, rightIndex, minIndex 29 | leftIndex = index * 2 30 | rightIndex = leftIndex + 1 31 | if rightIndex > heap.Size then 32 | if leftIndex > heap.Size then return 33 | else minIndex = leftIndex end 34 | else 35 | if heap.Compare( heap.Data[leftIndex], heap.Data[rightIndex] ) then minIndex = leftIndex 36 | else minIndex = rightIndex end 37 | end 38 | 39 | if not heap.Compare( heap.Data[index], heap.Data[minIndex] ) then 40 | heap.Data[index], heap.Data[minIndex] = heap.Data[minIndex], heap.Data[index] 41 | sortDown( heap, minIndex ) 42 | end 43 | end 44 | 45 | function Heap:Empty() 46 | return self.Size == 0 47 | end 48 | 49 | function Heap:Clear() 50 | self.Data, self.Size, self.Compare = {}, 0, self.Compare or findLowest 51 | return self 52 | end 53 | 54 | function Heap:Push( item ) 55 | if item then 56 | self.Size = self.Size + 1 57 | self.Data[self.Size] = item 58 | sortUp( self, self.Size ) 59 | end 60 | return self 61 | end 62 | 63 | function Heap:Pop() 64 | local root 65 | if self.Size > 0 then 66 | root = self.Data[1] 67 | self.Data[1] = self.Data[self.Size] 68 | self.Data[self.Size] = nil 69 | self.Size = self.Size - 1 70 | if self.Size > 1 then 71 | sortDown( self, 1 ) 72 | end 73 | end 74 | return root 75 | end 76 | 77 | return setmetatable( Heap, { __call = function( self, ... ) return newHeap( self, ... ) end } ) -------------------------------------------------------------------------------- /test/autoplaceturtles.lua: -------------------------------------------------------------------------------- 1 | 2 | local g = global 3 | 4 | 5 | -- Function to place a turtle, refuel it, and make it download and run a file 6 | local function deployTurtle(pastebinCode) 7 | -- Check if there's a turtle in the inventory 8 | local slot = nil 9 | for i = 1, 16 do 10 | local item = turtle.getItemDetail(i) 11 | if item and item.name == "computercraft:turtle_advanced" then 12 | slot = i 13 | break 14 | end 15 | end 16 | 17 | if not slot then 18 | print("No turtle found in inventory!") 19 | return 20 | end 21 | 22 | -- Select the slot with the turtle and place it 23 | turtle.select(slot) 24 | if not turtle.place() then 25 | print("Failed to place the turtle!") 26 | return 27 | end 28 | 29 | print("Turtle placed successfully!") 30 | 31 | -- Refuel the placed turtle 32 | local fuelSlot = nil 33 | for i = 1, 16 do 34 | local item = turtle.getItemDetail(i) 35 | if item and item.name == "minecraft:coal_block" then 36 | fuelSlot = i 37 | break 38 | end 39 | end 40 | 41 | if not fuelSlot then 42 | print("No fuel found in inventory!") 43 | return 44 | end 45 | 46 | -- Drop fuel into the placed turtle 47 | turtle.select(fuelSlot) 48 | if not turtle.drop() then 49 | print("Failed to drop fuel into the turtle!") 50 | return 51 | end 52 | 53 | print("Fuel provided to the turtle!") 54 | 55 | -- Send a command to the placed turtle to download and run the file 56 | local modem = peripheral.find("modem") 57 | if not modem then 58 | print("No modem found! Ensure a wireless modem is attached.") 59 | return 60 | end 61 | 62 | local channel = 12000 -- Communication channel 63 | modem.open(channel) 64 | 65 | -- Send the command to the placed turtle 66 | local command = string.format( 67 | "pastebin get %s startup && startup", 68 | pastebinCode 69 | ) 70 | modem.transmit(channel, channel, command) 71 | 72 | print("Command sent to the turtle to download and run the file!") 73 | end 74 | 75 | -- Example usage 76 | local pastebinCode = "your_pastebin_code_here" -- Replace with your Pastebin code 77 | deployTurtle(pastebinCode) -------------------------------------------------------------------------------- /host/initialize.lua: -------------------------------------------------------------------------------- 1 | 2 | --require("classNetworkNode") 3 | require("classBluenetNode") 4 | local Monitor = require("classMonitor") 5 | local HostDisplay = require("classHostDisplay") 6 | --require("classMap") 7 | require("classChunkyMap") 8 | require("classTaskGroup") 9 | local RemoteStorage = require("classRemoteStorage") 10 | 11 | 12 | local function initNode() 13 | global.node = NetworkNode:new("miner",true) 14 | end 15 | local function initStream() 16 | global.nodeStream = NetworkNode:new("miner_stream",true) 17 | end 18 | local function initUpdate() 19 | global.nodeUpdate = NetworkNode:new("update",true) 20 | end 21 | local function initStorage() 22 | global.storage = RemoteStorage:new() 23 | end 24 | 25 | local function initPosition() 26 | local x,y,z = gps.locate() 27 | if x and y and z then 28 | x, y, z = math.floor(x), math.floor(y), math.floor(z) 29 | global.pos = vector.new(x,y,z) 30 | else 31 | print("gps not working") 32 | global.pos = vector.new(0,70,0) -- this is bad for turtles especially 33 | end 34 | print("position:",global.pos.x,global.pos.y,global.pos.z) 35 | end 36 | 37 | local function loadGroups(fileName) 38 | if not fileName then fileName = "runtime/taskGroups.txt" end 39 | local f = fs.open(fileName,"r") 40 | local groups = nil 41 | if f then 42 | groups = textutils.unserialize( f.readAll() ) 43 | f.close() 44 | else 45 | -- no problem if this file does not exist yet 46 | -- print("FILE DOES NOT EXIST", fileName) 47 | end 48 | if groups then 49 | for _,group in pairs(groups) do 50 | local taskGroup = TaskGroup:new(global.turtles,nil,group) 51 | global.taskGroups[taskGroup.id] = taskGroup 52 | end 53 | else 54 | global.taskGroups = {} 55 | end 56 | end 57 | 58 | -- quick boot 59 | parallel.waitForAll(initNode,initStream,initUpdate) 60 | 61 | 62 | 63 | initPosition() 64 | global.map = ChunkyMap:new(false) 65 | global.map:setMaxChunks(2048) --256 for operational use 66 | global.map:setLifeTime(-1) 67 | global.map:load() 68 | global.loadTurtles() 69 | global.loadStations() 70 | loadGroups() 71 | global.loadAlerts() 72 | 73 | initStorage() -- init after loading the rest but before display 74 | 75 | if not pocket then -- pocket uses shellDisplay 76 | global.monitor = Monitor:new() 77 | global.display = HostDisplay:new(1,1,global.monitor:getWidth(),global.monitor:getHeight()) 78 | end 79 | 80 | 81 | -------------------------------------------------------------------------------- /old/classNetworkHost.lua: -------------------------------------------------------------------------------- 1 | require("classList") 2 | require("classNetworkClient") 3 | 4 | 5 | NetworkHost = {} 6 | 7 | function NetworkHost:new(protocol) 8 | local o = o or NetworkClient:new(protocol) {} 9 | setmetatable(o,self) 10 | self.__index = self 11 | print("----INITIALIZING----") 12 | 13 | self.isHost = true 14 | self.worklist = List:new() 15 | self.currentTask = 0 --UUID generator alternativ 16 | 17 | self:initialize() 18 | print("--------------------") 19 | return self 20 | end 21 | 22 | function NetworkHost:initialize() 23 | --super initialization NetworkNode already done 24 | self.host = self.id 25 | 26 | rednet.unhost(self.protocol) 27 | self:hostProtocol() 28 | end 29 | 30 | function NetworkHost:hostProtocol() 31 | rednet.host(self.protocol, "host") 32 | end 33 | 34 | function NetworkHost:registerNode(sender, msg, senderProtocol) 35 | 36 | end 37 | 38 | -- task = { computerId, taskName, taskId, startTime, endTime } 39 | function NetworkNode:addTask(computerId, taskName) 40 | local task = { computerId = computerId, 41 | taskName = taskName, 42 | taskId = self.currentTask, 43 | startTime = os.clock(), 44 | endTime = 0 } 45 | self.currentTask = self.currentTask + 1 46 | self.worklist:add(task) 47 | --self:lookup(self.protocol, taskName) 48 | local msg = self:broadcast({"RUN", taskName},true) 49 | print("added task", task.taskName, task.taskId) 50 | return msg, task 51 | end 52 | 53 | function NetworkNode:removeTask(taskId) 54 | --remove task according to taskId because Lua does not reference variables well 55 | local task = self:findTask(taskId) 56 | if task then 57 | task = self.worklist:remove(task) 58 | task = nil 59 | end 60 | return task 61 | end 62 | 63 | function NetworkNode:findTask(taskId) 64 | local task = nil 65 | local current = self.worklist:getFirst() 66 | while current do 67 | if current.taskId == taskId then 68 | task = current 69 | break 70 | end 71 | current = self.worklist.getNext(current) 72 | end 73 | --print("found task:", task.taskId, task.taskName) 74 | return task 75 | end 76 | 77 | function NetworkNode:lookupHost() 78 | self.host = self.id 79 | return self.host 80 | end 81 | 82 | function NetworkHost:lookup() 83 | self.host = self.id 84 | self.computers = {rednet.lookup(self.protocol)} 85 | end -------------------------------------------------------------------------------- /test/serialize_consistency.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | package.path = package.path ..";../?/?.lua" .. ";../general/?.lua" 4 | local utilsSerialize = require("utilsSerialize") 5 | local binarize = utilsSerialize.binarize 6 | local serialize = utilsSerialize.serialize 7 | local unbinarize = utilsSerialize.unbinarize 8 | local unserialize = utilsSerialize.unserialize 9 | 10 | 11 | local path = "test/map/chunks" 12 | local type = type 13 | 14 | local function compareChunks(chunkA, chunkB) 15 | for k, v in pairs(chunkA) do 16 | if type(k) == "number" then 17 | if chunkB[k] ~= v then 18 | print("MISSING KEY:", k, "VALUE A:", v, "VALUE B:", chunkB[k]) 19 | return false 20 | end 21 | end 22 | end 23 | for k, v in pairs(chunkB) do 24 | if type(k) == "number" then 25 | if chunkA[k] ~= v then 26 | print("MISSING KEY:", k, "VALUE A:", chunkA[k], "VALUE B:", v) 27 | return false 28 | end 29 | end 30 | end 31 | return true 32 | end 33 | 34 | function compare_results() 35 | -- for each file in path compare results of serialize/unserialize and binarize/unbinarize 36 | local files = fs.list(path) 37 | local binaryBytes, serializedBytes = 0, 0 38 | for _, file in ipairs(files) do 39 | print("Comparing file:", file) 40 | local f = fs.open(path .. "/" .. file, "r") 41 | local serializedChunk = f.readAll() 42 | f.close() 43 | 44 | local unserializedChunk = unserialize(serializedChunk) 45 | local binaryChunk = binarize(unserializedChunk) 46 | local unbinarizedChunk = unbinarize(binaryChunk) 47 | 48 | binaryBytes = binaryBytes + #binaryChunk 49 | serializedBytes = serializedBytes + #serializedChunk 50 | 51 | if not compareChunks(unserializedChunk, unbinarizedChunk or {}) then 52 | print("Mismatch in file: " .. file) 53 | return false 54 | end 55 | os.pullEvent(os.queueEvent("yield")) 56 | end 57 | print("Total binary bytes:", binaryBytes) 58 | print("Total serialized bytes:", serializedBytes) 59 | print("Binary is " .. (serializedBytes / binaryBytes) .. " times smaller than serialized.") 60 | return true 61 | end 62 | 63 | print(compare_results()) -------------------------------------------------------------------------------- /gui/classGPU.lua: -------------------------------------------------------------------------------- 1 | local GPU = 2 | { 3 | prvBackgroundColor, 4 | prvTextColor, 5 | backgroundColor = colors.black, 6 | textColor = colors.white, 7 | old, 8 | monitor, 9 | } 10 | 11 | function GPU:new(o,monitor) 12 | o = o or {} 13 | setmetatable(o, self) 14 | self.__index = self 15 | self.monitor = monitor or nil 16 | if self.monitor == nil then 17 | self:findMonitor() 18 | end 19 | return o 20 | end 21 | 22 | function GPU:findMonitor() 23 | local monitors = peripheral.find("monitor") 24 | if monitors[1] == nil then 25 | error("no monitor found",0) 26 | end 27 | self.monitor = monitors[1] 28 | end 29 | function GPU:setBackgroundColor(backgroundColor) 30 | self.prvBackgroundColor = self.monitor.getBackgroundColor() 31 | if backgroundColor == nil then 32 | self.backgroundColor = colors.white 33 | else 34 | self.backgroundColor = backgroundColor 35 | end 36 | self.monitor.setBackgroundColor(self.backgroundColor) 37 | end 38 | 39 | function GPU:setTextColor(textColor) 40 | self.prvTextColor = self.monitor.getTextColor() 41 | if textColor == nil then 42 | self.textColor = colors.white 43 | else 44 | self.textColor = textColor 45 | end 46 | self.monitor.setTextColor(self.textColor) 47 | end 48 | function GPU:setColor(backgroundColor, textColor) 49 | self:setBackgroundColor(backgroundColor) 50 | self:setTextColor(textColor) 51 | end 52 | 53 | function GPU:restoreColor() 54 | if self.prvBackgroundColor ~= nil then 55 | self.monitor.setBackgroundColor(self.prvBackgroundColor) 56 | else 57 | self.monitor.setBackgroundColor(colors.black) 58 | end 59 | if self.prvTextColor ~= nil then 60 | self.monitor.setTextColor(self.prvTextColor) 61 | else 62 | self.monitor.setTextColor(colors.white) 63 | end 64 | end 65 | 66 | function GPU:drawBox(x,y,width,height,color) 67 | self:setBackgroundColor(color) 68 | --local width = endX - x + 1 69 | --local height = endY - y + 1 70 | self.old = term.redirect(self.monitor) 71 | 72 | self.monitor.setCursorPos(x,y) 73 | 74 | for c=1,height do 75 | for ln = 1,width do 76 | self.monitor.write(" ") 77 | end 78 | self.monitor.setCursorPos(x, y+c) 79 | end 80 | 81 | term.redirect(self.old) 82 | self:restoreColor() 83 | 84 | end 85 | 86 | return GPU -------------------------------------------------------------------------------- /test/bluenet_performance_receive.lua: -------------------------------------------------------------------------------- 1 | 2 | --package.path = package.path ..";../runtime/?.lua" 3 | 4 | os.loadAPI("bluenet.lua") 5 | require("classBluenetNode") 6 | 7 | 8 | local data = {"TEST"} 9 | local node = NetworkNode:new("test", false) 10 | 11 | 12 | node.onRequestStreamData = function(previous) 13 | return previous.data 14 | end 15 | 16 | node.onStreamMessage = function(msg, previous) 17 | node:stream() 18 | end 19 | 20 | node.onRequestAnswer = function(forMsg) 21 | node:answer(forMsg,forMsg.data) 22 | end 23 | 24 | local ct = 0 25 | local prvct = 0 26 | while true do 27 | 28 | node:listen() 29 | -- if msg.data[1] - prvct > 1 then 30 | -- print("hmm", msg.data[1], msg.id, "prvct", prvct) 31 | -- end 32 | -- prvct = msg.data[1] 33 | --node:checkWaitList() 34 | -- local msg = node:listen() 35 | -- if msg then 36 | -- node:answer(msg,msg.data) 37 | -- end 38 | end 39 | 40 | 41 | ---################# RAW 42 | 43 | local ID, TIME, SENDER, RECIPIENT, PROTOCOL, TYPE, DATA, ANSWER, WAIT, WAITTIME = 1,2,3,4,5,6,7,8,9,10 44 | local DISTANCE = 11 45 | 46 | local computerId = os.getComputerID() 47 | local protocol = "test" 48 | local eventFilter = "modem_message" 49 | local pullEventRaw = os.pullEventRaw 50 | -- print(bluenet.isOpen("top", 0)) 51 | -- print(bluenet.isOpen("top", 10)) 52 | -- print(bluenet.isOpen("top", 11)) 53 | 54 | local peripheralCall = peripheral.call 55 | -- channels already opened by node 56 | 57 | 58 | while true do 59 | local event, side, channel, sender, msg, distance = pullEventRaw(eventFilter) 60 | --if event == "modem_message" then print(os.clock(),event, modem, channel, sender) end 61 | --print(event, modem, sender, channel, msg.sender, msg.recipient, msg.data[1], distance) 62 | if event == "modem_message" 63 | --type(msg) == "table" 64 | -- and ( type(msg[4]) == "number" and msg[4] 65 | -- and ( msg[4] == computerId ) 66 | -- and ( protocol == nil or protocol == msg[5] ) 67 | then 68 | --msg.distance = distance 69 | peripheralCall(side, "transmit", sender, channel, msg) 70 | --native.call(side,"transmit",sender,channel,msg) 71 | 72 | --return msg 73 | 74 | elseif event == "timer" then 75 | --print(os.clock(),event, modem, channel, sender, timer) 76 | if modem == timer then -- must be equal! >= geht nicht 77 | --print("returning nil") 78 | return nil 79 | end 80 | elseif event == "terminate" then 81 | error("Terminated",0) 82 | end 83 | 84 | end 85 | 86 | -------------------------------------------------------------------------------- /host/startup.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- COPY REQUIRED FILES 4 | local folders = { 5 | "general", 6 | "gui", 7 | "host", 8 | "storage", 9 | } 10 | if pocket then 11 | table.insert(folders, "pocket") 12 | end 13 | 14 | local reboot = false 15 | 16 | local function copyFile(fileName, targetFileName) 17 | local modified = fs.attributes(fileName).modified 18 | if fs.exists(targetFileName) then 19 | local modifiedTarget = fs.attributes(targetFileName).modified 20 | if modified > modifiedTarget then 21 | fs.delete(targetFileName) 22 | fs.copy(fileName, targetFileName) 23 | reboot = true 24 | end 25 | else 26 | fs.copy(fileName, targetFileName) 27 | reboot = true 28 | end 29 | end 30 | 31 | local function copyFolder(folderName, targetFolder) 32 | print("copying", folderName, targetFolder) 33 | if not fs.isDir(targetFolder) then 34 | print("no such folder", folderName) 35 | end 36 | if fs.isDir(folderName) then 37 | for _, fileName in ipairs(fs.list('/' .. folderName)) do 38 | copyFile(folderName.."/"..fileName, targetFolder.."/"..fileName) 39 | end 40 | else 41 | print("no such folder", folderName) 42 | end 43 | end 44 | 45 | local function copyFiles() 46 | for _,folderName in ipairs(folders) do 47 | copyFolder(folderName, "runtime") 48 | end 49 | copyFile("runtime/startup.lua", "startup.lua") 50 | if reboot then 51 | os.reboot() 52 | end 53 | end 54 | -- END OF COPY 55 | 56 | copyFiles() 57 | 58 | -- add runtime as default environment 59 | package.path = package.path ..";../runtime/?.lua" 60 | --package.path = package.path .. ";../?.lua" .. ";../runtime/?.lua" 61 | --require("classMonitor") 62 | --require("../runtime/classMonitor") 63 | --require("runtime/classMonitor") 64 | 65 | if rednet then 66 | shell.run("runtime/killRednet.lua") 67 | return 68 | end 69 | 70 | os.loadAPI("/runtime/global.lua") 71 | os.loadAPI("/runtime/config.lua") 72 | os.loadAPI("/runtime/bluenet.lua") 73 | 74 | shell.run("runtime/initialize.lua") 75 | 76 | local tabGui 77 | if pocket then 78 | tabGui = shell.openTab("runtime/shellDisplay.lua") 79 | multishell.setTitle(tabGui, "GUI") 80 | end 81 | 82 | shell.openTab("runtime/display.lua") 83 | 84 | shell.openTab("runtime/main.lua") 85 | shell.openTab("runtime/receive.lua") 86 | shell.openTab("runtime/send.lua") 87 | 88 | -- can only be done once receiving is running 89 | local transferOk = dofile("runtime/hostTransfer.lua") 90 | if pocket and transferOk and tabGui then 91 | shell.switchTab(tabGui) 92 | end -------------------------------------------------------------------------------- /startup.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- COPY REQUIRED FILES 4 | local folders = { 5 | "general", 6 | "gui", 7 | "host", 8 | } 9 | if pocket then 10 | table.insert(folders, "pocket") 11 | end 12 | 13 | local reboot = false 14 | 15 | local function copyFile(fileName, targetFileName) 16 | local modified = fs.attributes(fileName).modified 17 | if fs.exists(targetFileName) then 18 | local modifiedTarget = fs.attributes(targetFileName).modified 19 | if modified > modifiedTarget then 20 | fs.delete(targetFileName) 21 | fs.copy(fileName, targetFileName) 22 | reboot = true 23 | end 24 | else 25 | fs.copy(fileName, targetFileName) 26 | reboot = true 27 | end 28 | end 29 | 30 | local function copyFolder(folderName, targetFolder) 31 | print("copying", folderName, targetFolder) 32 | if not fs.isDir(targetFolder) then 33 | print("no such folder", folderName) 34 | end 35 | if fs.isDir(folderName) then 36 | for _, fileName in ipairs(fs.list('/' .. folderName)) do 37 | copyFile(folderName.."/"..fileName, targetFolder.."/"..fileName) 38 | end 39 | else 40 | print("no such folder", folderName) 41 | end 42 | end 43 | 44 | local function copyFiles() 45 | for _,folderName in ipairs(folders) do 46 | copyFolder(folderName, "runtime") 47 | end 48 | copyFile("runtime/startup.lua", "startup.lua") 49 | if reboot then 50 | os.reboot() 51 | end 52 | end 53 | -- END OF COPY 54 | 55 | copyFiles() 56 | 57 | -- add runtime as default environment 58 | package.path = package.path ..";../runtime/?.lua" 59 | --package.path = package.path .. ";../?.lua" .. ";../runtime/?.lua" 60 | --require("classMonitor") 61 | --require("../runtime/classMonitor") 62 | --require("runtime/classMonitor") 63 | 64 | if rednet then 65 | shell.run("runtime/killRednet.lua") 66 | return 67 | end 68 | 69 | os.loadAPI("/runtime/global.lua") 70 | os.loadAPI("/runtime/config.lua") 71 | os.loadAPI("/runtime/bluenet.lua") 72 | 73 | shell.run("runtime/initialize.lua") 74 | 75 | local tabGui 76 | if pocket then 77 | tabGui = shell.openTab("runtime/shellDisplay.lua") 78 | multishell.setTitle(tabGui, "GUI") 79 | end 80 | 81 | shell.openTab("runtime/display.lua") 82 | 83 | shell.openTab("runtime/main.lua") 84 | shell.openTab("runtime/receive.lua") 85 | shell.openTab("runtime/send.lua") 86 | 87 | 88 | --shell.run("runtime/testMonitor") 89 | 90 | -- can only be done once receiving is running 91 | -- make its own file: 92 | -- shell.run("runtime/hostTransfer.lua") 93 | local transferOk = dofile("runtime/hostTransfer.lua") 94 | if pocket and transferOk and tabGui then 95 | shell.switchTab(tabGui) 96 | end -------------------------------------------------------------------------------- /test/classes.lua: -------------------------------------------------------------------------------- 1 | local CheckPointer = {} 2 | CheckPointer.__index = CheckPointer 3 | 4 | 5 | -- Standard method call (via metatable) 6 | function CheckPointer:new(o) 7 | o = o or {} 8 | setmetatable(o, self) -- Uses __index for function lookup 9 | return o 10 | end 11 | 12 | -- Optimized method call (direct assignment) 13 | function CheckPointer:newOptimized(o) 14 | o = o or {} 15 | setmetatable(o, self) 16 | --o.exampleMethod = self.exampleMethod -- Direct reference 17 | -- **Automate function caching: Copy all methods from prototype to object** 18 | for k, v in pairs(self) do 19 | if type(v) == "function" then 20 | o[k] = v -- Directly assign method to object 21 | end 22 | end 23 | 24 | return o 25 | end 26 | 27 | -- Example method 28 | function CheckPointer.exampleMethod(x) 29 | return x * 2 30 | end 31 | local exampleMethod = CheckPointer.exampleMethod 32 | 33 | -- Local definition 34 | local LocalCheckPointer = {} 35 | LocalCheckPointer.__index = LocalCheckPointer 36 | 37 | function LocalCheckPointer:exampleMethod(x) 38 | return x * 2 39 | end 40 | 41 | function LocalCheckPointer:new() 42 | local o = {} 43 | setmetatable(o, self) 44 | --o.exampleMethod = self.exampleMethod 45 | return o 46 | end 47 | 48 | -- Create objects 49 | local obj1 = CheckPointer:new() -- Uses __index lookup 50 | local obj2 = CheckPointer:newOptimized() -- Direct function reference 51 | local obj3 = LocalCheckPointer:new() 52 | 53 | -- Benchmarking 54 | local iterations = 10^7 -- 10 million iterations 55 | local start, stop 56 | 57 | -- Test standard method call 58 | start = os.epoch("local") 59 | for i = 1, iterations do 60 | obj1.exampleMethod(i) 61 | end 62 | stop = os.epoch("local") 63 | print("Standard method call time:", stop - start) 64 | 65 | -- Test optimized method call 66 | start = os.epoch("local") 67 | for i = 1, iterations do 68 | obj2.exampleMethod(i) -- No __index lookup 69 | end 70 | stop = os.epoch("local") 71 | print("Optimized method call time:", stop - start) 72 | 73 | -- Test standard method call 74 | start = os.epoch("local") 75 | for i = 1, iterations do 76 | obj3:exampleMethod(i) 77 | end 78 | stop = os.epoch("local") 79 | print("Local object call time:", stop - start) 80 | 81 | -- Test standard method call 82 | start = os.epoch("local") 83 | for i = 1, iterations do 84 | exampleMethod(i) 85 | end 86 | stop = os.epoch("local") 87 | print("Local method call time:", stop - start) 88 | 89 | -- standard: 993 90 | -- local class: 960 91 | -- optimized: 845 92 | 93 | -------------------------------------------------------------------------------- /host/send.lua: -------------------------------------------------------------------------------- 1 | 2 | local global = global 3 | 4 | local nodeStream = global.nodeStream 5 | local turtles = global.turtles 6 | local osEpoch = os.epoch 7 | 8 | nodeStream.onRequestStreamData = function(previous) 9 | 10 | --local start = os.epoch("local") 11 | 12 | local turtle = turtles[previous.sender] 13 | -- append the entries 14 | local mapLog = turtle.mapLog 15 | local mapBuffer = turtle.mapBuffer 16 | if #mapLog > 0 then 17 | local bufCount = #mapBuffer 18 | for i = 1, #mapLog do 19 | mapBuffer[bufCount+i] = mapLog[i] 20 | end 21 | turtle.mapLog = {} 22 | 23 | end 24 | 25 | -- local entry = table.remove(turtle.mapLog) 26 | -- while entry do 27 | -- table.insert(turtle.mapBuffer, entry) 28 | -- entry = table.remove(turtle.mapLog) 29 | -- end 30 | -- if global.printSend then 31 | -- print(osEpoch("local"), "sending map update", previous.sender, #mapBuffer) 32 | -- end 33 | if #mapBuffer > 0 and turtle.state.online then 34 | 35 | if global.printSend then 36 | print(osEpoch("local"), "sending map update", id, #mapBuffer) 37 | end 38 | return {"MAP_UPDATE",mapBuffer} 39 | --print("id", id, "time", timeSend .. " / " .. os.epoch("local")-start, "count", #data.mapBuffer) 40 | end 41 | 42 | return nil 43 | end 44 | 45 | 46 | while global.running do 47 | -- PROBLEM: node:send probably yields and lets other processes work 48 | -- processes (probably of turtles) should wait until send is done 49 | -- problem lies on the receiving end of turtles or size of the payload 50 | -- to avoid high payloads being sent unnecessarily -> only send to online turtles 51 | -- offline turtle buffer gets filled but only sent if turtle comes back 52 | 53 | -- mapBuffer is not cleared if sending takes too long 54 | -- yield while sending (current implementation) or checkValid not with 55 | -- current time, rather compare originalMsg with answerMsg 56 | 57 | --print(os.epoch("local"),"sending") 58 | 59 | local startTime = osEpoch("local") 60 | nodeStream:stream() 61 | --sendMapLog() 62 | if global.printSendTime then 63 | print(osEpoch("local")-startTime,"done", "events", global.eventCount, "msgs", global.messageCount, "timers", global.timerCount) 64 | global.eventCount = 0 65 | global.messageCount = 0 66 | global.timerCount = 0 67 | end 68 | local delay = (osEpoch("local")-startTime) / 1000 69 | if delay < global.minMessageDelay then delay = global.minMessageDelay 70 | elseif delay > 1 then delay = 1 end 71 | --else delay = delay * 2 end 72 | --print("delay", delay) 73 | -- if running into performance problems again -> set sleep time dynamically 74 | -- based on duration of sendMapLog 75 | --sleep(delay) --0.2 76 | sleep(delay) 77 | --os.pullEvent(os.queueEvent("yield")) 78 | 79 | end -------------------------------------------------------------------------------- /mon.lua: -------------------------------------------------------------------------------- 1 | function printGlobals() 2 | count = 0 3 | for _,entry in pairs(global.map.chunks) do 4 | count = count + 1 5 | end 6 | print("map chunks ", count) 7 | print("map.log ", #global.map.log) 8 | print("global.updates ", #global.updates) 9 | end 10 | 11 | function printTurtles() 12 | for id,turtle in pairs(global.turtles) do 13 | print("turtle.state.mapLog", id, #turtle.state.mapLog) 14 | print("turtle.maplog ", id, #turtle.mapLog) 15 | print("turtle.mapBuffer ", id, #turtle.mapBuffer) 16 | end 17 | end 18 | 19 | function printEvents() 20 | print("stream.events ", global.nodeStream.events.count) 21 | print("stream.messages ", global.nodeStream.messages.count) 22 | print("stream.waitlist ", global.nodeStream.waitlist.count) 23 | print("stream.streamlist", global.nodeStream.streamlist.count) 24 | 25 | print("update.events ", global.nodeUpdate.events.count) 26 | print("update.messages ", global.nodeUpdate.messages.count) 27 | print("update.waitlist ", global.nodeUpdate.waitlist.count) 28 | 29 | print("node.events ", global.node.events.count) 30 | print("node.messages ", global.node.messages.count) 31 | print("node.waitlist ", global.node.waitlist.count) 32 | print("monitor.events ", global.monitor.events.count) 33 | end 34 | 35 | function createDeepTable() 36 | local updates = {} 37 | local mapLogs = {} 38 | local ct = 0 39 | for i=1,2000 do 40 | mapLogs[i] = {} 41 | for k = 1,80 do 42 | table.insert(mapLogs[i], { x=200, y=200, z=200, data = "asdfkjasdflklaksjdflksadjflaskdfj"..k}) 43 | ct = ct +1 44 | end 45 | end 46 | print("created mapLogs", ct) 47 | 48 | return mapLogs 49 | end 50 | 51 | function createFlatTable(mapLogs) 52 | local mapLogReturn = {} 53 | for _,mapLog in ipairs(mapLogs) do 54 | for _,entry in ipairs(mapLog) do 55 | table.insert(mapLogReturn,entry) 56 | end 57 | end 58 | return mapLogReturn 59 | end 60 | 61 | function emptyDeepTable(mapLogs) 62 | local start = os.epoch("local") 63 | for _,mapLog in ipairs(mapLogs) do 64 | for _,entry in ipairs(mapLog) do 65 | global.map:setData(entry.x,entry.y,entry.z,entry.data) 66 | end 67 | end 68 | print("deep", os.epoch("local")-start) 69 | end 70 | 71 | function emptyFlatTable(mapLog) 72 | local start = os.epoch("local") 73 | for _,entry in ipairs(mapLog) do 74 | global.map:setData(entry.x,entry.y,entry.z,entry.data) 75 | end 76 | print("flat", os.epoch("local")-start) 77 | end 78 | 79 | mapLogs = {} 80 | mapLog = {} 81 | 82 | function testTableInsert() 83 | mapLogs = createDeepTable() 84 | mapLog = createFlatTable(createDeepTable()) 85 | 86 | emptyDeepTable(mapLogs) 87 | emptyFlatTable(mapLog) 88 | 89 | end 90 | 91 | 92 | 93 | printTurtles() 94 | printGlobals() 95 | printEvents() 96 | 97 | --testTableInsert() 98 | -------------------------------------------------------------------------------- /host/receive.lua: -------------------------------------------------------------------------------- 1 | 2 | local bluenet = require("bluenet") 3 | local ownChannel = bluenet.ownChannel 4 | local channelBroadcast = bluenet.default.channels.broadcast 5 | local channelHost = bluenet.default.channels.host 6 | local channelStorage = bluenet.default.channels.storage 7 | local computerId = os.getComputerID() 8 | 9 | local global = global 10 | local monitor = global.monitor 11 | 12 | local node = global.node 13 | local nodeStream = global.nodeStream 14 | local nodeUpdate = global.nodeUpdate 15 | local nodeStorage = global.storage.node 16 | 17 | global.timerCount = 0 18 | global.eventCount = 0 19 | global.messageCount = 0 20 | 21 | local updateRate = 0.1 22 | 23 | local pullEventRaw = os.pullEventRaw 24 | local type = type 25 | --local tmr = os.startTimer(updateRate) 26 | 27 | while global.running and global.receiving do 28 | --local event = {os.pullEventRaw()} 29 | 30 | -- !! none of the functions called here can use os.pullEvent !! 31 | 32 | local event, p1, p2, p3, msg, p5 = pullEventRaw() 33 | global.eventCount = global.eventCount + 1 34 | if event == "modem_message" 35 | --and ( p2 == ownChannel or p2 == channelBroadcast or p2 == channelHost ) 36 | and type(msg) == "table" 37 | and ( type(msg.recipient) == "number" and msg.recipient 38 | and ( msg.recipient == computerId or msg.recipient == channelBroadcast 39 | or msg.recipient == channelHost or msg.recipient == channelStorage) ) 40 | -- just to make sure its a bluenet message 41 | then 42 | -- event, modem, channel, replyChannel, message, distance 43 | global.messageCount = global.messageCount + 1 44 | msg.distance = p5 45 | local protocol = msg.protocol 46 | if protocol == "miner_stream" then 47 | nodeStream:addMessage(msg) 48 | -- handle events immediately to avoid getting behind 49 | --nodeStream:handleEvent(event) 50 | 51 | elseif protocol == "update" then 52 | nodeUpdate:addMessage(msg) 53 | elseif protocol == "miner" then 54 | node:addMessage(msg) 55 | elseif protocol == "chunk" then 56 | -- handle chunk requests immediately 57 | -- would be nice but seems to lead to problems 58 | node:handleMessage(msg) 59 | --node:addMessage(msg) 60 | elseif protocol == "storage" then 61 | nodeStorage:addMessage(msg) 62 | elseif protocol == "storage_priority" then 63 | nodeStorage:handleMessage(msg) 64 | end 65 | 66 | elseif event == "timer" then 67 | --if event[2] == bluenet.receivedTimer then 68 | --bluenet.clearReceivedMessages() 69 | --end 70 | global.timerCount = global.timerCount + 1 71 | elseif event == "monitor_touch" or event == "mouse_up" 72 | or event == "mouse_click" or event == "monitor_resize" then 73 | monitor:addEvent({event,p1,p2,p3,msg,p5}) 74 | elseif event == "terminate" then 75 | error("Terminated",0) 76 | end 77 | if event and global.printEvents then 78 | if not (event == "timer") then 79 | print(event,p1,p2,p3,msg,p5) 80 | end 81 | end 82 | end -------------------------------------------------------------------------------- /gui/classButton.lua: -------------------------------------------------------------------------------- 1 | local Box = require("classBox") 2 | 3 | local defaultBackgroundColor = colors.gray 4 | local defaultTextColor = colors.white 5 | local defaultDisabledColor = colors.lightGray 6 | local defaultWidth = 10 7 | local defaultHeight = 3 8 | local blinkTime = 0.12 9 | 10 | local Button = Box:new() 11 | 12 | function Button:new(text,x,y,width,height,color) 13 | local o = o or Box:new(x,y,width or defaultWidth,height or defaultHeight,color or defaultBackgroundColor) 14 | setmetatable(o, self) 15 | self.__index = self 16 | 17 | o.parent = parent or nil 18 | o.textColor = defaultTextColor 19 | o.text = text or "" 20 | 21 | o.enabled = true 22 | o.disabledColor = defaultDisabledColor 23 | o.enabledColor = o.backgroundColor 24 | 25 | o:initialize() 26 | return o 27 | end 28 | 29 | function Button:initialize() 30 | self:calculateMid() 31 | end 32 | 33 | function Button:calculateMid() -- super override 34 | self.midWidth = math.floor((self.width-string.len(self.text)) /2) 35 | self.midHeight = math.floor(self.height/2) 36 | self.midX = self.x + self.midWidth 37 | self.midY = self.y + self.midHeight 38 | end 39 | 40 | function Button:blink() 41 | local col = self:getBackgroundColor() 42 | if self.parent then 43 | self:setBackgroundColor(self.disabledColor) 44 | self:redraw() 45 | self.parent:update() 46 | sleep(blinkTime) 47 | self:setBackgroundColor(col) 48 | self:redraw() 49 | self.parent:update() 50 | end 51 | end 52 | function Button:handleClick() 53 | if self.enabled == true then 54 | local noBlink = self:click() 55 | if not noBlink then 56 | self:blink() 57 | end 58 | end 59 | end 60 | 61 | function Button:click() 62 | --pseudo function 63 | --print(self:getText(), "clicked", "no function assigned") 64 | end 65 | 66 | function Button:setEnabled(enabled) 67 | self.enabled = enabled 68 | if enabled then 69 | self:setBackgroundColor(self.enabledColor) 70 | else 71 | self:setBackgroundColor(self.disabledColor) 72 | end 73 | end 74 | 75 | function Button:redraw() 76 | --super 77 | Box.redraw(self) 78 | 79 | --text 80 | if self.parent and self.visible then 81 | self.parent:drawText(self.midX, self.midY, self.text, self.textColor, self.backgroundColor) 82 | end 83 | end 84 | 85 | function Button:setText(text) 86 | self.text = tostring(text) 87 | self.midWidth = math.floor((self.width-string.len(self.text)) /2) 88 | self.midX = self.x + self.midWidth 89 | --self.midY = self.y + math.floor(self.height/2) 90 | end 91 | function Button:getText() 92 | return self.text 93 | end 94 | function Button:setTextColor(color) 95 | self.textColor = color 96 | end 97 | 98 | function Button:setDisabledColor(color) 99 | self.disabledColor = color 100 | end 101 | 102 | function Button:setWidth(width) 103 | self.width = width 104 | self:calculateMid() 105 | end 106 | 107 | function Button:setHeight(height) 108 | self.height = height 109 | self:calculateMid() 110 | end 111 | 112 | return Button -------------------------------------------------------------------------------- /old/classListOld.lua: -------------------------------------------------------------------------------- 1 | List = { 2 | first, 3 | last, 4 | count, 5 | } 6 | function List:new(o) 7 | local o = o or {} 8 | setmetatable(o, {__index = self}) 9 | self.__index = self 10 | o.first = nil 11 | o.last = nil 12 | o.count = 0 13 | return o 14 | end 15 | 16 | function List:clear() 17 | self.first = nil 18 | self.last = nil 19 | self.count = 0 20 | end 21 | 22 | function List:add(n) 23 | --assert(n) 24 | if self.first then 25 | self.first._prev = n 26 | n._next = self.first 27 | self.first = n 28 | else 29 | self.first = n 30 | self.last = n 31 | n._next = nil 32 | n._prev = nil 33 | end 34 | self.count = self.count + 1 35 | return n 36 | end 37 | 38 | function List:remove(n) 39 | 40 | --assert(n) 41 | if n._next then 42 | if n._prev then 43 | n._next._prev = n._prev 44 | n._prev._next = n._next 45 | else 46 | assert(n == self.first) 47 | n._next._prev = nil 48 | self.first = n._next 49 | end 50 | else 51 | if n._prev then 52 | assert(n == self.last) 53 | n._prev._next = nil 54 | self.last = n._prev -- n._next holy maccaroni 55 | else 56 | if n ~= self.first and n ~= self.last then 57 | f = fs.open("trace.txt", "r") 58 | local text = "" 59 | if f then 60 | text = f.readAll() 61 | f.close() 62 | end 63 | 64 | f = fs.open("trace.txt", "w") 65 | f.write(text.." END") 66 | f.write(textutils.serialize(debug.traceback())) 67 | f.close() 68 | --print(debug.traceback()) 69 | --error("asd") 70 | end 71 | assert(n == self.first and n == self.last) 72 | self.first = nil 73 | self.last = nil 74 | end 75 | end 76 | n._next = nil 77 | n._prev = nil 78 | self.count = self.count - 1 79 | --n = nil 80 | return n 81 | end 82 | 83 | function List:getFirst() 84 | return self.first 85 | end 86 | function List:getLast() 87 | return self.last 88 | end 89 | 90 | function List:getNext(n) 91 | if n then 92 | return n._next 93 | else 94 | return self.first 95 | end 96 | end 97 | function List:getPrev(n) 98 | if n then 99 | return n._prev 100 | else 101 | return self.last 102 | end 103 | end 104 | 105 | function List:toString() 106 | local text = "" 107 | node = self:getFirst() 108 | while node do 109 | text = text .. ":" .. textutils.serialize(node[1]) 110 | node = self:getNext(node) 111 | end 112 | return text 113 | end 114 | 115 | function List:moveToFront(n) 116 | -- for least recently used functionality. not used 117 | if n == self.first then 118 | return 119 | end 120 | if n._prev then 121 | n._prev._next = n._next 122 | end 123 | if n._next then 124 | n._next._prev = n._prev 125 | end 126 | if n == self.last then 127 | self.last = n._prev 128 | end 129 | self.count = self.count - 1 130 | return self:add(n) 131 | end -------------------------------------------------------------------------------- /storage/standalone/update.lua: -------------------------------------------------------------------------------- 1 | require("classBluenetNode") 2 | 3 | local node = NetworkNode:new("update") 4 | local waitTime = 5 5 | 6 | folders = { 7 | "general", 8 | "storage", 9 | "storage/standalone", 10 | } 11 | 12 | files = { 13 | --"classList.lua", 14 | --"classNetworkNode.lua", 15 | } 16 | 17 | local restart = false 18 | 19 | 20 | local function getFileAttributes(folder) 21 | local fileAttributes = {} 22 | if fs.exists(folder) and fs.isDir(folder) then 23 | 24 | for _, fileName in ipairs(fs.list("/"..folder)) do 25 | local modified = fs.attributes(folder .."/"..fileName).modified 26 | fileAttributes[fileName] = { modified = modified } 27 | end 28 | end 29 | return fileAttributes 30 | end 31 | 32 | local function compareFiles(f1, f2) 33 | local file = fs.open(f1, "r") 34 | local data1, data2 35 | if file then 36 | data1 = file.readAll() 37 | file.close() 38 | end 39 | local file = fs.open(f2, "r") 40 | if file then 41 | data2 = file.readAll() 42 | file.close() 43 | end 44 | if data1 and data2 then 45 | return data1 == data2 46 | end 47 | return false 48 | end 49 | local function importFile(fileName, fileData) 50 | 51 | print("updating", fileName) 52 | restart = true 53 | if fs.exists(fileName) then 54 | fs.delete(fileName) 55 | end 56 | file = fs.open(fileName, "w") 57 | file.write(fileData) 58 | file.close() 59 | 60 | end 61 | 62 | node.onNoAnswer = function(forMsg) 63 | print("NO ANSWER",forMsg.data[1]) 64 | end 65 | 66 | function handleAnswer(msg,forMsg) 67 | if msg and msg.data then 68 | 69 | if msg.data[1] == "FILE" then 70 | print("received",msg.data[2].name) 71 | importFile(msg.data[2].name, msg.data[2].data) 72 | elseif msg.data[1] == "FOLDERS" then 73 | 74 | for folderName, folder in pairs(msg.data[2]) do 75 | for fileName,file in pairs(folder) do 76 | print("importing", folderName, fileName) 77 | if fileName == "startup.lua" then 78 | importFile(fileName, file.data) 79 | else 80 | importFile("runtime/"..fileName, file.data) 81 | end 82 | end 83 | end 84 | else 85 | print(msg.data[1], textutils.serialize(msg.data[2])) 86 | end 87 | end 88 | end 89 | 90 | if not node.host then 91 | print("NO UPDATE HOST AVAILABLE") 92 | else 93 | print("updating...") 94 | for _,file in ipairs(files) do 95 | print("requesting", file) 96 | local modified = nil 97 | if fs.exists(file) then 98 | modified = fs.attributes(file).modified 99 | end 100 | local data = { "FILE_REQUEST", { fileName = file, modified = modified } } 101 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 102 | handleAnswer(answer, forMsg) 103 | end 104 | local files = getFileAttributes("/runtime") 105 | if fs.exists("startup.lua") then 106 | files["startup.lua"] = { modified = fs.attributes("startup.lua").modified } 107 | end 108 | 109 | print("requesting folders") 110 | local data = { "FOLDERS_REQUEST", { folderNames = folders, files = files } } 111 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 112 | handleAnswer(answer, forMsg) 113 | 114 | if restart then 115 | os.reboot() 116 | end 117 | end -------------------------------------------------------------------------------- /turtle/classCheckPointer.lua: -------------------------------------------------------------------------------- 1 | require("classList") 2 | 3 | local default = { 4 | fileName = "runtime/checkpoint.txt", 5 | } 6 | 7 | local CheckPointer = {} 8 | 9 | local tpack = table.pack 10 | local tableinsert = table.insert 11 | 12 | function CheckPointer:new(o) 13 | o = o or {} 14 | setmetatable(o, self) 15 | self.__index = self 16 | 17 | -- Function Caching 18 | for k, v in pairs(self) do 19 | if type(v) == "function" then 20 | o[k] = v -- Directly assign method to object 21 | end 22 | end 23 | 24 | o.fileName = default.fileName 25 | o.index = 0 26 | o.checkpoint = { } 27 | 28 | return o 29 | end 30 | 31 | function CheckPointer:existsCheckpoint() 32 | if fs.exists(self.fileName) then 33 | return true 34 | end 35 | return false 36 | end 37 | 38 | function CheckPointer:load(miner) 39 | if not fs.exists(self.fileName) then 40 | print("no checkpoint available") 41 | return nil 42 | end 43 | 44 | local file = fs.open(self.fileName, "r") 45 | self.checkpoint = textutils.unserialize(file.readAll()) 46 | file.close() 47 | 48 | if not self.checkpoint then 49 | print("checkpoint file empty") 50 | fs.delete(self.fileName) 51 | return false 52 | end 53 | 54 | local taskList = miner.taskList 55 | for _, task in ipairs(self.checkpoint.tasks or {}) do 56 | local entry = { task.func, taskState = task.taskState } 57 | taskList:addLast(entry) 58 | end 59 | 60 | -- restore position seperately 61 | 62 | return true 63 | end 64 | 65 | function CheckPointer:executeTasks(miner) 66 | print("CONTINUE FROM CHECKPOINT") 67 | 68 | -- restore the miner position 69 | local pos, orientation = self.checkpoint.pos, self.checkpoint.orientation 70 | 71 | for k, task in ipairs(self.checkpoint.tasks) do 72 | if k == 1 and not task.taskState.ignorePosition then 73 | -- only restore Position if needed 74 | if not miner:navigateToPos(pos.x, pos.y, pos.z) then 75 | print("checkpoint position not reachable") 76 | return false 77 | end 78 | miner:turnTo(orientation) 79 | end 80 | local func = task.func 81 | local args = task.taskState.args 82 | miner[func](miner, table.unpack(args, 1, args.n)) 83 | end 84 | 85 | -- remove the checkpoint file after restoration 86 | fs.delete(self.fileName) 87 | return true 88 | end 89 | 90 | local function getCheckpointableTasks(taskList) 91 | -- save only checkpointable tasks 92 | 93 | local checkpointableTasks = {} 94 | local node = taskList.first 95 | while node do 96 | if node.taskState then 97 | -- checkpointable task 98 | tableinsert(checkpointableTasks, { func = node[1], taskState = node.taskState }) 99 | end 100 | node = node._next 101 | end 102 | 103 | return checkpointableTasks 104 | end 105 | 106 | function CheckPointer:save(miner) 107 | 108 | local checkpoint = { 109 | tasks = getCheckpointableTasks(miner.taskList), 110 | pos = miner.pos, 111 | orientation = miner.orientation, 112 | } 113 | 114 | if #checkpoint.tasks == 0 then 115 | fs.delete(self.fileName) 116 | else 117 | --if not self.file then 118 | self.file = fs.open(self.fileName, "w") 119 | --end 120 | self.file.write(textutils.serialize(checkpoint)) 121 | self.file.close() 122 | --self.file.flush() 123 | 124 | --print("CHP:", checkpoint.tasks[1].func) 125 | -- flush appends the file 126 | end 127 | 128 | end 129 | 130 | function CheckPointer:close() 131 | if self.file then 132 | self.file.close() 133 | end 134 | end 135 | 136 | return CheckPointer -------------------------------------------------------------------------------- /test/startupDownload.lua: -------------------------------------------------------------------------------- 1 | 2 | -- installation using github for the host computer 3 | 4 | local git = "https://raw.githubusercontent.com/helpmyRF24isntworking/computercraft/main" 5 | 6 | 7 | local files, folders 8 | 9 | local allFolders = { 10 | ["general"] = { 11 | name = "general", 12 | files = { 13 | "classLogger.lua", 14 | "classPathFinder.lua", 15 | "classQueue.lua", 16 | "classSimpleVector.lua", 17 | "config.lua", 18 | "killRednet.lua", 19 | "utilsSerialize.lua", 20 | "blockTranslation.lua", 21 | "bluenet.lua", 22 | "classBluenetNode.lua", 23 | "classChunkyMap.lua", 24 | "classHeap.lua", 25 | "classList.lua", 26 | } 27 | }, 28 | ["gui"] = { 29 | name = "gui", 30 | files = { 31 | "classMonitor.lua", 32 | "classTaskGroupControl.lua", 33 | "classTaskGroupSelector.lua", 34 | "classTaskSelector.lua", 35 | "classToggleButton.lua", 36 | "classTurtleControl.lua", 37 | "classWindow.lua", 38 | "classBox.lua", 39 | "classButton.lua", 40 | "classCheckBox.lua", 41 | "classFrame.lua", 42 | "classGPU.lua", 43 | "classHostDisplay.lua", 44 | "classLabel.lua", 45 | "classMapDisplay.lua", 46 | 47 | } 48 | }, 49 | ["host"] = { 50 | name = "host", 51 | files = { 52 | "startup.lua", 53 | "classTaskGroup.lua", 54 | "display.lua", 55 | "global.lua", 56 | "initialize.lua", 57 | "main.lua", 58 | "receive.lua", 59 | "send.lua", 60 | } 61 | }, 62 | ["pocket"] = { 63 | name = "pocket", 64 | files = { 65 | "startup.lua", 66 | "update.lua", 67 | "initialize.lua", 68 | "shellDisplay.lua", 69 | } 70 | }, 71 | ["turtle"] = { 72 | name = "turtle", 73 | files = { 74 | "update.lua", 75 | "classCheckPointer.lua", 76 | "classMiner.lua", 77 | "global.lua", 78 | "initialize.lua", 79 | "main.lua", 80 | "receive.lua", 81 | "send.lua", 82 | "startup.lua", 83 | 84 | } 85 | }, 86 | } 87 | 88 | if turtle then 89 | -- download turtle files, will be updated by host anyways 90 | files = { 91 | -- "turtle/startup.lua", 92 | } 93 | folders = { 94 | ["turtle"] = { 95 | name = "turtle", 96 | files = { 97 | "startup.lua", 98 | "update.lua", 99 | } 100 | } 101 | , 102 | ["general"] = { 103 | name = "general", 104 | files = { 105 | "bluenet.lua", 106 | "classBluenetNode.lua", 107 | "classList.lua", 108 | } 109 | } 110 | } 111 | else 112 | -- host computer 113 | files = { 114 | "startup.lua" 115 | } 116 | folders = allFolders 117 | end 118 | 119 | local function saveFile(filePath, fileData) 120 | if fs.exists(filePath) then 121 | fs.delete(filePath) 122 | end 123 | 124 | local f = fs.open(filePath, "w") 125 | f.write(fileData) 126 | f.close() 127 | end 128 | 129 | 130 | local function downloadFile(filePath) 131 | local url = git.."/"..filePath 132 | print("downloading", filePath) 133 | 134 | local file = http.get(url) 135 | local fileData = file.readAll() 136 | return fileData 137 | end 138 | 139 | -- download folders 140 | for _,folder in pairs(folders) do 141 | print("downloading folder", folder.name) 142 | if not fs.exists(folder.name) then 143 | fs.makeDir(folder.name) 144 | end 145 | 146 | for _,fileName in pairs(folder.files) do 147 | local filePath = folder.name.."/"..fileName 148 | local data = downloadFile(filePath) 149 | if turtle then 150 | if fileName == "startup.lua" then 151 | saveFile(fileName, data) -- save to root folder 152 | else 153 | saveFile("runtime/"..fileName, data) 154 | end 155 | else 156 | saveFile(filePath, data) 157 | end 158 | end 159 | end 160 | 161 | -- download single files 162 | for _,fileName in pairs(files) do 163 | local data = downloadFile(fileName) 164 | saveFile(fileName, data) 165 | end 166 | 167 | turtle.forward(3) 168 | 169 | os.reboot() -------------------------------------------------------------------------------- /install.lua: -------------------------------------------------------------------------------- 1 | 2 | -- installation using github for the host computer 3 | 4 | local git = "https://raw.githubusercontent.com/helpmyRF24isntworking/computercraft/main" 5 | 6 | --https://pastebin.com/pU2HBysT 7 | -- https://pastebin.com/raw/NaFu674J for simpler turtle download 8 | 9 | local files, folders 10 | 11 | local allFolders = { 12 | ["general"] = { 13 | name = "general", 14 | files = { 15 | "classLogger.lua", 16 | "classPathFinder.lua", 17 | "classQueue.lua", 18 | "classSimpleVector.lua", 19 | "config.lua", 20 | "killRednet.lua", 21 | "utilsSerialize.lua", 22 | "blockTranslation.lua", 23 | "bluenet.lua", 24 | "classBluenetNode.lua", 25 | "classChunkyMap.lua", 26 | "classHeap.lua", 27 | "classList.lua", 28 | } 29 | }, 30 | ["gui"] = { 31 | name = "gui", 32 | files = { 33 | "classMonitor.lua", 34 | "classTaskGroupControl.lua", 35 | "classTaskGroupSelector.lua", 36 | "classTaskSelector.lua", 37 | "classToggleButton.lua", 38 | "classTurtleControl.lua", 39 | "classWindow.lua", 40 | "classBox.lua", 41 | "classButton.lua", 42 | "classCheckBox.lua", 43 | "classFrame.lua", 44 | "classGPU.lua", 45 | "classHostDisplay.lua", 46 | "classLabel.lua", 47 | "classMapDisplay.lua", 48 | "classChoiceSelector.lua", 49 | 50 | } 51 | }, 52 | ["host"] = { 53 | name = "host", 54 | files = { 55 | "startup.lua", 56 | "classTaskGroup.lua", 57 | "display.lua", 58 | "global.lua", 59 | "initialize.lua", 60 | "main.lua", 61 | "receive.lua", 62 | "send.lua", 63 | "hostTransfer.lua", 64 | } 65 | }, 66 | ["pocket"] = { 67 | name = "pocket", 68 | files = { 69 | "shellDisplay.lua", 70 | } 71 | }, 72 | ["turtle"] = { 73 | name = "turtle", 74 | files = { 75 | "update.lua", 76 | "classCheckPointer.lua", 77 | "classMiner.lua", 78 | "global.lua", 79 | "initialize.lua", 80 | "main.lua", 81 | "receive.lua", 82 | "send.lua", 83 | "startup.lua", 84 | 85 | } 86 | }, 87 | } 88 | 89 | if turtle then 90 | -- download turtle files, will be updated by host anyways 91 | files = { 92 | -- "turtle/startup.lua", 93 | } 94 | folders = { 95 | ["turtle"] = { 96 | name = "turtle", 97 | files = { 98 | "startup.lua", 99 | "update.lua", 100 | } 101 | } 102 | , 103 | ["general"] = { 104 | name = "general", 105 | files = { 106 | "bluenet.lua", 107 | "classBluenetNode.lua", 108 | "classList.lua", 109 | } 110 | } 111 | } 112 | else 113 | -- host computer 114 | files = { 115 | "startup.lua" 116 | } 117 | folders = allFolders 118 | end 119 | 120 | local function saveFile(filePath, fileData) 121 | if fs.exists(filePath) then 122 | fs.delete(filePath) 123 | end 124 | 125 | local f = fs.open(filePath, "w") 126 | f.write(fileData) 127 | f.close() 128 | end 129 | 130 | 131 | local function downloadFile(filePath) 132 | local url = git.."/"..filePath 133 | print("downloading", filePath) 134 | 135 | local file = http.get(url) 136 | local fileData = file.readAll() 137 | return fileData 138 | end 139 | 140 | -- download folders 141 | for _,folder in pairs(folders) do 142 | print("downloading folder", folder.name) 143 | if not fs.exists(folder.name) then 144 | fs.makeDir(folder.name) 145 | end 146 | 147 | for _,fileName in pairs(folder.files) do 148 | local filePath = folder.name.."/"..fileName 149 | local data = downloadFile(filePath) 150 | if turtle then 151 | if fileName == "startup.lua" then 152 | saveFile(fileName, data) -- save to root folder 153 | else 154 | saveFile("runtime/"..fileName, data) 155 | end 156 | else 157 | saveFile(filePath, data) 158 | end 159 | end 160 | end 161 | 162 | -- download single files 163 | for _,fileName in pairs(files) do 164 | local data = downloadFile(fileName) 165 | saveFile(fileName, data) 166 | end 167 | 168 | 169 | os.reboot() -------------------------------------------------------------------------------- /gui/classStorageDisplay.lua: -------------------------------------------------------------------------------- 1 | 2 | local Button = require("classButton") 3 | local Label = require("classLabel") 4 | local Window = require("classWindow") 5 | local ItemControl = require("classStorageItemControl") 6 | 7 | 8 | 9 | local default = { 10 | colors = { 11 | --background = colors.black, 12 | }, 13 | } 14 | local global = global 15 | 16 | local StorageDisplay = Window:new() 17 | 18 | function StorageDisplay:new(x,y,width,height,storage) 19 | local o = o or Window:new(x,y,width,height) 20 | setmetatable(o,self) 21 | self.__index = self 22 | 23 | --o.backgroundColor = default.colors.background 24 | 25 | self.itemControls = {} 26 | self.itemCt = 0 27 | o.storage = storage or nil 28 | 29 | o:initialize() 30 | 31 | return o 32 | end 33 | 34 | function StorageDisplay:initialize() 35 | -- Initialize storage display components here 36 | 37 | self.lblTitle = Label:new("Stored Items",1,1) 38 | self:addObject(self.lblTitle) 39 | 40 | self:refresh() 41 | 42 | end 43 | 44 | function StorageDisplay:setHostDisplay(hostDisplay) 45 | self.hostDisplay = hostDisplay 46 | if self.hostDisplay then 47 | self.mapDisplay = self.hostDisplay:getMapDisplay() 48 | end 49 | end 50 | 51 | 52 | function StorageDisplay:setStorage(storage) 53 | self.storage = storage 54 | end 55 | 56 | function StorageDisplay:onAdd() 57 | self.storage:requestItemList(true) 58 | end 59 | 60 | function StorageDisplay:checkUpdates() 61 | -- check if storage data has changed, and refresh if needed 62 | if self.storage and self.visible then 63 | local redraw = true 64 | -- TODO: only redraw/refresh if the itemlist has changed or expanded/collapsed or provider info changed in expanded 65 | self:refresh() 66 | if redraw then self:redraw() end 67 | end 68 | end 69 | 70 | function StorageDisplay:refresh() 71 | -- change positions / contents etc. 72 | if self.visible then 73 | local itemControls = self.itemControls 74 | local storage = self.storage 75 | local itemList = storage:getAccumulatedItemList() 76 | table.sort(itemList, function(a,b) return a.name < b.name end) 77 | 78 | -- todo: resort existing controls if order changed 79 | 80 | local x, y = 1,3 81 | local prvHeight = 0 82 | 83 | for i = 1, #itemList do 84 | local item = itemList[i] 85 | local data = { itemName = item.name, total = item.count } 86 | local itemControl = itemControls[item.name] 87 | if not itemControl then 88 | 89 | itemControl = ItemControl:new(x,y,data,storage) 90 | self:addObject(itemControl) 91 | itemControl:fillWidth() 92 | itemControl:setHostDisplay(self.hostDisplay) 93 | itemControls[item.name] = itemControl 94 | self.itemCt = self.itemCt + 1 95 | else 96 | if prvHeight > 3 and itemControl:getHeight() > 3 then 97 | y = y - 1 98 | end 99 | if itemControl:getY() ~= y then 100 | itemControl:setY(y) 101 | end 102 | itemControl:setData(data) 103 | end 104 | prvHeight = itemControl:getHeight() 105 | y = y + prvHeight 106 | itemControl.refreshed = true 107 | end 108 | 109 | for itemName, itemControl in pairs(itemControls) do 110 | if not itemControl.refreshed then 111 | self:removeObject(itemControl) 112 | itemControls[itemName] = nil 113 | self.itemCt = self.itemCt - 1 114 | else 115 | itemControl.refreshed = nil 116 | end 117 | end 118 | 119 | end 120 | end 121 | 122 | return StorageDisplay -------------------------------------------------------------------------------- /turtle/send.lua: -------------------------------------------------------------------------------- 1 | 2 | local global = global 3 | local tasks = global.tasks 4 | local taskList = global.list 5 | local miner = global.miner 6 | local nodeStream = global.nodeStream 7 | 8 | local id = os.getComputerID() 9 | local label = os.getComputerLabel() or id 10 | 11 | local waitTime = 3 -- to not overload the host 12 | local mapLog = {} 13 | local unloadedLog = {} 14 | local osEpoch = os.epoch 15 | 16 | nodeStream.onStreamBroken = function(previous) 17 | --print("STREAM BROKEN") 18 | end 19 | 20 | -- called by onStreamMessage 21 | nodeStream._clearLog = function() 22 | mapLog = {} 23 | unloadedLog = {} 24 | end 25 | 26 | 27 | local function packData() 28 | -- label = string -- no need to send this every time 29 | -- time = long 30 | -- pos = 3 longs 31 | -- orientation = 2 bit (0-3) 32 | -- home = 3 longs -- not needed 33 | -- fuelLevel = long 34 | -- emptySlots = 5 bit (0-16) 35 | -- task = string 36 | -- lastTask = string 37 | -- mapLog: 38 | -- entries long 39 | -- entryLength long? 40 | -- entry: 41 | -- chunkId long 42 | -- posId 13 bit / (12) (1-4096) 43 | -- value string or long 44 | -- unloadedLog: (not sent very often) 45 | -- array of chunkIds: long 46 | 47 | 48 | 49 | local data = { 50 | 51 | label or nil, 52 | osEpoch("ingame"), 53 | 54 | miner.pos.x, 55 | miner.pos.y, 56 | miner.pos.z, 57 | miner.orientation, 58 | 59 | miner:getFuelLevel(), 60 | miner:getEmptySlots(), 61 | miner.taskList.first[1], 62 | miner.taskList.last[1], 63 | 64 | mapLog, 65 | unloadedLog, 66 | } 67 | 68 | local packet = string.pack((">zLlllHBlBzz"), 69 | "label", 70 | os.epoch("ingame"), 71 | -123, 72 | 1234567, 73 | 5000, 74 | 3, 75 | 100000, 76 | 16, 77 | "task", 78 | "lastTask" 79 | 80 | ) 81 | 82 | end 83 | 84 | nodeStream.onRequestStreamData = function(previous) 85 | local state = {} 86 | state.id = id 87 | state.label = label 88 | state.time = osEpoch("ingame") --ingame milliseconds 89 | 90 | if miner and miner.pos then -- somethings broken 91 | 92 | state.pos = miner.pos 93 | state.orientation = miner.orientation 94 | state.stuck = miner.stuck -- can be nil 95 | 96 | state.fuelLevel = miner:getFuelLevel() 97 | state.emptySlots = miner:getEmptySlots() 98 | 99 | --state.inventory = miner: 100 | local map = miner.map 101 | local minerLog = map.log 102 | if #minerLog > 0 then 103 | local mapLog = mapLog 104 | local logCount = #mapLog 105 | for i = 1, #minerLog do 106 | mapLog[logCount+i] = minerLog[i] 107 | end 108 | map.log = {} 109 | end 110 | 111 | -- send unloadedChunks 112 | if #map.unloadedChunks > 0 then 113 | local unloadedChunks = map.unloadedChunks 114 | for i = 1, #unloadedChunks do 115 | unloadedLog[#unloadedLog+1] = unloadedChunks[i] 116 | end 117 | map.unloadedChunks = {} 118 | end 119 | 120 | state.unloadedLog = unloadedLog 121 | state.mapLog = mapLog 122 | 123 | if miner.taskList.first then 124 | state.task = miner.taskList.first[1] 125 | state.lastTask = miner.taskList.last[1] 126 | end 127 | else 128 | state.pos = vector.new(-1,-1,-1) 129 | state.orientation = -1 130 | state.fuelLevel = -1 131 | state.emptySlots = -1 132 | state.stuck = true 133 | if global.err then 134 | state.lastTask = global.err.func 135 | state.task = global.err.text 136 | else 137 | state.lastTask = "ERROR" 138 | state.task = "" 139 | end 140 | state.mapLog = {} 141 | end 142 | if global.err then 143 | state.lastTask = global.err.func 144 | state.task = global.err.text 145 | end 146 | 147 | return {"STATE", state } 148 | end 149 | 150 | while true do 151 | --sendState() 152 | if not nodeStream.host then 153 | --print("no streaming host") 154 | nodeStream:lookupHost(1, waitTime) 155 | else 156 | nodeStream:openStream(nodeStream.host,waitTime) 157 | end 158 | nodeStream:stream() 159 | nodeStream:checkWaitList() 160 | sleep(0.2) --0.2 161 | end 162 | 163 | print("how did we end up here...") -------------------------------------------------------------------------------- /general/classList.lua: -------------------------------------------------------------------------------- 1 | List = { 2 | first, 3 | last, 4 | count, 5 | } 6 | 7 | List.__index = List 8 | 9 | function List:new(o) 10 | local o = o or {} 11 | setmetatable(o, self) 12 | 13 | ---- Function Caching 14 | --for k, v in pairs(self) do 15 | -- if type(v) == "function" then 16 | -- o[k] = v -- Directly assign method to object 17 | -- end 18 | --end 19 | 20 | o.first = nil 21 | o.last = nil 22 | o.count = 0 23 | return o 24 | end 25 | 26 | function List:clear() 27 | self.first, self.last = nil, nil 28 | self.count = 0 29 | end 30 | 31 | function List:addFirst(n) 32 | local first = self.first 33 | if first then 34 | first._prev = n 35 | n._prev, n._next = nil, first -- slower but neccessary 36 | self.first = n 37 | else 38 | self.first, self.last = n, n 39 | n._prev, n._next = nil, nil 40 | end 41 | self.count = self.count + 1 42 | return n 43 | end 44 | 45 | function List:addLast(n) 46 | local last = self.last 47 | if last then 48 | last._next = n 49 | n._prev, n._next = last, nil 50 | self.last = n 51 | else 52 | self.first, self.last = n, n 53 | n._prev, n._next = nil, nil 54 | end 55 | self.count = self.count + 1 56 | return n 57 | end 58 | 59 | function List:removeLast(n) 60 | -- for faster removal within loops, where the position is known 61 | -- if n ~= self.last then 62 | -- error("not last") 63 | -- end 64 | local prv = n._prev 65 | if prv then 66 | prv._next = nil 67 | self.last, self.count = prv, self.count - 1 68 | return prv 69 | else 70 | self.first, self.last, self.count = nil, nil, self.count - 1 71 | return nil 72 | end 73 | end 74 | 75 | function List:remove(n) 76 | local nxt, prv = n._next, n._prev 77 | if nxt then 78 | if prv then -- middle node 79 | nxt._prev = prv 80 | prv._next = nxt 81 | else 82 | if n ~= self.first then self:logError("not first", n) end 83 | nxt._prev = nil 84 | self.first = nxt 85 | end 86 | elseif prv then 87 | if n ~= self.last then self:logError("not last", n) end 88 | prv._next = nil 89 | self.last = prv 90 | else 91 | -- only node 92 | if n ~= self.first and n ~= self.last then 93 | self:logError("not first or last", n) 94 | end 95 | self.first, self.last = nil, nil 96 | end 97 | -- set to nil in add 98 | -- n._next = nil 99 | -- n._prev = nil 100 | self.count = self.count - 1 101 | 102 | end 103 | 104 | function List:logError(reason, n) 105 | f = fs.open("trace.txt", "r") 106 | local text = "" 107 | if f then 108 | text = f.readAll() 109 | f.close() 110 | end 111 | f = fs.open("trace.txt", "w") 112 | f.write(text.." END") 113 | f.write(reason .. " | " .. textutils.serialize(debug.traceback())) 114 | f.close() 115 | print(n._next, n._prev, n, self.first, self.last) 116 | error(reason) --textutils.serialize(debug.traceback())) 117 | end 118 | 119 | -- DO NOT USE 120 | -- function List:getFirst() 121 | -- return self.first 122 | -- end 123 | -- function List:getLast() 124 | -- return self.last 125 | -- end 126 | 127 | -- function List:getNext(n) 128 | -- if n then 129 | -- return n._next 130 | -- else 131 | -- return self.first 132 | -- end 133 | -- end 134 | -- function List:getPrev(n) 135 | -- if n then 136 | -- return n._prev 137 | -- else 138 | -- return self.last 139 | -- end 140 | -- end 141 | 142 | function List:toString() 143 | local text = "" 144 | node = self.first 145 | while node do 146 | text = text .. ":" .. textutils.serialize(node[1]) 147 | node = node._next 148 | end 149 | return text 150 | end 151 | 152 | 153 | function List:moveToFront(n) 154 | -- for least recently used functionality. not used 155 | if n == self.first then 156 | return 157 | end 158 | if n._prev then 159 | n._prev._next = n._next 160 | end 161 | if n._next then 162 | n._next._prev = n._prev 163 | end 164 | if n == self.last then 165 | self.last = n._prev 166 | end 167 | self.count = self.count - 1 168 | return self:addFirst(n) 169 | end -------------------------------------------------------------------------------- /test/serialization.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | local chunk = { 4 | --[1] = 0, 5 | [2] = 0, 6 | [3] = 0, 7 | [4] = 0, 8 | [5] = "computercraft:turtle_advanced", 9 | [6] = 0, 10 | [7] = "computercraft:turtle_advanced", 11 | [8] = "computercraft:turtle_advanced", 12 | [9] = "computercraft:turtle_advanced", 13 | [10] = 0, 14 | [11] = "computercraft:turtle_advanced", 15 | [12] = "computercraft:turtle_advanced", 16 | [13] = 0, 17 | [14] = 0, 18 | [15] = "computercraft:turtle_advanced", 19 | [16] = "computercraft:turtle_advanced", 20 | [17] = 0, 21 | [18] = "computercraft:turtle_advanced", 22 | [19] = 0, 23 | --[20] = 0, 24 | [21] = 0, 25 | [22] = 0, 26 | [23] = "computercraft:turtle_advanced", 27 | 28 | ["_lastChange"] = 1847592000, 29 | ["_accessCount"] = 1332, 30 | } 31 | package.path = package.path ..";../?/?.lua" .. ";../general/?.lua" 32 | local utilsSerialize = require("utilsSerialize") 33 | local binarize = utilsSerialize.binarize 34 | local simpleSerialize = utilsSerialize.serialize 35 | local binarizeRuns = utilsSerialize.binarizeRuns 36 | local unbinarize = utilsSerialize.unbinarize 37 | local unserialize = utilsSerialize.unserialize 38 | 39 | local f = fs.open("test/testchunk.txt","r") 40 | local stillSerializedChunk = f.readAll() 41 | chunk = unserialize(stillSerializedChunk) 42 | f.close() 43 | 44 | 45 | -- BINARIZE 46 | local function testBinarize(times) 47 | local ts = os.epoch("utc") 48 | local binaryData 49 | for i = 1, times do 50 | binaryData = binarize(chunk) 51 | end 52 | print(os.epoch("utc") - ts, "BINARY DATA LENGTH (CHAT):", binaryData and #binaryData or 0) 53 | local ts = os.epoch("utc") 54 | local open = fs.open 55 | for i = 1, times do 56 | f = open("test/binary_fast_test.bin","wb") 57 | f.write(binaryData) 58 | f.close() 59 | end 60 | print("FILE WRITE TIME:" , os.epoch("utc") - ts) 61 | local ts = os.epoch("utc") 62 | local restoredChunk 63 | for i = 1, times do 64 | restoredChunk = unbinarize(binaryData) 65 | end 66 | print("UNBINARIZE TIME:" , os.epoch("utc") - ts) 67 | 68 | end 69 | 70 | 71 | 72 | local function testBinarizeRuns(times) 73 | local ts = os.epoch("utc") 74 | local binaryData 75 | for i = 1, times do 76 | binaryData = binarizeRuns(chunk) 77 | end 78 | print(os.epoch("utc") - ts, "BINARY DATA LENGTH:", binaryData and #binaryData or 0) 79 | local ts = os.epoch("utc") 80 | for i = 1, times do 81 | f = fs.open("test/binary_test.bin","w") 82 | f.write(binaryData) 83 | f.close() 84 | end 85 | 86 | 87 | end 88 | 89 | -- SERIALIZE 90 | local function testSerialize(times) 91 | local ts = os.epoch("utc") 92 | local serializedData 93 | for i = 1, times do 94 | serializedData = simpleSerialize(chunk) 95 | end 96 | print(os.epoch("utc") - ts, "SERIALIZED DATA LENGTH:", serializedData and #serializedData or 0) 97 | local ts = os.epoch("utc") 98 | for i = 1, times do 99 | f = fs.open("test/serialized_test.txt","w") 100 | f.write(serializedData) 101 | f.close() 102 | end 103 | print("FILE WRITE TIME:" , os.epoch("utc") - ts) 104 | local ts = os.epoch("utc") 105 | local restoredChunk 106 | for i = 1, times do 107 | restoredChunk = unserialize(serializedData) 108 | end 109 | print("UNSERIALIZE TIME:" , os.epoch("utc") - ts) 110 | end 111 | 112 | 113 | local serializeDefault = textutils.serialize 114 | local function testSerializeDefault(times) 115 | local ts = os.epoch("utc") 116 | local serializedData 117 | for i = 1, times do 118 | serializedData = serializeDefault(chunk) 119 | end 120 | print(os.epoch("utc") - ts, "SERIALIZED DATA LENGTH (DEFAULT):", serializedData and #serializedData or 0) 121 | local ts = os.epoch("utc") 122 | for i = 1, times do 123 | f = fs.open("test/serialized_default_test.txt","w") 124 | f.write(serializedData) 125 | f.close() 126 | end 127 | print("FILE WRITE TIME:" , os.epoch("utc") - ts) 128 | end 129 | 130 | 131 | local times = 1000 132 | testBinarize(times) 133 | testSerialize(times) 134 | --testBinarizeRuns(times) 135 | testSerializeDefault(times) 136 | 137 | 138 | -------------------------------------------------------------------------------- /gui/classTaskSelector.lua: -------------------------------------------------------------------------------- 1 | local Button = require("classButton") 2 | local Window = require("classWindow") 3 | 4 | local default = { 5 | colors = { 6 | background = colors.black, 7 | border = colors.gray 8 | }, 9 | width = 20, 10 | height = 12, 11 | yLevel = { 12 | top = 73, 13 | bottom = -60, 14 | } 15 | } 16 | 17 | local TaskSelector = Window:new() 18 | 19 | function TaskSelector:new(x,y,width,height) 20 | local o = o or Window:new(x,y,width or default.width ,height or default.height ) or {} 21 | setmetatable(o, self) 22 | self.__index = self 23 | 24 | o.backgroundColor = default.colors.background 25 | o.borderColor = default.colors.border 26 | o.node = node or nil 27 | o.mapDisplay = mapDisplay or nil 28 | o.taskName = nil 29 | 30 | o:initialize() 31 | return o 32 | end 33 | 34 | function TaskSelector:initialize() 35 | 36 | self.btnMineArea = Button:new("mineArea",3,3,14,1) 37 | self.btnNavigateToPos = Button:new("navigateToPos",3,5,14,1) 38 | self.btnDigToPos = Button:new("digToPos", 3,7,14,1) 39 | self.btnReboot = Button:new("reboot", 3,9,14,1) 40 | 41 | self.btnMineArea.click = function() self:mineArea() end 42 | self.btnNavigateToPos.click = function() self:navigateToPos() end 43 | self.btnDigToPos.click = function() self:digToPos() end 44 | self.btnReboot.click = function() self:reboot() end 45 | 46 | self:addObject(self.btnMineArea) 47 | self:addObject(self.btnNavigateToPos) 48 | self:addObject(self.btnDigToPos) 49 | self:addObject(self.btnReboot) 50 | end 51 | 52 | function TaskSelector:setNode(node) 53 | self.node = node 54 | end 55 | function TaskSelector:setData(data) 56 | self.data = data 57 | end 58 | function TaskSelector:setHostDisplay(hostDisplay) 59 | self.hostDisplay = hostDisplay 60 | if self.hostDisplay then 61 | self.mapDisplay = self.hostDisplay:getMapDisplay() 62 | end 63 | end 64 | function TaskSelector:openMap() 65 | if self.hostDisplay and self.mapDisplay then 66 | self.hostDisplay:displayMap() 67 | end 68 | end 69 | 70 | function TaskSelector:selectPosition() 71 | self.position = nil 72 | self.mapDisplay.onPositionSelected = function(objRef,x,y,z) self:onPositionSelected(x,y,z) end 73 | self.mapDisplay:selectPosition() 74 | self:openMap() 75 | end 76 | 77 | function TaskSelector:selectArea() 78 | self.positions = {} 79 | self.mapDisplay.onPositionSelected = function(objRef,x,y,z) self:onAreaSelected(x,y,z) end 80 | self.mapDisplay:selectPosition() 81 | self:openMap() 82 | end 83 | 84 | function TaskSelector:mineArea() 85 | if self.node then 86 | self.taskName = "mineArea" 87 | self:selectArea() 88 | end 89 | end 90 | 91 | 92 | function TaskSelector:onAreaSelected(x, y, z) 93 | print("selected position", #self.positions, x,y,z) 94 | if x and z then 95 | if #self.positions < 2 then 96 | if y == nil then 97 | if #self.positions == 0 then 98 | -- default top level 99 | y = default.yLevel.top 100 | else 101 | -- default end level 102 | y = default.yLevel.bottom 103 | end 104 | end 105 | table.insert(self.positions,vector.new(x,y,z)) 106 | 107 | if #self.positions == 1 then 108 | -- start selection for second position 109 | self.mapDisplay.onPositionSelected = function(objRef,x,y,z) self:onAreaSelected(x,y,z) end 110 | self.mapDisplay:selectPosition() 111 | end 112 | end 113 | else 114 | -- cancel position selection 115 | end 116 | 117 | if #self.positions == 2 then 118 | -- area selected 119 | self.node:send(self.data.id, {"DO", self.taskName, {self.positions[1] ,self.positions[2]}}) 120 | self:close() 121 | self.mapDisplay:close() 122 | end 123 | end 124 | 125 | function TaskSelector:onPositionSelected(x,y,z) 126 | if x and z then 127 | if y == nil then y = default.yLevel.top end 128 | self.node:send(self.data.id, {"DO",self.taskName,{x,y,z}}) 129 | else 130 | -- cancel position selection 131 | end 132 | 133 | self:close() 134 | self.mapDisplay:close() 135 | end 136 | 137 | function TaskSelector:navigateToPos() 138 | if self.node then 139 | self.taskName = "navigateToPos" 140 | self:selectPosition() 141 | end 142 | end 143 | 144 | function TaskSelector:digToPos() 145 | if self.node then 146 | self.taskName = "digToPos" 147 | self:selectPosition() 148 | end 149 | end 150 | 151 | function TaskSelector:reboot() 152 | if self.node then 153 | self.node:send(self.data.id, {"REBOOT"},false,false) 154 | self:close() 155 | end 156 | end 157 | 158 | return TaskSelector -------------------------------------------------------------------------------- /turtle/update.lua: -------------------------------------------------------------------------------- 1 | require("classBluenetNode") 2 | --require("classNetworkNode") 3 | 4 | local node = NetworkNode:new("update") 5 | local waitTime = 5 6 | 7 | folders = { 8 | "general", 9 | "turtle", 10 | } 11 | 12 | files = { 13 | --"classList.lua", 14 | --"classNetworkNode.lua", 15 | } 16 | 17 | local restart = false 18 | 19 | -- local function getFileAttributes(file) 20 | -- if fs.exists(file) then 21 | -- local modified = fs.attributes(file).modified 22 | -- return { fileName = file, modified = modified 23 | -- end 24 | local function getFileAttributes(folder) 25 | local fileAttributes = {} 26 | if fs.exists(folder) and fs.isDir(folder) then 27 | 28 | for _, fileName in ipairs(fs.list("/"..folder)) do 29 | local modified = fs.attributes(folder .."/"..fileName).modified 30 | fileAttributes[fileName] = { modified = modified } 31 | end 32 | end 33 | return fileAttributes 34 | end 35 | 36 | local function compareFiles(f1, f2) 37 | local file = fs.open(f1, "r") 38 | local data1, data2 39 | if file then 40 | data1 = file.readAll() 41 | file.close() 42 | end 43 | local file = fs.open(f2, "r") 44 | if file then 45 | data2 = file.readAll() 46 | file.close() 47 | end 48 | if data1 and data2 then 49 | return data1 == data2 50 | end 51 | return false 52 | end 53 | local function importFile(fileName, fileData) 54 | 55 | print("updating", fileName) 56 | restart = true 57 | if fs.exists(fileName) then 58 | fs.delete(fileName) 59 | end 60 | file = fs.open(fileName, "w") 61 | file.write(fileData) 62 | file.close() 63 | 64 | end 65 | 66 | node.onNoAnswer = function(forMsg) 67 | print("NO ANSWER",forMsg.data[1]) 68 | end 69 | 70 | function handleAnswer(msg,forMsg) 71 | if msg and msg.data then 72 | 73 | if msg.data[1] == "FILE" then 74 | print("received",msg.data[2].name) 75 | importFile(msg.data[2].name, msg.data[2].data) 76 | elseif msg.data[1] == "FOLDERS" then 77 | 78 | for folderName, folder in pairs(msg.data[2]) do 79 | for fileName,file in pairs(folder) do 80 | print("importing", folderName, fileName) 81 | if fileName == "startup.lua" then 82 | importFile(fileName, file.data) 83 | else 84 | importFile("runtime/"..fileName, file.data) 85 | end 86 | end 87 | end 88 | else 89 | print(msg.data[1], textutils.serialize(msg.data[2])) 90 | end 91 | end 92 | end 93 | 94 | if not node.host then 95 | print("NO UPDATE HOST AVAILABLE") 96 | else 97 | print("updating...") 98 | for _,file in ipairs(files) do 99 | print("requesting", file) 100 | local modified = nil 101 | if fs.exists(file) then 102 | modified = fs.attributes(file).modified 103 | end 104 | local data = { "FILE_REQUEST", { fileName = file, modified = modified } } 105 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 106 | handleAnswer(answer, forMsg) 107 | end 108 | local files = getFileAttributes("/runtime") 109 | if fs.exists("startup.lua") then 110 | files["startup.lua"] = { modified = fs.attributes("startup.lua").modified } 111 | end 112 | 113 | print("requesting folders") 114 | local data = { "FOLDERS_REQUEST", { folderNames = folders, files = files } } 115 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 116 | handleAnswer(answer, forMsg) 117 | 118 | if restart then 119 | os.reboot() 120 | end 121 | end 122 | 123 | 124 | -- raw file request.. basically just bluenet, dont like it very much. 125 | 126 | -- local modem 127 | -- local waitTime = 5 128 | -- local protocol = "update" 129 | -- local host 130 | 131 | -- local function waitForAnswer(protocol, waitTime) 132 | -- -- identical to bluenet 133 | 134 | -- local timer = nil 135 | -- local eventFilter = nil 136 | 137 | -- if waitTime then 138 | -- timer = os.startTimer(waitTime) 139 | -- eventFilter = nil 140 | -- else 141 | -- eventFilter = "modem_message" 142 | -- end 143 | 144 | -- --print("receiving", protocol, waitTime, timer, eventFilter) 145 | -- while true do 146 | -- local event, modem, channel, sender, msg, distance = os.pullEvent(eventFilter) 147 | 148 | -- if event == "modem_message" 149 | -- and type(msg) == "table" 150 | -- and ( type(msg.recipient) == "number" and msg.recipient 151 | -- and ( msg.recipient == computerId or msg.recipient == default.channels.broadcast 152 | -- or msg.recipient == default.channels.host ) ) 153 | -- and ( protocol == nil or protocol == msg.protocol ) 154 | -- -- just to make sure its a bluenet message 155 | -- then 156 | -- msg.distance = distance 157 | -- return msg 158 | 159 | -- elseif event == "timer" then 160 | -- if modem == timer then 161 | -- return nil 162 | -- end 163 | -- end 164 | 165 | -- end 166 | 167 | -- end 168 | 169 | -- local function requestFiles() 170 | -- modem = peripheral.find("modem") 171 | -- if not modem then 172 | -- print("NO MODEM") 173 | -- return nil 174 | -- end 175 | -- peripheral.call(modem, "open", os.getComputerID()%65400) 176 | 177 | 178 | -- end 179 | 180 | -------------------------------------------------------------------------------- /old/pocket/update.lua: -------------------------------------------------------------------------------- 1 | require("classBluenetNode") 2 | --require("classNetworkNode") 3 | 4 | local node = NetworkNode:new("update") 5 | local waitTime = 5 6 | 7 | folders = { 8 | "general", 9 | "gui", 10 | "host", 11 | "pocket", 12 | } 13 | 14 | files = { 15 | --"classList.lua", 16 | --"classNetworkNode.lua", 17 | } 18 | 19 | local restart = false 20 | 21 | -- local function getFileAttributes(file) 22 | -- if fs.exists(file) then 23 | -- local modified = fs.attributes(file).modified 24 | -- return { fileName = file, modified = modified 25 | -- end 26 | local function getFileAttributes(folder) 27 | local fileAttributes = {} 28 | if fs.exists(folder) and fs.isDir(folder) then 29 | 30 | for _, fileName in ipairs(fs.list("/"..folder)) do 31 | local modified = fs.attributes(folder .."/"..fileName).modified 32 | fileAttributes[fileName] = { modified = modified } 33 | end 34 | end 35 | return fileAttributes 36 | end 37 | 38 | local function compareFiles(f1, f2) 39 | local file = fs.open(f1, "r") 40 | local data1, data2 41 | if file then 42 | data1 = file.readAll() 43 | file.close() 44 | end 45 | local file = fs.open(f2, "r") 46 | if file then 47 | data2 = file.readAll() 48 | file.close() 49 | end 50 | if data1 and data2 then 51 | return data1 == data2 52 | end 53 | return false 54 | end 55 | local function importFile(fileName, fileData) 56 | 57 | print("updating", fileName) 58 | restart = true 59 | if fs.exists(fileName) then 60 | fs.delete(fileName) 61 | end 62 | file = fs.open(fileName, "w") 63 | file.write(fileData) 64 | file.close() 65 | 66 | end 67 | 68 | node.onNoAnswer = function(forMsg) 69 | print("NO ANSWER",forMsg.data[1]) 70 | end 71 | 72 | function handleAnswer(msg,forMsg) 73 | if msg and msg.data then 74 | 75 | if msg.data[1] == "FILE" then 76 | print("received",msg.data[2].name) 77 | importFile(msg.data[2].name, msg.data[2].data) 78 | elseif msg.data[1] == "FOLDERS" then 79 | 80 | for folderName, folder in pairs(msg.data[2]) do 81 | for fileName,file in pairs(folder) do 82 | print("importing", folderName, fileName) 83 | if fileName == "startup.lua" then 84 | importFile(fileName, file.data) 85 | else 86 | importFile("runtime/"..fileName, file.data) 87 | end 88 | end 89 | end 90 | else 91 | print(msg.data[1], textutils.serialize(msg.data[2])) 92 | end 93 | end 94 | end 95 | 96 | if not node.host then 97 | print("NO UPDATE HOST AVAILABLE") 98 | else 99 | print("updating...") 100 | for _,file in ipairs(files) do 101 | print("requesting", file) 102 | local modified = nil 103 | if fs.exists(file) then 104 | modified = fs.attributes(file).modified 105 | end 106 | local data = { "FILE_REQUEST", { fileName = file, modified = modified } } 107 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 108 | handleAnswer(answer, forMsg) 109 | end 110 | local files = getFileAttributes("/runtime") 111 | if fs.exists("startup.lua") then 112 | files["startup.lua"] = { modified = fs.attributes("startup.lua").modified } 113 | end 114 | 115 | print("requesting folders") 116 | local data = { "FOLDERS_REQUEST", { folderNames = folders, files = files } } 117 | local answer, forMsg = node:send(node.host, data, true, true, waitTime) 118 | handleAnswer(answer, forMsg) 119 | 120 | if restart then 121 | os.reboot() 122 | end 123 | end 124 | 125 | 126 | -- raw file request.. basically just bluenet, dont like it very much. 127 | 128 | -- local modem 129 | -- local waitTime = 5 130 | -- local protocol = "update" 131 | -- local host 132 | 133 | -- local function waitForAnswer(protocol, waitTime) 134 | -- -- identical to bluenet 135 | 136 | -- local timer = nil 137 | -- local eventFilter = nil 138 | 139 | -- if waitTime then 140 | -- timer = os.startTimer(waitTime) 141 | -- eventFilter = nil 142 | -- else 143 | -- eventFilter = "modem_message" 144 | -- end 145 | 146 | -- --print("receiving", protocol, waitTime, timer, eventFilter) 147 | -- while true do 148 | -- local event, modem, channel, sender, msg, distance = os.pullEvent(eventFilter) 149 | 150 | -- if event == "modem_message" 151 | -- and type(msg) == "table" 152 | -- and ( type(msg.recipient) == "number" and msg.recipient 153 | -- and ( msg.recipient == computerId or msg.recipient == default.channels.broadcast 154 | -- or msg.recipient == default.channels.host ) ) 155 | -- and ( protocol == nil or protocol == msg.protocol ) 156 | -- -- just to make sure its a bluenet message 157 | -- then 158 | -- msg.distance = distance 159 | -- return msg 160 | 161 | -- elseif event == "timer" then 162 | -- if modem == timer then 163 | -- return nil 164 | -- end 165 | -- end 166 | 167 | -- end 168 | 169 | -- end 170 | 171 | -- local function requestFiles() 172 | -- modem = peripheral.find("modem") 173 | -- if not modem then 174 | -- print("NO MODEM") 175 | -- return nil 176 | -- end 177 | -- peripheral.call(modem, "open", os.getComputerID()%65400) 178 | 179 | 180 | -- end 181 | 182 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Actually Useful Turtles 2 | 3 | Remotely controlled mining turtles for the CC:Tweaked mod in Minecraft. This project started as a funny idea while playing with friends to compete with those ridiculously op mining mods. At first i wrote some simple code but after 15k lines of code i cant stop. 4 | 5 | While turtles are quite cool, they are more of a novelty than being actually useful for a normal playthrough or at least require a high level of maintainence. To compete with other quarry mods you would also need a LOT of turtles, controlling them individually is a nightmare even with prewritten scripts. 6 | 7 | With this I aim to centralize the management via a single host. Just give them fuel and select a task. Tested with up to 250 Turtles. 8 | 9 | 10 | 11 | ### Features: 12 | 13 | 14 | #### Full remote GUI Control from a single Host 15 | > All turtles can be controlled via the monitor next to the host. There you can view the status of each turtle and assign them a task - individually or via groups. 16 | > View the map with live updates from the turtles. 17 | #### High Performance ingame Messaging via Modems 18 | > Uses a questionable protocol and a more performant implementation of rednet -> bluenet 19 | > - Bidirectional message streaming ( basically an ingame websocket ) 20 | > - Faster lookups 21 | > - Message acknowledgements ( kind of like MQTT QOS 1 ) 22 | > - Host as message broker 23 | > - Versioned file sharing / requesting for updating the turtles 24 | > - More performant event pulling and filtering 25 | > - up to 50.000 messages per second with default settings, the upper limit for cached messaging with peripheral.call sits at 70.000. 26 | > 27 | > A lot of time has been spent on ensuring consistency while maintaining performance. 28 | 29 | #### Chunk based Mapping 30 | > Turtles passively map the entire map during their tasks and pass the updates basically in real time to one another via bluenet. This enables the live-map display and pathfinding. 31 | Each turtle only has the needed chunks cached in memory, while the host manages version control, persistence and distribution. The map is stored in chunks in runtime/map/chunks on the host. 32 | 33 | #### Actual Mining Tasks 34 | > The turtles are basically just there to mine... for this they use efficient mining strategies: When assigning turtles with an area to mine, the area is split evenly across each member of the group. Afterwards the turtle pathfinds to the closest starting position and starts stripmining the entire area. It uses the map to skip already explored blocks and find previously discovered but unmined ores. Turtles can resume their tasks while the host is offline and store their updates for distribution until it is back online. They automatically refuel, condense their inventory, dropoff items when full etc. 35 | > 36 | #### Unload Protection 37 | > By creating checkpoints during specific tasks, the turtles can always resume their task after being unloaded, rebooted or after closing the game. GPS needs to be available during startup though, to determine their position. 38 | > In regular intervals the map changes are saved onto the disk by the host, some updates might be lost when the host is suddenly unloaded. 39 | 40 | 41 |

42 | 43 | ![grafik](https://github.com/user-attachments/assets/7731f1ae-0d55-4345-b8da-e62db92dde1f) 44 | 45 | THIS IS WORK IN PROGRESS. 46 | Let me know about any issues you have or ideas. :) 47 | 48 | 49 | # INSTALLATION 50 | 51 | ### GPS 52 | 53 | Before setting up the actual Computers, GPS should be available. Place it somewhere near the Host-Computer. 54 | https://tweaked.cc/guide/gps_setup.html 55 | 56 | ### HOST COMPUTER 57 | 58 | 1. Place the Host-Computer with a Wireless Modem and Monitor next to it 59 | ( I recommend the monitors facing south, so the map is aligned more intuitively ) 60 | 3. Download and run the installation using those commands: 61 | ``pastebin get https://pastebin.com/Svg4QckR install`` 62 | ``install`` 63 | 3. Setup the Stations for the Turtles: 64 | 1. Open lua 65 | 2. Delete existing stations, otherwise the turtles will run away: 66 | ``global.deleteAllStations()`` 67 | 3. Add new Stations: 68 | ``global.addStation(x, y, z, facing, type)`` 69 | facing = "north", "west", "south", "east" 70 | type = "turtle" for home and dropoff, "refuel" for refueling 71 | 4. optional but recommended: add a refuel queue area 72 | ``global.setRefuelQueue(x, y, z, maxDistance)`` 73 | maxDistance like 8, and position a few blocks above the actual refuel stations 74 | 4. Save Config: 75 | ``global.saveConfig()`` 76 | 77 |
78 | 79 | Other helpful commands: 80 | - View the stations: ``global.listStations()`` 81 | - Delete a station: ``global.deleteStation(x, y, z)`` 82 | 83 |
84 | 85 | ![grafik](https://github.com/user-attachments/assets/b37d059c-8b09-4d74-8bf2-eb3a31dfa35d) 86 | 87 | 88 | ### TURTLES 89 | 90 | 1. Place Turtle anywhere, with a Wireless Modem and some Fuel 91 | 2. Install using pastebin ( see Host, same file ) 92 | Turtle should request a Station from Host and move there 93 | 94 | After having placed all turtles and they moved to their station, reboot the host using the reboot button. 95 | This saves the station assignments for each turtle. 96 | 97 | Done 98 | 99 | ![grafik](https://github.com/user-attachments/assets/e493f9d3-a631-4364-aff3-c813791652b8) 100 | ![grafik](https://github.com/user-attachments/assets/224e47a3-88e6-428c-8a6d-2c7643ce7ddb) 101 | -------------------------------------------------------------------------------- /test/temp.lua: -------------------------------------------------------------------------------- 1 | 2 | -- event tests 3 | 4 | -- os.loadAPI("general/bluenet.lua") 5 | --os.loadAPI("host/global.lua") 6 | --shell.openTab("test/temp_1.lua") 7 | --shell.openTab("test/temp_2.lua") 8 | 9 | --os.queueEvent("test",os.epoch("local")) 10 | --os.startTimer(1) 11 | 12 | -- translation test 13 | 14 | -- local translation = require("general/blockTranslation") 15 | -- --local nameToId = translation.nameToId 16 | -- local nameToId = translation.nameToId 17 | -- local idToName = translation.idToName 18 | 19 | -- Map = {} 20 | 21 | -- function Map:new() 22 | -- local o = o or {} 23 | -- setmetatable(o, self) 24 | -- self.__index = self 25 | -- o.nameToId = require("general/blockTranslation").nameToId 26 | -- return o 27 | -- end 28 | 29 | -- function Map:translate(name) 30 | -- return nameToId[name] 31 | -- end 32 | 33 | 34 | -- function Map:doNameToId(name) 35 | -- return nameToId[name] 36 | -- end 37 | 38 | -- function Map:test(name) 39 | -- local start = os.epoch("local") 40 | -- for i =1, 1000000 do 41 | -- --id = map:nameToId("minecraft:stone") 42 | -- --id = self:translate("minecraft:stone") 43 | -- id = nameToId[name] 44 | -- end 45 | -- print("test",os.epoch("local")-start) 46 | -- end 47 | 48 | 49 | 50 | -- function Map:doStuff() 51 | -- local start = os.epoch("local") 52 | -- for i =1, 1000000 do 53 | -- id = self:doNameToId("minecraft:stone") 54 | -- end 55 | -- print(os.epoch("local")-start) 56 | -- end 57 | 58 | 59 | -- local map = Map:new() 60 | 61 | -- local function doNameToId(name) 62 | -- return nameToId["minecraft:stone"] 63 | -- end 64 | 65 | 66 | -- local start = os.epoch("local") 67 | -- for i =1, 1000000 do 68 | -- id = doNameToId("minecraft:stone") 69 | -- end 70 | -- print(os.epoch("local")-start) 71 | -- map:doStuff() 72 | -- map:test(1) 73 | 74 | 75 | 76 | -- --other stuff 77 | 78 | -- local start = os.epoch("local") 79 | -- for i =1, 1000000 do 80 | -- id = translation.idToName[1] 81 | -- end 82 | -- print(os.epoch("local")-start) 83 | 84 | 85 | 86 | -- local translation = require("general/blockTranslation") 87 | -- local map = global.map 88 | 89 | -- local data = { name = "minecraft:stone" } 90 | -- local start = os.epoch("local") 91 | -- for i =1, 1000000 do 92 | -- --id = map:getData(1,1,1) 93 | -- --has = string.find("minecraft:iron_ore","_ore") 94 | -- --if type(data.name) == "string" then 95 | -- id = nameToId["minecraft:iron_ore"] 96 | -- --end 97 | -- end 98 | -- print(id, os.epoch("local")-start) 99 | 100 | -- local start = os.epoch("local") 101 | -- for i =1, 1000000 do 102 | -- id = idToName[1] 103 | -- id = nameToId[id] 104 | -- end 105 | -- print(os.epoch("local")-start) 106 | 107 | 108 | local vectors = { 109 | [0] = {x=0, y=0, z=1}, -- +z = 0 south 110 | [1] = {x=-1, y=0, z=0}, -- -x = 1 west 111 | [2] = {x=0, y=0, z=-1}, -- -z = 2 north 112 | [3] = {x=1, y=0, z=0}, -- +x = 3 east 113 | } 114 | local tableinsert = table.insert 115 | 116 | local function getNeighbours(cur) 117 | local neighbours = {} 118 | 119 | -- forward 120 | local vector = vectors[cur.o] 121 | table.insert(neighbours, { x = cur.x + vector.x, y = cur.y + vector.y, z = cur.z + vector.z, o = cur.o }) 122 | -- up 123 | table.insert(neighbours, { x = cur.x, y = cur.y+1, z = cur.z, o = cur.o }) 124 | -- down 125 | table.insert(neighbours, { x = cur.x, y = cur.y-1, z = cur.z, o = cur.o }) 126 | -- left 127 | vector = vectors[(cur.o-1)%4] 128 | table.insert(neighbours, { x = cur.x + vector.x, y = cur.y + vector.y, z = cur.z + vector.z, o = (cur.o-1)%4 }) 129 | -- right 130 | vector = vectors[(cur.o+1)%4] 131 | table.insert(neighbours, { x = cur.x + vector.x, y = cur.y + vector.y, z = cur.z + vector.z, o = (cur.o+1)%4 }) 132 | -- back 133 | vector = vectors[(cur.o+2)%4] 134 | table.insert(neighbours, { x = cur.x + vector.x, y = cur.y + vector.y, z = cur.z + vector.z, o = (cur.o+2)%4 }) 135 | 136 | return neighbours 137 | end 138 | 139 | local function getNeighboursNew(cur) 140 | local neighbours = {} 141 | 142 | local cx, cy, cz, co = cur.x, cur.y, cur.z, cur.o 143 | -- forward 144 | local vector = vectors[co] 145 | neighbours[1] = { x = cx + vector.x, y = cy + vector.y, z = cz + vector.z, o = co } 146 | -- up 147 | neighbours[2] = { x = cx, y = cy + 1, z = cz, o = co } 148 | -- down 149 | neighbours[3] = { x = cx, y = cy - 1, z = cz, o = co } 150 | -- left 151 | local curo = (co-1)%4 152 | vector = vectors[curo] 153 | neighbours[4] = { x = cx + vector.x, y = cy + vector.y, z = cz + vector.z, o = curo } 154 | -- right 155 | curo = (co+1)%4 156 | vector = vectors[curo] 157 | neighbours[5] = { x = cx + vector.x, y = cy + vector.y, z = cz + vector.z, o = curo } 158 | -- back 159 | curo = (co+2)%4 160 | vector = vectors[curo] 161 | neighbours[6] = { x = cx + vector.x, y = cy + vector.y, z = cz + vector.z, o = curo } 162 | 163 | return neighbours 164 | end 165 | 166 | 167 | 168 | -- test performance 169 | 170 | local function testNeighbours() 171 | local cur = { x = 2345, y = 72, z = -2664, o = 3, block = 2 } 172 | local iterations = 100000 -- Number of operations to test 173 | local start = os.epoch("local") 174 | for i = 1, iterations do 175 | local neighbours = getNeighbours(cur) 176 | --print(neighbours) 177 | end 178 | local stop = os.epoch("local") 179 | print("getNeighbours time:", stop - start) 180 | 181 | 182 | local start = os.epoch("local") 183 | for i = 1, iterations do 184 | local neighbours = getNeighboursNew(cur) 185 | --print(neighbours) 186 | end 187 | local stop = os.epoch("local") 188 | print("getNeighboursNew time:", stop - start) 189 | end 190 | 191 | testNeighbours() -------------------------------------------------------------------------------- /test/message_meta.lua: -------------------------------------------------------------------------------- 1 | 2 | package.path = package.path ..";../runtime/?.lua" 3 | 4 | os.loadAPI("general/bluenet.lua") 5 | require("classBluenetNode") 6 | 7 | local tinsert = table.insert 8 | 9 | local node = NetworkNode:new("test", true) 10 | 11 | local data = {} 12 | for k = 1, 500 do 13 | data[k] = tostring(k) 14 | end 15 | --data = nil 16 | local ct = 0 17 | 18 | local buf = data 19 | buf[0] = 500 20 | local bufCount = 0 21 | 22 | local turt = { buf = buf } 23 | --print(#buf) 24 | node.onStreamMessage = function(msg,previous) 25 | local data = msg.data 26 | 27 | -- buf = msg.data 28 | 29 | local buf = turt.buf 30 | --local turt = turt 31 | for i=1, #data do 32 | 33 | --buf[0] = buf[0] + 1 34 | --buf[buf[0]] = data[i] 35 | --buf[#buf+1] = data[1] 36 | --bufCount = bufCount + 1 37 | --buf[bufCount] = data[i] 38 | buf[i] = data[i] 39 | --table.insert(buf, data[i]) 40 | end 41 | 42 | 43 | end 44 | 45 | 46 | node.onRequestStreamData = function(previous) 47 | --print("requested data") 48 | local data = {} 49 | 50 | data = buf 51 | turt.buf = {} 52 | bufCount = 0 53 | buf[0] = 0 54 | 55 | 56 | return data 57 | end 58 | 59 | local function send() 60 | local ct = 0 61 | for a = 1, 10 do 62 | 63 | 64 | ct = ct + 1 65 | local start = os.epoch("local") 66 | for i = 1, 1000 do 67 | 68 | node:send(65,{"TEST", data},true,true,3) 69 | --local answer = node:listen() 70 | end 71 | local t = os.epoch("local")-start 72 | print(ct, "send", t/1000) 73 | end 74 | end 75 | 76 | local function stream() 77 | node.streams = {} 78 | local ct = 0 79 | for a = 1, 10 do 80 | 81 | ct = ct + 1 82 | local start = os.epoch("local") 83 | node:openStream(65, 6) 84 | for i = 1, 1000 do 85 | node:stream() 86 | node:listen() 87 | end 88 | local t = os.epoch("local")-start 89 | print(ct, "stream", t/1000, #buf) 90 | end 91 | end 92 | 93 | 94 | 95 | local messageFields = { 96 | id = 1, 97 | time = 2, 98 | sender = 3, 99 | recipient = 4, 100 | protocol = 5, 101 | type = 6, 102 | data = 7, 103 | answer = 8, 104 | wait = 9, 105 | waitTime = 10 106 | } 107 | 108 | local msg_mt = { 109 | __index = function(t, key) 110 | return t[messageFields[key]] 111 | end 112 | } 113 | 114 | local function createMessage(...) 115 | local msg = { ... } 116 | setmetatable(msg, msg_mt) 117 | return msg 118 | end 119 | local function setMessageMetatable(msg) 120 | setmetatable(msg, msg_mt) 121 | return msg 122 | end 123 | 124 | -- Usage 125 | -- local msg = createMessage(self:generateUUID(), osEpoch(), self.id, recipient, subProtocol or self.protocol, default.typeSend, data, answer, wait, waitTime) 126 | -- print(msg.id) -- Access as if it had named fields 127 | 128 | local ID, TIME, SENDER, RECIPIENT, PROTOCOL, TYPE, DATA, ANSWER, WAIT, WAITTIME = 1,2,3,4,5,6,7,8,9,10 129 | 130 | local form = ">zLi3i3i3Bi3Bzz" 131 | local pack = string.pack 132 | local unpack = string.unpack 133 | local tpack = table.pack 134 | local tunpack = table.unpack 135 | 136 | --local createPacket = function() 137 | node.createPacket = function() 138 | local msg 139 | 140 | local createMessage = createMessage 141 | local start = os.epoch("local") 142 | for i = 1, 1000000 do 143 | 144 | msg = { 145 | 12341243, 146 | start, 147 | 234, 148 | 2345, 149 | "protocol", 150 | 2, 151 | { "data" }, 152 | true, 153 | false, 154 | 5 155 | } 156 | 157 | -- local vals = { msg[1],msg[2],msg[3],msg[4], 158 | -- msg[5],msg[6],msg[7],msg[8],msg[9],msg[10] } 159 | --local vals = { tunpack( packet) } 160 | 161 | end 162 | 163 | print(os.epoch("local")-start,"no index") 164 | print(#msg,table.unpack(msg)) 165 | 166 | 167 | local start = os.epoch("local") 168 | for i = 1, 1000000 do 169 | local msg = { 170 | id = 12341243, 171 | time = start, 172 | sender = 234, 173 | recipient = 2345, 174 | protocol = "protocol", 175 | type = 2, 176 | data = { "data" }, 177 | answer = true, 178 | wait = false, 179 | waitTime = 5 180 | } 181 | -- local vals = { msg.id, msg.time, msg.sender, msg.recipient, msg.protocol, 182 | -- msg.type, msg.data, msg.answer, msg.wait, msg.waitTime } 183 | end 184 | print(os.epoch("local")-start,"named") 185 | print(#msg,table.unpack(msg)) 186 | 187 | 188 | local start = os.epoch("local") 189 | 190 | 191 | for i = 1, 1000000 do 192 | 193 | msg = { 194 | 12341243, 195 | start, 196 | 234, 197 | 2345, 198 | "protocol", 199 | 2, 200 | { "data" }, 201 | true, 202 | false, 203 | 5 204 | } 205 | --setmetatable(msg,msg_mt) 206 | -- msg.__index = function(t,key) 207 | -- return t[messageFields[key]] 208 | -- end 209 | -- msg = createMessage( 210 | -- 12341243, 211 | -- start, 212 | -- 234, 213 | -- 2345, 214 | -- "protocol", 215 | -- 2, 216 | -- { "data" }, 217 | -- true, 218 | -- false, 219 | -- 5 220 | -- ) 221 | 222 | -- local vals = { msg.id, msg.time, msg.sender, msg.recipient, msg.protocol, 223 | -- msg.type, msg.data, msg.answer, msg.wait, msg.waitTime } 224 | local vals = { msg[ID], msg[TIME], msg[SENDER], msg[RECIPIENT], msg[PROTOCOL], 225 | msg[TYPE], msg[DATA], msg[ANSWER], msg[WAIT], msg[WAITTIME] } 226 | end 227 | print(os.epoch("local")-start,"metatable") 228 | local vals = { msg[ID], msg[TIME], msg[SENDER], msg[RECIPIENT], msg[PROTOCOL], 229 | msg[TYPE], msg[DATA], msg[ANSWER], msg[WAIT], msg[WAITTIME] } 230 | print(#vals, table.unpack(vals)) 231 | 232 | 233 | 234 | 235 | return packet 236 | end 237 | local function unpackPacket(packet) 238 | print(string.unpack((form),packet)) 239 | return string.unpack((form),packet) 240 | end 241 | 242 | --node.createPacket = createPacket 243 | node.createPacket() 244 | --_G.packet = createPacket() 245 | --_G.vals = {unpackPacket(packet)} 246 | 247 | 248 | --stream() -------------------------------------------------------------------------------- /old/bluenet.lua: -------------------------------------------------------------------------------- 1 | 2 | -- bluenet, a modified rednet for better performance 3 | 4 | default = { 5 | typeSend = 1, 6 | typeAnswer = 2, 7 | typeDone = 3, 8 | waitTime = 1, 9 | 10 | channels = { 11 | broadcast = 65401, 12 | repeater = 65402, 13 | host = 65403, 14 | max = 65400 15 | } 16 | } 17 | --msg = { id, time, sender, recipient, protocol, type, data, answer, wait, distance} 18 | 19 | receivedMessages = {} 20 | receivedTimer = nil -- does that work? 21 | osEpoch = os.epoch 22 | opened = false 23 | modem = nil 24 | ownChannel = nil 25 | computerId = os.getComputerID() 26 | 27 | function idAsChannel(id) 28 | return (id or os.getComputerID()) % default.channels.max 29 | end 30 | 31 | function findModem() 32 | for _,modem in ipairs(peripheral.getNames()) do 33 | if peripheral.getType(modem) == "modem" then 34 | return modem 35 | end 36 | end 37 | return nil 38 | end 39 | 40 | function open(modem) 41 | if not opened then 42 | 43 | if not modem then 44 | print("NO MODEM") 45 | opened = false 46 | end 47 | peripheral.call(modem, "open", ownChannel) 48 | peripheral.call(modem, "open", default.channels.broadcast) 49 | print("opened",ownChannel,default.channels.broadcast) 50 | 51 | end 52 | opened = true 53 | return true 54 | end 55 | 56 | function close(modem) 57 | if modem then 58 | if peripheral.getType(modem) == "modem" then 59 | peripheral.call(modem, "close", ownChannel) 60 | peripheral.call(modem, "close", default.channels.broadcast) 61 | opened = false 62 | end 63 | else 64 | for _,modem in ipairs(peripheral.getNames()) do 65 | if isOpen(modem) then 66 | close(modem) 67 | end 68 | end 69 | end 70 | end 71 | 72 | function isOpen(modem) 73 | if modem then 74 | if peripheral.getType(modem) == "modem" then 75 | return peripheral.call(modem, "isOpen", ownChannel) 76 | and peripheral.call(modem, "isOpen", default.channels.broadcast) 77 | end 78 | else 79 | for _,modem in ipairs(peripheral.getNames()) do 80 | if isOpen(modem) then 81 | return true 82 | end 83 | end 84 | end 85 | return false 86 | end 87 | 88 | function openChannel(modem, channel) 89 | if not isChannelOpen(modem, channel) then 90 | if not modem then 91 | print("NO MODEM") 92 | return false 93 | end 94 | peripheral.call(modem, "open", channel) 95 | print("opened", channel) 96 | end 97 | return true 98 | end 99 | 100 | function closeChannel(modem, channel) 101 | if not modem then 102 | print("NO MODEM", modem) 103 | return false 104 | end 105 | if isChannelOpen(modem, channel) then 106 | return peripheral.call(modem, "close", channel) 107 | end 108 | return true 109 | end 110 | 111 | function isChannelOpen(modem, channel) 112 | if not modem then 113 | print("NO MODEM", modem) 114 | return false 115 | end 116 | return peripheral.call(modem, "isOpen", channel) 117 | end 118 | 119 | 120 | local startTimer = os.startTimer 121 | local cancelTimer = os.cancelTimer 122 | local osClock = os.clock 123 | local timerClocks = {} 124 | local timers = {} 125 | local pullEventRaw = os.pullEventRaw 126 | local type = type 127 | 128 | function receive(protocol, waitTime) 129 | local timer = nil 130 | local eventFilter = nil 131 | 132 | -- CAUTION: if bluenet is loaded globally, 133 | -- TODO: the timers must be distinguished by protocol/coroutine 134 | -- leads to host being unable to reboot!!! 135 | 136 | if waitTime then 137 | local t = osClock() 138 | if timerClocks[waitTime] ~= t then 139 | --cancel the previous timer and create a new one 140 | cancelTimer((timers[waitTime] or 0)) 141 | timer = startTimer(waitTime) 142 | --print( protocol, "cancelled", timers[waitTime], "created", timer, "diff", timer - (timers[waitTime]or 0)) 143 | timerClocks[waitTime] = t 144 | timers[waitTime] = timer 145 | else 146 | timer = timers[waitTime] 147 | --print( protocol, "reusing", timer) 148 | end 149 | 150 | eventFilter = nil 151 | else 152 | eventFilter = "modem_message" 153 | end 154 | 155 | --print("receiving", protocol, waitTime, timer, eventFilter) 156 | while true do 157 | local event, modem, channel, sender, msg, distance = pullEventRaw(eventFilter) 158 | --if event == "modem_message" then print(os.clock(),event, modem, channel, sender) end 159 | 160 | if event == "modem_message" 161 | --and ( channel == ownChannel or channel == default.channels.broadcast 162 | -- or channel == default.channels.host ) 163 | and type(msg) == "table" 164 | --and type(msg.id) == "number" and not receivedMessages[msg.id] 165 | and ( type(msg.recipient) == "number" and msg.recipient 166 | and ( msg.recipient == computerId or msg.recipient == default.channels.broadcast 167 | or msg.recipient == default.channels.host ) ) 168 | and ( protocol == nil or protocol == msg.protocol ) 169 | -- just to make sure its a bluenet message 170 | then 171 | msg.distance = distance 172 | -- event, modem, channel, replyChannel, message, distance 173 | --print("received", msg.id, msg.protocol) 174 | --receivedMessages[msg.id] = os.clock() + 9.5 175 | --resetTimer() 176 | --cancelTimer(timer) 177 | -- if osEpoch() > t then 178 | -- print("cancel old timer") 179 | -- cancelTimer(timer) 180 | -- end 181 | return msg 182 | 183 | elseif event == "timer" then 184 | --print(os.clock(),event, modem, channel, sender, timer) 185 | 186 | if modem == timer then -- must be equal! >= geht nicht 187 | --print("returning nil") 188 | return nil 189 | end 190 | elseif event == "terminate" then 191 | error("Terminated",0) 192 | end 193 | 194 | end 195 | 196 | end 197 | 198 | function resetTimer() 199 | if not receivedTimer then receivedTimer = os.startTimer(10) end 200 | end 201 | 202 | function clearReceivedMessages() 203 | receivedTimer = nil 204 | local time, hasMore = os.clock(), nil 205 | for id, deadline in pairs(receivedMessages) do 206 | if deadline <= now then receivedMessages[id] = nil 207 | else hasMore = true end 208 | end 209 | receivedTimer = hasMore and os.startTimer(10) 210 | end 211 | 212 | modem = findModem() 213 | ownChannel = idAsChannel() -------------------------------------------------------------------------------- /old/classNetworkClient.lua: -------------------------------------------------------------------------------- 1 | require("classList") 2 | 3 | local default = { 4 | typeSend = 1, 5 | typeAnswer = 2, 6 | typeDone = 3, 7 | typeBroadcast = 4, 8 | typeRegister = 5, 9 | waitTime = 2, 10 | } 11 | --msg = { type, data, answer, task } 12 | 13 | NetworkNode = {} 14 | 15 | function NetworkNode:new(protocol) 16 | local o = o or {} 17 | setmetatable(o, self) 18 | self.__index = self 19 | 20 | print("----INITIALIZING----") 21 | 22 | self.isHost = false 23 | self.protocol = protocol 24 | self.id = os.getComputerID() 25 | self.computers = {} 26 | self.host = nil 27 | 28 | self:initialize() 29 | print("--------------------") 30 | return self 31 | end 32 | 33 | --pseudo funcitons to be implemented by enduser 34 | -- function NetworkNode:onReceive(sender,msg,protocol) end 35 | -- function NetworkNode:onAnswer(sender,msg,protocol) end 36 | -- function NetworkNode:onNoAnswer(sender,msg,protocol) end 37 | -- function NetworkNode:onRequestAnswer(sender,msg,protocol) end 38 | 39 | function NetworkNode:initialize() 40 | self:openRednet() 41 | 42 | self:hostProtocol() 43 | self:lookupHost() 44 | self:notifyHost() 45 | print("myId:", self.id, "host:", self.host, "protocol:", self.protocol) 46 | end 47 | 48 | function NetworkNode:openRednet() 49 | if rednet.isOpen() then 50 | rednet.close() 51 | end 52 | peripheral.find("modem",rednet.open) 53 | assert(rednet.isOpen(),"no modem found") 54 | end 55 | 56 | function NetworkNode:notifyHost() 57 | --notify host that a new worker is available 58 | --could be replaced by regular lookups through host 59 | if self.host then 60 | if self.host >= 0 then 61 | local answerMsg = self:send(self.host, {"REGISTER"}, true) 62 | assert(answerMsg, "no host found") 63 | end 64 | end 65 | end 66 | 67 | function NetworkNode:hostProtocol() 68 | rednet.host(self.protocol, tostring(self.id)) 69 | end 70 | 71 | function NetworkNode:setProtocol(protocol) 72 | if self.protocol then 73 | rednet.unhost(self.protocol) 74 | end 75 | self:hostProtocol() 76 | end 77 | 78 | function NetworkNode:beforeReceive(sender,msg,senderProtocol) 79 | if msg.data[1] == "RUN" then 80 | shell.run(msg.data[2]) 81 | elseif msg.data[1] == "REBOOT" then 82 | os.reboot() 83 | end 84 | end 85 | 86 | 87 | function NetworkNode:onDone(sender, msg, senderProtocol) 88 | --self.worklist:removeTask(taskId) 89 | --remove and forward to user defined funciton 90 | --if self.onDone then 91 | -- self.onDone() 92 | --end 93 | --TODO: worklist mit auftragsnummer status etc. 94 | --multiple protocol support für host 95 | --startup animation "setting up rednet" etc. 96 | 97 | end 98 | 99 | function NetworkNode:listen(waitTime) 100 | local sender, msg, senderProtocol = rednet.receive(self.protocol,waitTime) 101 | if msg then 102 | self:handleMessage(sender,msg,senderProtocol) 103 | else 104 | if self.onNoAnswer then 105 | self.onNoAnswer() 106 | end 107 | end 108 | return msg 109 | end 110 | function NetworkNode:handleEvent(event) 111 | if event and event[1] == "rednet_message" then 112 | --local name, sender, msg, senderProtocol = event 113 | self:handleMessage(event[2],event[3],event[4]) 114 | end 115 | end 116 | 117 | function NetworkNode:handleMessage(sender,msg,senderProtocol) 118 | if senderProtocol == self.protocol and msg then 119 | if msg.answer then 120 | if self.onRequestAnswer then 121 | --special handler exists 122 | self.onRequestAnswer(sender,msg,senderProtocol) 123 | else 124 | self:answer(sender,{"RECEIVED"},msg.task) 125 | end 126 | end 127 | 128 | if msg.type == default.typeSend or msg.type == default.typeBroadcast then 129 | self:beforeReceive(sender,msg,senderProtocol) 130 | if self.onReceive then 131 | self.onReceive(sender,msg,senderProtocol) 132 | end 133 | elseif msg.type == default.typeAnswer then 134 | if self.onAnswer then 135 | self.onAnswer(sender,msg,senderProtocol) 136 | end 137 | elseif msg.type == default.typeDone then 138 | --not yet implemted 139 | --callback if task is done 140 | if self.onDone then 141 | self:onDone(sender,msg,senderProtocol) 142 | end 143 | elseif msg.type == default.typeRegister then 144 | if self.registerNode then 145 | self:registerNode(sender,msg,senderProtocol) 146 | end 147 | end 148 | 149 | --DOESNT WORK PROPERLY! 150 | --new variable msg.done for requesting done event? 151 | if msg.answer then 152 | if self.onRequestDone then 153 | --special handler exists 154 | self.onRequestDone(sender,msg,senderProtocol) 155 | else 156 | self:sendDone(sender,{"DONE"},msg.task) 157 | end 158 | end 159 | --elseif senderProtocol == "dns" then 160 | --new friend 161 | end 162 | end 163 | 164 | function NetworkNode:sendDone(sender,data,answer) 165 | self:send(sender, data, default.typeDone, answer) 166 | end 167 | 168 | function NetworkNode:answer(sender,data,answer) 169 | rednet.send(sender, data, default.typeAnswer, false) 170 | end 171 | 172 | function NetworkNode:send(recipient,data,typ,answer) 173 | local retval 174 | if recipient ~= self.id then 175 | local msg = {} 176 | msg.type = typ 177 | msg.data = data 178 | msg.answer = answer 179 | rednet.send(recipient, msg, self.protocol) 180 | if answer then 181 | retval = self:listen(default.waitTime) 182 | end 183 | end 184 | return retval 185 | end 186 | 187 | function NetworkNode:broadcast(data,answer) 188 | local retval 189 | local msg = {} 190 | msg.type = default.typeBroadcast 191 | msg.data = data 192 | msg.answer = answer 193 | rednet.broadcast(msg, self.protocol) 194 | if answer then 195 | retval = self:listen(default.waitTime) 196 | end 197 | return retval 198 | end 199 | 200 | function NetworkNode:getHost() 201 | return self.host 202 | end 203 | 204 | function NetworkNode:lookupHost() 205 | self.host = rednet.lookup(self.protocol,"host") 206 | return self.host 207 | end 208 | 209 | function NetworkNode:lookup() 210 | self.host = rednet.lookup(self.protocol,"host") 211 | self.computers = {rednet.lookup(self.protocol)} 212 | end 213 | 214 | function NetworkNode:close() 215 | rednet.unhost(self.protocol) 216 | if rednet.isOpen() then 217 | rednet.close() 218 | end 219 | end -------------------------------------------------------------------------------- /old/classMap.lua: -------------------------------------------------------------------------------- 1 | local default = { 2 | bedrockLevel = -60, 3 | file = "runtime/map.txt", 4 | minHeight = -64, 5 | maxHeight = 320, 6 | } 7 | 8 | Map = {} 9 | 10 | function Map:new() 11 | local o = o or {} 12 | setmetatable(o, self) 13 | self.__index = self 14 | 15 | o.map = {} 16 | o.minedAreas = {} --TODO 17 | o.log = {} 18 | -- list of turtles: function: getNearestTurtle 19 | 20 | o:initialize() 21 | return o 22 | end 23 | 24 | function Map:initialize() 25 | --self:load() 26 | end 27 | 28 | function Map:load(fileName) 29 | if not fileName then fileName = default.file end 30 | local f = fs.open(fileName,"r") 31 | if f then 32 | self.map = textutils.unserialize( f.readAll() ) 33 | f.close() 34 | else 35 | print("FILE DOES NOT EXIST") 36 | end 37 | end 38 | 39 | function Map:save(fileName) 40 | if not fileName then fileName = default.file end 41 | local f = fs.open(fileName,"w") 42 | f.write(textutils.serialize(self.map)) 43 | f.close() 44 | end 45 | 46 | 47 | function Map:getMap() 48 | -- used for transferring map via rednet 49 | return { map = self.map, minedAreas = self.minedAreas } 50 | end 51 | function Map:setMap(map) 52 | self.map = map.map 53 | self.minedAreas = map.minedAreas 54 | end 55 | 56 | function Map:logData(x,y,z,data) 57 | table.insert(self.log,{x=x,y=y,z=z,data=data}) 58 | end 59 | function Map:readLog() 60 | return self.log 61 | end 62 | function Map:clearLog() 63 | self.log = {} 64 | end 65 | 66 | function Map:setData(x,y,z,data) 67 | --nil = not yet inspected 68 | --0 = inspected but empty or mined 69 | -- self:logData(x,y,z,data) -- logData is done by miner 70 | if not self.map then self.map = {} end 71 | --print(x,y,z,data) 72 | if y > default.bedrockLevel then 73 | self.map[self:xyzToId(x,y,z)] = data 74 | else 75 | self.map[self:xyzToId(x,y,z)] = -1 --bedrock 76 | end 77 | end 78 | 79 | function Map:getData(x,y,z) 80 | if y <= default.bedrockLevel then 81 | return -1 82 | else 83 | local id = self:xyzToId(x,y,z) 84 | if self.map then --and self.map[id] 85 | return self.map[id] 86 | end 87 | end 88 | return nil 89 | end 90 | 91 | function Map:clear() 92 | self.map = {} 93 | end 94 | 95 | function Map:posToId(pos) 96 | return self:xyzToId(pos.x, pos.y, pos.z) 97 | end 98 | function Map:xyzToId(x,y,z) 99 | -- dont use string IDs for Tables, instead use numbers 100 | -- Cantor pairing - natural numbers only to make it reversable 101 | 102 | --default.maxHeight - default.minHeight + 64 103 | 104 | --max length of id = 16 (then its 1.234234e23) 105 | -- x,y,z can be up to around 10000,320,10000 106 | -- if this is ever an issue, set the coordinates of turtles relative to their home 107 | 108 | if x < 0 then 109 | x = -x 110 | y = y + 448 111 | end 112 | if z < 0 then 113 | z = -z 114 | y = y + 896 115 | end 116 | y = y + 64 -- default.minHeight 117 | -------------------------------------------------------- 118 | local temp = 0.5 * ( x + y ) * ( x + y + 1 ) + y 119 | return 0.5 * ( temp + z ) * ( temp + z + 1 ) + z 120 | -------------------------------------------------------- 121 | end 122 | function Map:idToXYZ(id) 123 | local w = math.floor( ( math.sqrt( 8 * id + 1 ) - 1 ) / 2 ) 124 | local t = ( w^2 + w ) / 2 125 | local z = id - t 126 | local temp = w - z 127 | 128 | w = math.floor( ( math.sqrt( 8 * temp + 1 ) - 1 ) / 2 ) 129 | t = ( w^2 + w ) / 2 130 | local y = temp - t 131 | local x = w - y 132 | 133 | -- restore negative coordinates 134 | if y > 448 then 135 | -- x or z negative 136 | if y > 896 then 137 | -- z negative 138 | z = -z 139 | y = y - 896 140 | end 141 | if y > 448 then 142 | -- x negative 143 | x = -x 144 | y = y - 448 145 | end 146 | end 147 | y = y - 64 148 | 149 | return x,y,z 150 | end 151 | function Map:idToPos(id) 152 | local x,y,z = self:idToXYZ(id) 153 | return vector.new(x,y,z) 154 | end 155 | 156 | function Map:getDistance(start,finish) 157 | return math.sqrt( ( finish.x - start.x )^2 + ( finish.y - start.y )^2 + ( finish.z - start.z )^2 ) 158 | end 159 | 160 | function Map:findNextBlock(curPos, checkFunction, maxDistance) 161 | -- TODO if type(id) == "Table" then ... 162 | if not maxDistance then maxDistance = math.huge end 163 | -- local ores 164 | -- if not id then 165 | -- ores = oreBlocks 166 | -- elseif type(id) == "table" then 167 | -- ores = id 168 | -- else 169 | -- ores = { [id]=true } 170 | -- end 171 | 172 | local start = os.epoch("local") 173 | local ct = 0 174 | -- TODO: do not check entire table with pairs, only entries within maxDistance cube 175 | -- -> more performant with big maps 176 | local minDist = -1 177 | local minPos = nil 178 | 179 | if maxDistance <= 16 then 180 | -- still 32.768 positions to be checked 181 | local totalRange = (maxDistance*2)+1 182 | local halfRange = maxDistance+1 183 | for x=1,totalRange do 184 | for z=1,totalRange do 185 | for y=1, totalRange do 186 | local pos = vector.new(curPos.x-x+halfRange, 187 | curPos.y-y+halfRange, 188 | curPos.z-z+halfRange) 189 | local blockName = self:getData(pos.x, pos.y, pos.z) 190 | ct = ct +1 191 | if checkFunction(nil,blockName) then 192 | local dist = self:getDistance(curPos, pos) 193 | if ( minDist < 0 or dist < minDist) and dist <= maxDistance and dist > 0 then 194 | minDist = dist 195 | minPos = pos 196 | -- if minDist<=1 then 197 | -- -- cant be any more nearby 198 | -- break 199 | -- end 200 | end 201 | end 202 | end 203 | end 204 | end 205 | end 206 | print(os.epoch("local")-start, "findNextBlock", minPos, "count", ct) 207 | 208 | -- start = os.epoch("local") 209 | -- for key,value in pairs(self.map) do 210 | -- ct = ct + 1 211 | -- -- pass nil as self 212 | -- if checkFunction(nil,value) then 213 | -- local pos = self:idToPos(key) 214 | -- local dist = self:getDistance(curPos, pos) 215 | 216 | -- if ( minDist < 0 or dist < minDist) and dist <= maxDistance then 217 | -- minDist = dist 218 | -- minPos = pos 219 | -- end 220 | -- end 221 | -- end 222 | -- print(os.epoch("local")-start, "findNextBlock", minPos, "count", ct) 223 | return minPos 224 | end -------------------------------------------------------------------------------- /old/requireBluenetTable.lua: -------------------------------------------------------------------------------- 1 | 2 | -- bluenet, a modified rednet for better performance 3 | 4 | 5 | local bluenet = { 6 | 7 | default = { 8 | typeSend = 1, 9 | typeAnswer = 2, 10 | typeDone = 3, 11 | waitTime = 1, 12 | 13 | channels = { 14 | broadcast = 65401, 15 | repeater = 65402, 16 | host = 65403, 17 | max = 65400 18 | } 19 | }, 20 | --msg = { id, time, sender, recipient, protocol, type, data, answer, wait, distance} 21 | 22 | receivedMessages = {}, 23 | receivedTimer = nil, -- does that work? 24 | osEpoch = os.epoch, 25 | opened = false, 26 | modem = nil, 27 | ownChannel = nil, 28 | computerId = os.getComputerID(), 29 | 30 | idAsChannel = function(id) 31 | return (id or os.getComputerID()) % default.channels.max 32 | end, 33 | 34 | findModem = function() 35 | for _,modem in ipairs(peripheral.getNames()) do 36 | if peripheral.getType(modem) == "modem" then 37 | return modem 38 | end 39 | end 40 | return nil 41 | end, 42 | 43 | open = function(modem) 44 | if not opened then 45 | 46 | if not modem then 47 | print("NO MODEM") 48 | opened = false 49 | end 50 | peripheral.call(modem, "open", ownChannel) 51 | peripheral.call(modem, "open", default.channels.broadcast) 52 | print("opened",ownChannel,default.channels.broadcast) 53 | 54 | end 55 | opened = true 56 | return true 57 | end, 58 | 59 | close = function(modem) 60 | if modem then 61 | if peripheral.getType(modem) == "modem" then 62 | peripheral.call(modem, "close", ownChannel) 63 | peripheral.call(modem, "close", default.channels.broadcast) 64 | opened = false 65 | end 66 | else 67 | for _,modem in ipairs(peripheral.getNames()) do 68 | if isOpen(modem) then 69 | close(modem) 70 | end 71 | end 72 | end 73 | end, 74 | 75 | isOpen = function(modem) 76 | if modem then 77 | if peripheral.getType(modem) == "modem" then 78 | return peripheral.call(modem, "isOpen", ownChannel) 79 | and peripheral.call(modem, "isOpen", default.channels.broadcast) 80 | end 81 | else 82 | for _,modem in ipairs(peripheral.getNames()) do 83 | if isOpen(modem) then 84 | return true 85 | end 86 | end 87 | end 88 | return false 89 | end, 90 | 91 | openChannel = function(modem, channel) 92 | if not isChannelOpen(modem, channel) then 93 | if not modem then 94 | print("NO MODEM") 95 | return false 96 | end 97 | peripheral.call(modem, "open", channel) 98 | print("opened", channel) 99 | end 100 | return true 101 | end, 102 | 103 | closeChannel = function(modem, channel) 104 | if not modem then 105 | print("NO MODEM", modem) 106 | return false 107 | end 108 | if isChannelOpen(modem, channel) then 109 | return peripheral.call(modem, "close", channel) 110 | end 111 | return true 112 | end, 113 | 114 | isChannelOpen = function(modem, channel) 115 | if not modem then 116 | print("NO MODEM", modem) 117 | return false 118 | end 119 | return peripheral.call(modem, "isOpen", channel) 120 | end, 121 | 122 | -- local functions perhaps outside bluenet? -> no apparently doesnt matter 123 | startTimer = os.startTimer, 124 | cancelTimer = os.cancelTimer, 125 | osClock = os.clock, 126 | timerClocks = {}, 127 | timers = {}, 128 | pullEventRaw = os.pullEventRaw, 129 | type = type, 130 | 131 | receive = function(protocol, waitTime) 132 | local timer = nil 133 | local eventFilter = nil 134 | 135 | -- CAUTION: if bluenet is loaded globally, 136 | -- TODO: the timers must be distinguished by protocol/coroutine 137 | -- leads to host being unable to reboot!!! 138 | 139 | if waitTime then 140 | local t = osClock() 141 | if timerClocks[waitTime] ~= t then 142 | --cancel the previous timer and create a new one 143 | cancelTimer((timers[waitTime] or 0)) 144 | timer = startTimer(waitTime) 145 | --print( protocol, "cancelled", timers[waitTime], "created", timer, "diff", timer - (timers[waitTime]or 0)) 146 | timerClocks[waitTime] = t 147 | timers[waitTime] = timer 148 | else 149 | timer = timers[waitTime] 150 | --print( protocol, "reusing", timer) 151 | end 152 | 153 | eventFilter = nil 154 | else 155 | eventFilter = "modem_message" 156 | end 157 | 158 | --print("receiving", protocol, waitTime, timer, eventFilter) 159 | while true do 160 | local event, modem, channel, sender, msg, distance = pullEventRaw(eventFilter) 161 | --if event == "modem_message" then print(os.clock(),event, modem, channel, sender) end 162 | 163 | if event == "modem_message" 164 | --and ( channel == ownChannel or channel == default.channels.broadcast 165 | -- or channel == default.channels.host ) 166 | and type(msg) == "table" 167 | --and type(msg.id) == "number" and not receivedMessages[msg.id] 168 | and ( type(msg.recipient) == "number" and msg.recipient 169 | and ( msg.recipient == computerId or msg.recipient == default.channels.broadcast 170 | or msg.recipient == default.channels.host ) ) 171 | and ( protocol == nil or protocol == msg.protocol ) 172 | -- just to make sure its a bluenet message 173 | then 174 | msg.distance = distance 175 | -- event, modem, channel, replyChannel, message, distance 176 | --print("received", msg.id, msg.protocol) 177 | --receivedMessages[msg.id] = os.clock() + 9.5 178 | --resetTimer() 179 | --cancelTimer(timer) 180 | -- if osEpoch() > t then 181 | -- print("cancel old timer") 182 | -- cancelTimer(timer) 183 | -- end 184 | return msg 185 | 186 | elseif event == "timer" then 187 | --print(os.clock(),event, modem, channel, sender, timer) 188 | 189 | if modem == timer then -- must be equal! >= geht nicht 190 | --print("returning nil") 191 | return nil 192 | end 193 | elseif event == "terminate" then 194 | error("Terminated",0) 195 | end 196 | 197 | end 198 | 199 | end, 200 | 201 | resetTimer = function() 202 | if not receivedTimer then receivedTimer = os.startTimer(10) end 203 | end, 204 | 205 | clearReceivedMessages = function() 206 | receivedTimer = nil 207 | local time, hasMore = os.clock(), nil 208 | for id, deadline in pairs(receivedMessages) do 209 | if deadline <= now then receivedMessages[id] = nil 210 | else hasMore = true end 211 | end 212 | receivedTimer = hasMore and os.startTimer(10) 213 | end, 214 | 215 | modem = findModem(), 216 | ownChannel = idAsChannel(), 217 | 218 | } 219 | return bluenet -------------------------------------------------------------------------------- /test/testMonitor.lua: -------------------------------------------------------------------------------- 1 | --Includes 2 | 3 | require("classMonitor") 4 | require("classButton") 5 | require("classGPU") 6 | require("classBox") 7 | require("classToggleButton") 8 | require("classFrame") 9 | require("classLabel") 10 | require("classNetworkNode") 11 | require("classCheckBox") 12 | require("classWindow") 13 | require("classMap") 14 | require("classMapDisplay") 15 | require("classTurtleControl") 16 | 17 | --Functions 18 | 19 | --Declaration 20 | monitor = global.monitor 21 | node = global.node 22 | nodeUpdate = global.nodeUpdate 23 | nodeStatus = global.nodeStatus 24 | map = global.map 25 | lastUpdates = global.lastUpdates 26 | 27 | --Initialization 28 | 29 | local x = 0 30 | local time = 0 31 | 32 | --Code 33 | local winMain = Window:new(1,1) 34 | monitor:addObject(winMain) 35 | --winMain:setWidth(monitor:getWidth()) 36 | winMain:fillParent() 37 | 38 | box = Box:new(18,7,5,5,colors.white) 39 | winMain:addObject(box) 40 | box:setWidth(15) 41 | winMain:removeObject(box) 42 | box = nil 43 | 44 | frmText = Frame:new("Data",22,4,20,20,colors.lightGray) 45 | winMain:addObject(frmText) 46 | 47 | 48 | lblTime = Label:new("Time:",24,6) 49 | winMain:addObject(lblTime) 50 | lblTimeVal = Label:new("0",30,6) 51 | winMain:addObject(lblTimeVal) 52 | 53 | lblID = winMain:addObject(Label:new("ID: " .. os.getComputerID(),24,8)) 54 | 55 | btnCheck = CheckBox:new(24,10, "print status", global.printStatus) 56 | winMain:addObject(btnCheck) 57 | btnCheck.click = function() 58 | global.printStatus = btnCheck.active 59 | end 60 | 61 | frmBtn = Frame:new("Functions",1,4,20,20,colors.gray) 62 | winMain:addObject(frmBtn) 63 | 64 | btnMap = Button:new("Map",3,6) 65 | winMain:addObject(btnMap) 66 | 67 | btnTurtles = Button:new("Turtles",3,10) 68 | winMain:addObject(btnTurtles) 69 | 70 | 71 | -- example Toggle Button 72 | -- btnToggle = ToggleBtn:new(3,14) 73 | -- winMain:addObject(btnToggle) 74 | 75 | -- example disabled Button 76 | -- btnDisabled = Button:new("Disabled",3,6) 77 | -- winMain:addObject(btnDisabled) 78 | -- btnDisabled:setEnabled(false) 79 | 80 | 81 | btnCount = winMain:addObject(Button:new("0",3,18,10,3,colors.purple)) 82 | btnCount:setEnabled(true) 83 | btnCount.click = function() 84 | local ct = tonumber(btnCount.text) + 1 85 | btnCount:setText(tostring(ct)) 86 | end 87 | 88 | btnStop = Button:new("STOP",monitor:getWidth()-9, 1, 10,3,colors.red) 89 | winMain:addObject(btnStop) 90 | btnStop.click = function() 91 | global.running = false 92 | end 93 | 94 | 95 | btnReboot = winMain:addObject(Button:new("REBOOT", monitor:getWidth()-9,4,11,3,colors.blue)) 96 | btnReboot.click = function() 97 | monitor.clear() 98 | monitor.setCursorPos((monitor:getWidth()-10)/2,monitor:getHeight()/2) 99 | monitor.write("REBOOTING") 100 | node:broadcast({"REBOOT"},true) 101 | --global.map:save() 102 | os.reboot() 103 | --edit startup 104 | end 105 | 106 | btnAddTask = winMain:addObject(Button:new("addTask",44,8,11,3,colors.purple)) 107 | btnRemoveTask = winMain:addObject(Button:new("removeTask",44,12,11,3,colors.purple)) 108 | btnReturnHome = winMain:addObject(Button:new("returnHome",44,16,11,3,colors.yellow)) 109 | 110 | local taskId = -1 111 | 112 | btnAddTask.click = function() 113 | print("SENT") 114 | -- local msg, task = node:addTask(1, "testMine") 115 | -- if task then 116 | -- print("sent task", task.taskId) 117 | -- taskId = task.taskId 118 | -- end 119 | -- if msg then print(msg.type, msg.data[1]) end 120 | --local msg = node:broadcast({"DO","error",{"test",false}},true) 121 | --local msg = node:broadcast({"DO","navigateToPos",{275, 70, -177}},true) 122 | local msg = node:broadcast({"DO","transferItems"},true) 123 | --local msg = node:broadcast({"DO","turnTo",{1}},true) 124 | --local msg = node:broadcast({"RUN","testMine",{"1",2}},true) 125 | if msg then 126 | print(msg.type, msg.data[1]) 127 | end 128 | end 129 | 130 | btnRemoveTask.click = function() 131 | local task = node:removeTask(taskId) 132 | if not task then 133 | print("deleted successfully") 134 | else 135 | print("task not deleted") 136 | end 137 | end 138 | 139 | local mapDisplay 140 | mapDisplay = MapDisplay:new(4,4,32,16) 141 | mapDisplay:setMid(275, 70, -177) 142 | mapDisplay:setMap(map) 143 | 144 | btnMap.click = function() 145 | -- display Map 146 | 147 | monitor:addObject(mapDisplay) 148 | mapDisplay:fillParent() 149 | map:setData(275,70,-177,"aaa") 150 | monitor:redraw() 151 | return true 152 | end 153 | 154 | 155 | 156 | 157 | 158 | 159 | -- Turtle Management 160 | -- needed vars 161 | winTurtles = Window:new() 162 | lblTurtles = Label:new("Turtles",1,1) 163 | winTurtles:addObject(lblTurtles) 164 | turtleControls = {} 165 | turtleCt = 0 166 | local function refreshTurtles() 167 | for sender,msg in pairs(lastUpdates) do 168 | if not turtleControls[sender] then 169 | turtleControls[sender] = TurtleControl:new(1,3+6*turtleCt,msg.status,global.node) 170 | winTurtles:addObject(turtleControls[sender]) 171 | turtleControls[sender]:fillWidth() 172 | turtleCt = turtleCt + 1 173 | else 174 | turtleControls[sender]:setData(msg.status) 175 | end 176 | end 177 | winTurtles:redraw() 178 | end 179 | 180 | 181 | btnTurtles.click = function() 182 | monitor:addObject(winTurtles) 183 | winTurtles:fillParent() 184 | for _,turtleControl in pairs(turtleControls) do 185 | turtleControl:fillWidth() 186 | end 187 | refreshTurtles() 188 | monitor:redraw() 189 | return true 190 | end 191 | 192 | 193 | 194 | btnReturnHome.click = function() 195 | -- call mine home 196 | print("SENT") 197 | local msg = node:broadcast({"DO","returnHome"},true) 198 | if msg then 199 | print(msg.type, msg.data[1]) 200 | end 201 | end 202 | 203 | monitor:redraw() -- draw initial monitor 204 | 205 | local function updateTime() 206 | time = time + 1 207 | if time%1 == 0 then 208 | lblTimeVal:setText(time/20) 209 | --lblTimeVal:redraw() 210 | end 211 | --to remove blinking http://www.computercraft.info/forums2/index.php?/topic/22397-surface-api-162/ 212 | end 213 | 214 | local wasWindowVisible = true 215 | 216 | while global.running do 217 | 218 | monitor:checkEvents() 219 | 220 | if mapDisplay and mapDisplay.visible then 221 | winMain:setVisible(false) 222 | wasWindowVisible = winMain.visible 223 | elseif wasWindowVisible == false then 224 | winMain:setVisible(true) 225 | wasWindowVisible = winMain.visible 226 | monitor:redraw() 227 | end 228 | updateTime() 229 | if time%5 == 0 and mapDisplay then 230 | mapDisplay:checkUpdates() 231 | refreshTurtles() 232 | end 233 | 234 | sleep(0.05) 235 | 236 | end 237 | 238 | 239 | 240 | monitor.clear() 241 | monitor.setCursorPos((monitor:getWidth()-10)/2,monitor:getHeight()/2) 242 | monitor.write("TERMINATED") 243 | print("TERMINATED") 244 | -------------------------------------------------------------------------------- /test/bluenet_local_instance.lua: -------------------------------------------------------------------------------- 1 | 2 | package.path = package.path ..";../general/?.lua" --";../runtime/?.lua" 3 | 4 | local required = require("bluenet") 5 | os.loadAPI("old/bluenet.lua") 6 | local bluenet = bluenet 7 | require("classBluenetNode") 8 | 9 | local tinsert = table.insert 10 | 11 | local resetTimer = bluenet.resetTimer 12 | NetworkNode.resetTimer = bluenet.resetTimer 13 | 14 | local node = NetworkNode:new("test", true) 15 | --node.resetTimer = bluenet.resetTimer 16 | 17 | 18 | local computerId = os.getComputerID() 19 | local protocol = "joo" 20 | local eventFilter = "modem_message" 21 | local pullEventRaw = os.pullEventRaw 22 | local side = bluenet.findModem() 23 | 24 | 25 | local function handle(event) 26 | local p1, p2, p3, msg, p5 = event[1], event[2], event[3], event[4], event[5] 27 | if --( p2 == ownChannel or p2 == channelBroadcast ) 28 | type(msg) == "table" 29 | 30 | then 31 | --local recipient = msg.recipient 32 | if ( msg.recipient and type(msg.recipient) == "number" 33 | and ( msg.recipient == computerId or msg.recipient == channelBroadcast 34 | or msg.recipient == channelHost ) ) 35 | then 36 | msg.distance = p5 37 | local protocol = msg.protocol 38 | if protocol == "miner_stream" then 39 | --and ( not msg.data or msg.data[1] ~= "STREAM_OK" ) then 40 | node:handleMessage(msg) 41 | 42 | elseif protocol == "miner" or protocol == "chunk" then 43 | node:handleMessage(msg) 44 | end 45 | end 46 | elseif p1 == "terminate" then 47 | error("Terminated",0) 48 | end 49 | end 50 | 51 | local function testBluenetVariants(node, iterations) 52 | local osEpoch = os.epoch -- Cache os.epoch for performance 53 | local startTime = osEpoch("utc") -- Start time for the test 54 | for i = 1, iterations do 55 | bluenet.resetTimer() 56 | end 57 | local endTime = osEpoch("utc") -- End time for the test 58 | print("local global", endTime - startTime, "ms for", iterations, "iterations") 59 | 60 | local startTime = osEpoch("utc") -- Start time for the test 61 | for i = 1, iterations do 62 | required.resetTimer() 63 | end 64 | local endTime = osEpoch("utc") -- End time for the test 65 | print("required", endTime - startTime, "ms for", iterations, "iterations") 66 | 67 | local startTime = osEpoch("utc") -- Start time for the test 68 | for i = 1, iterations do 69 | resetTimer() 70 | end 71 | local endTime = osEpoch("utc") -- End time for the test 72 | print("node", endTime - startTime, "ms for", iterations, "iterations") 73 | 74 | local event = { 75 | "modem_message", 76 | side, 77 | protocol, 78 | protocol, 79 | { 80 | protocol = protocol, 81 | sender = computerId, 82 | distance = 0, 83 | recipient = computerId, 84 | data = { "test" }, 85 | }, 86 | 0 87 | } 88 | local msg = { 89 | protocol = protocol, 90 | sender = computerId, 91 | distance = 0, 92 | recipient = computerId, 93 | data = { "test" }, 94 | } 95 | 96 | local startTime = osEpoch("utc") -- Start time for the test 97 | for i = 1, iterations do 98 | --node:handleMessage(msg) 99 | --node:handleEvent(event) 100 | handle(event) 101 | end 102 | local endTime = osEpoch("utc") -- End time for the test 103 | print("node", endTime - startTime, "ms for", iterations, "iterations") 104 | 105 | end 106 | 107 | 108 | 109 | testBluenetVariants(node, 10000000) 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | local startTimer = os.startTimer 127 | local cancelTimer = os.cancelTimer 128 | local osClock = os.clock 129 | local timerClocks = {} 130 | local timers = {} 131 | local pullEventRaw = os.pullEventRaw 132 | local type = type 133 | 134 | --local timings = { [protocol] = { clocks = {}, timers = {} }} 135 | --timerClocks[protocol] = {} 136 | --timers[protocol] = {} 137 | 138 | local function timerTest(protocol, waitTime) 139 | local timer = nil 140 | local eventFilter = nil 141 | 142 | -- CAUTION: if bluenet is loaded globally, 143 | -- TODO: the timers must be distinguished by protocol/coroutine 144 | -- leads to host being unable to reboot!!! 145 | 146 | if waitTime then 147 | local t = osClock() 148 | --print(timerClocks[protocol]) 149 | --local clocks, tmrs = timings[protocol].clocks, timings[protocol].timers 150 | local clocks, tmrs = timerClocks[protocol], timers[protocol] 151 | if not clocks then 152 | clocks = {} 153 | tmrs = {} 154 | timerClocks[protocol] = clocks 155 | timers[protocol] = tmrs 156 | end 157 | if clocks[waitTime] ~= t then 158 | --cancel the previous timer and create a new one 159 | cancelTimer((tmrs[waitTime] or 0)) 160 | timer = startTimer(waitTime) 161 | print( protocol, "cancelled", timers[protocol][waitTime], "created", timer, "diff", timer - (timers[waitTime]or 0)) 162 | clocks[waitTime] = t 163 | tmrs[waitTime] = timer 164 | else 165 | timer = tmrs[waitTime] 166 | --print( protocol, "reusing", timer) 167 | end 168 | end 169 | end 170 | 171 | local clocks = {} 172 | local tmrs = {} 173 | 174 | local function timerTestNormal(protocol, waitTime) 175 | local timer = nil 176 | local eventFilter = nil 177 | 178 | -- CAUTION: if bluenet is loaded globally, 179 | -- TODO: the timers must be distinguished by protocol/coroutine 180 | -- leads to host being unable to reboot!!! 181 | 182 | if waitTime then 183 | local t = osClock() 184 | --print(timerClocks[protocol]) 185 | if clocks[waitTime] ~= t then 186 | --cancel the previous timer and create a new one 187 | cancelTimer((tmrs[waitTime] or 0)) 188 | timer = startTimer(waitTime) 189 | print( protocol, "cancelled", tmrs[waitTime], "created", timer, "diff", timer - (timers[waitTime] or 0)) 190 | clocks[waitTime] = t 191 | tmrs[waitTime] = timer 192 | else 193 | timer = tmrs[waitTime] 194 | --print( protocol, "reusing", timer) 195 | end 196 | end 197 | end 198 | 199 | 200 | 201 | local function testTimerPerformance(iterations) 202 | local osEpoch = os.epoch -- Cache os.epoch for performance 203 | local startTime = osEpoch("utc") -- Start time for the test 204 | local protocol = protocol 205 | for i = 1, iterations do 206 | timerTest(protocol, 3) -- Call the timerTest function 207 | end 208 | 209 | local endTime = osEpoch("utc") -- End time for the test 210 | print("Test completed in", endTime - startTime, "ms for", iterations, "iterations") 211 | 212 | local startTime = osEpoch("utc") -- Start time for the test 213 | for i = 1, iterations do 214 | timerTestNormal(protocol, 3) -- Call the timerTest function 215 | end 216 | local endTime = osEpoch("utc") -- End time for the test 217 | print("Test completed in", endTime - startTime, "ms for", iterations, "iterations") 218 | 219 | end 220 | 221 | --testTimerPerformance(1000000) -------------------------------------------------------------------------------- /turtle/receive.lua: -------------------------------------------------------------------------------- 1 | 2 | local node = global.node 3 | local nodeStream = global.nodeStream 4 | local tasks = global.tasks 5 | local miner = global.miner 6 | local nodeRefuel = global.nodeRefuel 7 | local nodeStorage = global.nodeStorage 8 | local config = config 9 | 10 | local bluenet = require("bluenet") 11 | local ownChannel = bluenet.ownChannel 12 | local channelBroadcast = bluenet.default.channels.broadcast 13 | local channelHost = bluenet.default.channels.host 14 | local channelRefuel = bluenet.default.channels.refuel 15 | local channelStorage = bluenet.default.channels.storage 16 | local computerId = os.getComputerID() 17 | local osEpoch = os.epoch 18 | 19 | 20 | 21 | 22 | -- ################ start refueling logic 23 | 24 | -- dont use answers, because more than one response is possible 25 | nodeRefuel.onRequestAnswer = nil 26 | nodeRefuel.onAnswer = nil 27 | 28 | nodeRefuel.onReceive = function(msg) 29 | local refuelClaim = miner.refuelClaim 30 | 31 | if msg.data[1] == "OCCUPIED_STATION" then 32 | local occupiedId = msg.data[2] 33 | local station = config.stations.refuel[occupiedId] 34 | if station then 35 | station.occupied = true 36 | station.lastClaimed = msg.data.lastClaimed 37 | else 38 | -- station is not in config 39 | end 40 | 41 | elseif msg.data[1] == "CLAIM_ACK" then 42 | if msg.data.owner then 43 | -- approved by current owner of the station, ignore others denying it 44 | print("OWNER ACK", msg.sender, msg.data[1], msg.data[2]) 45 | refuelClaim.approvedByOwner = true 46 | end 47 | 48 | elseif msg.data[1] == "CLAIM_DENY" then 49 | -- print(msg.sender, msg.data[1], msg.data[2]) 50 | local id = msg.data[2] 51 | if id == refuelClaim.occupiedStation then 52 | refuelClaim.ok = false 53 | end 54 | 55 | elseif msg.data[1] == "REQUEST_STATION" then 56 | if refuelClaim.occupiedStation then 57 | nodeRefuel:send(msg.sender, {"OCCUPIED_STATION", 58 | refuelClaim.occupiedStation, 59 | lastClaimed = refuelClaim.lastClaimed}) 60 | --elseif refuelClaim.waiting then 61 | -- nodeRefuel:answer(forMsg, {"WAITING", priority = refuelClaim.priority}) 62 | end 63 | 64 | elseif msg.data[1] == "CLAIM_STATION" then 65 | local id = msg.data[2] 66 | local lastClaimed = osEpoch("utc") 67 | local station = config.stations.refuel[id] 68 | 69 | if station and id ~= refuelClaim.occupiedStation then 70 | station.occupied = true 71 | station.lastClaimed = lastClaimed 72 | -- nodeRefuel:send(msg.sender, {"CLAIM_ACK", id}) -- normal ACK not needed 73 | elseif id == refuelClaim.occupiedStation then 74 | if not refuelClaim.waiting and refuelClaim.isReleasing then 75 | -- if done refueling, pass station to first waiting turtle 76 | refuelClaim.isReleasing = false 77 | station.occupied = true 78 | station.lastClaimed = lastClaimed 79 | nodeRefuel:send(msg.sender, {"CLAIM_ACK", id, owner = true}) 80 | --print("send ack owner", id) 81 | else 82 | -- station is occupied by self 83 | nodeRefuel:send(msg.sender, {"CLAIM_DENY", id}) 84 | -- print("send deny", id, msg.sender) 85 | end 86 | else 87 | print("i have no station", refuelClaim.occupiedStation, id) 88 | end 89 | 90 | 91 | elseif msg.data[1] == "RELEASE_STATION" then 92 | local id = msg.data[2] 93 | local station = config.stations.refuel[id] 94 | if station then 95 | station.occupied = false 96 | 97 | -- OPTI: check if miner is looking for station? seems to work fine without 98 | --local refuelClaim = miner.refuelClaim 99 | --if refuelClaim.waiting then 100 | -- miner:tryClaimStation() 101 | --end 102 | end 103 | end 104 | end 105 | 106 | -- ################ end refueling logic 107 | 108 | nodeStorage.onReceive = function(msg) 109 | if msg.data[1] == "GET_TURTLE_STATE" then 110 | -- dont even respond if miner is not initialized 111 | if miner and miner.pos then 112 | local state = {} 113 | state.id = computerId 114 | state.label = os.getComputerLabel() or computerId 115 | 116 | state.pos = miner.pos 117 | state.orientation = miner.orientation 118 | state.stuck = miner.stuck -- can be nil 119 | 120 | state.fuelLevel = miner:getFuelLevel() 121 | state.emptySlots = miner:getEmptySlots() 122 | 123 | if miner.taskList.first then 124 | state.task = miner.taskList.first[1] 125 | state.lastTask = miner.taskList.last[1] 126 | end 127 | nodeStorage:send(msg.sender, {"TURTLE_STATE", state }) 128 | end 129 | elseif msg.data[1] == "DO" then 130 | -- e.g. pickupanddeliver items 131 | table.insert(tasks, msg.data) 132 | --nodeStorage:answer(forMsg, {"DO_ACK"}) -- oder so 133 | end 134 | end 135 | 136 | nodeStream.onStreamMessage = function(msg,previous) 137 | -- reboot is handled in NetworkNode 138 | nodeStream._clearLog() 139 | 140 | --local start = os.epoch("local") 141 | local ct = 0 142 | if msg and msg.data and msg.data[1] == "MAP_UPDATE" then 143 | if miner then 144 | local mapLog = msg.data[2] 145 | for i = 1, #mapLog do 146 | local entry = mapLog[i] 147 | 148 | --for _,entry in ipairs(mapLog) do 149 | -- setData without log 150 | -- setChunkData should not result in the chunk being requested! 151 | miner.map:setChunkData(entry[1],entry[2],entry[3],false) 152 | ct = ct + 1 153 | end 154 | end 155 | end 156 | --print(os.epoch("local")-start,"onStream", ct) 157 | end 158 | 159 | node.onReceive = function(msg) 160 | -- reboot is handled in NetworkNode 161 | if msg and msg.data then 162 | if msg.data[3] then 163 | --print("received:", msg.data[1], msg.data[2], unpack(msg.data[3])) 164 | else 165 | --print("received:", msg.data[1], msg.data[2]) 166 | end 167 | 168 | if msg.data[1] == "STOP" then 169 | if miner then 170 | miner.stop = true 171 | end 172 | else 173 | table.insert(tasks, msg.data) 174 | end 175 | end 176 | end 177 | 178 | local pullEventRaw = os.pullEventRaw 179 | local type = type 180 | 181 | while true do 182 | 183 | local event, p1, p2, p3, msg, p5 = pullEventRaw("modem_message") 184 | if --( p2 == ownChannel or p2 == channelBroadcast ) 185 | type(msg) == "table" 186 | and ( type(msg.recipient) == "number" and msg.recipient 187 | and ( msg.recipient == computerId or msg.recipient == channelBroadcast 188 | or msg.recipient == channelHost or msg.recipient == channelRefuel 189 | or msg.recipient == channelStorage ) ) 190 | then 191 | msg.distance = p5 192 | local protocol = msg.protocol 193 | if protocol == "miner_stream" then 194 | --and ( not msg.data or msg.data[1] ~= "STREAM_OK" ) then 195 | nodeStream:handleMessage(msg) 196 | 197 | elseif protocol == "miner" or protocol == "chunk" then -- chunk optional 198 | node:handleMessage(msg) 199 | elseif protocol == "refuel" then 200 | nodeRefuel:handleMessage(msg) 201 | elseif protocol == "storage" or protocol == "storage_priority" then 202 | nodeStorage:handleMessage(msg) 203 | end 204 | elseif event == "terminate" then 205 | error("Terminated",0) 206 | end 207 | 208 | end -------------------------------------------------------------------------------- /old/pathFindingOld.lua: -------------------------------------------------------------------------------- 1 | function Miner:aStarSLOW(startPos, startOrientation, goal, nodes, checkValidNodeFunc) 2 | local closedSet = {} 3 | local openSet = { { pos = startPos, orientation = startOrientation } } 4 | local predecessors = {} 5 | 6 | if checkValidNodeFunc then self.checkValidNode = checkValidNodeFunc end 7 | 8 | local gScore, fScore = {}, {} 9 | local strPosStart = self:posToString(startPos) 10 | gScore[strPosStart] = 0 11 | fScore[strPosStart] = gScore[strPosStart] + self:calculateHeuristic(startPos,goal) 12 | 13 | local i = 0 14 | local logBook = {} 15 | 16 | while #openSet > 0 do 17 | i = i + 1 18 | 19 | -- problem: removeNode, findNode, getLowestScore 20 | 21 | local current = self:getLowestScore(openSet, fScore) 22 | table.insert(logBook, tostring(current.pos)) 23 | 24 | if current.pos == goal then 25 | local path = self:reconstructPath( {}, predecessors, goal) 26 | table.insert(path,goal) 27 | print("FOUND PATH, MOVES:", #path, "ITERATIONS:", i) 28 | 29 | 30 | 31 | return path 32 | end 33 | 34 | self:removeNode(openSet, current) 35 | table.insert(closedSet, current) 36 | 37 | local neighbours = self:getNeighbours(current, nodes) 38 | for _, neighbour in ipairs(neighbours) do 39 | --table.insert(logBook, "nei " .. tostring(neighbour.pos)) 40 | if not self:findNode(closedSet, neighbour) then 41 | local strPosNeighbour = self:posToString(neighbour.pos) 42 | local tentativeGScore = gScore[self:posToString(current.pos)] + self:calculateCost(current,neighbour) 43 | local notInOpenSet = ( self:findNode(openSet, neighbour) == false ) 44 | 45 | if notInOpenSet == true or tentativeGScore < gScore[strPosNeighbour] then 46 | predecessors[strPosNeighbour] = current.pos --add orientation if needed 47 | gScore[strPosNeighbour] = tentativeGScore 48 | fScore[strPosNeighbour] = gScore[strPosNeighbour] + self:calculateHeuristic(neighbour.pos,goal) 49 | if notInOpenSet == true then 50 | table.insert(openSet, neighbour) 51 | end 52 | end 53 | end 54 | end 55 | if i > 1000000 then 56 | print("NO PATH FOUND") 57 | return nil 58 | end 59 | end 60 | return nil 61 | end 62 | --############################################ 63 | function Miner:aStarFAST(startPos, startOrientation, finishPos, map, checkValidNodeFunc) 64 | 65 | if checkValidNodeFunc then self.checkValidNode = checkValidNodeFunc end 66 | 67 | local start = { pos = startPos, orientation = startOrientation } 68 | local finish = { pos = finishPos } 69 | 70 | start.gScore = 0 71 | start.hScore = self:calculateHeuristic(start.pos, finish.pos) 72 | start.fScore = start.hScore 73 | 74 | local open = Heap() 75 | local closed = {} 76 | open.Compare = function(a,b) 77 | return a.fScore < b.fScore 78 | end 79 | open:Push(start) 80 | 81 | local logBook = {} 82 | 83 | 84 | local ct = 0 85 | 86 | while not open:Empty() do 87 | ct = ct + 1 88 | 89 | local current = open:Pop() 90 | 91 | local currentId = self:posToId(current.pos) 92 | if not closed[currentId] then 93 | if current.pos == finish.pos then 94 | local path = {} 95 | while true do 96 | if current.previous then 97 | table.insert(path, 1, current) 98 | current = current.previous 99 | else 100 | table.insert(path, 1, start) 101 | print("FOUND PATH, MOVES:", #path, "ITERATIONS:", ct) 102 | return path 103 | end 104 | end 105 | end 106 | closed[currentId] = true 107 | --print(current.pos, current.gScore, current.hScore, current.fScore) 108 | 109 | --works BUT neighbours does not work properly because when having the same "neighbour" the addresses are different. 110 | --must create connection with map! -> store 111 | 112 | local neighbours = self:getNeighbours(current, map) 113 | for i=1, #neighbours do 114 | local neighbour = neighbours[i] 115 | if not closed[self:posToId(neighbour.pos)] then 116 | local addedGScore = current.gScore + self:calculateCost(current,neighbour) 117 | if not neighbour.gScore or addedGScore < neighbour.gScore then 118 | neighbour.gScore = addedGScore 119 | 120 | if not neighbour.hScore then 121 | neighbour.hScore = self:calculateHeuristic(neighbour.pos,finish.pos) 122 | end 123 | neighbour.fScore = addedGScore + neighbour.hScore 124 | 125 | open:Push(neighbour) 126 | neighbour.previous = current 127 | end 128 | end 129 | end 130 | end 131 | if ct > 1000000 then 132 | print("NO PATH FOUND") 133 | return nil 134 | end 135 | if ct%10000 == 0 then 136 | --print(ct) -- to avoid timeout 137 | sleep(0.001) 138 | end 139 | end 140 | return nil 141 | --https://github.com/GlorifiedPig/Luafinding/blob/master/src/luafinding.lua 142 | -- noch besser ? https://www.love2d.org/wiki/Jumper 143 | end 144 | 145 | function Miner:findNode(set, fNode) 146 | for _, node in ipairs(set) do 147 | if node.pos == fNode.pos then 148 | return true 149 | end 150 | end 151 | return false 152 | end 153 | 154 | function Miner:removeNode(set, rNode) 155 | for i, node in ipairs(set) do 156 | if node == rNode then 157 | set [ i ] = set [ #set ] --move last entry to current to avoid holes 158 | set [ #set ] = nil 159 | break 160 | end 161 | end 162 | end 163 | function Miner:getLowestScore(set,fScore) 164 | -- performance ... Fibonacci Heap besser 165 | local minScore, minNode = math.huge, nil 166 | for _, node in ipairs(set) do 167 | local score = fScore[self:posToString(node.pos)] 168 | if score < minScore then 169 | minScore = score 170 | minNode = node 171 | end 172 | end 173 | return minNode 174 | end 175 | 176 | 177 | function Miner:breadthFirstSearch(startPos, startOrientation, goal, nodes) 178 | -- optimal path for short distances, not weighted 179 | -- e.g. veinMine 180 | local queue = { { pos = startPos, orientation = startOrientation } } 181 | local explored = {} 182 | local predecessors = {} 183 | explored[self:posToString(startPos)] = true 184 | 185 | local i = 0 186 | 187 | while #queue > 0 do 188 | i = i + 1 189 | 190 | local current = table.remove(queue,1) 191 | if current.pos == goal then 192 | local path = self:reconstructPath( {}, predecessors, goal) 193 | table.insert(path,goal) 194 | print("FOUND PATH, MOVES:", #path, "ITERATIONS:", i) 195 | return path 196 | end 197 | 198 | local neighbours = self:getNeighbours(current, nodes) 199 | for _, neighbour in ipairs(neighbours) do 200 | local blockName = self:getMapValue(neighbour.pos.x, neighbour.pos.y, neighbour.pos.z) 201 | 202 | local strPosNeighbour = self:posToString(neighbour.pos) 203 | if not explored[strPosNeighbour] then --and (not map or map[strPosNeighbour] 204 | explored[strPosNeighbour] = true 205 | predecessors[strPosNeighbour] = current.pos 206 | table.insert(queue, neighbour) 207 | end 208 | end 209 | if i > 1000000 then 210 | print("NO PATH FOUND") 211 | return nil 212 | end 213 | if i%1000 == 0 then 214 | sleep(0.001) 215 | end 216 | end 217 | return nil 218 | end -------------------------------------------------------------------------------- /host/hostTransfer.lua: -------------------------------------------------------------------------------- 1 | 2 | local osEpoch = os.epoch 3 | 4 | local function importFile(fileName, fileData) 5 | 6 | if fs.exists(fileName) then 7 | fs.delete(fileName) 8 | end 9 | file = fs.open(fileName, "w") 10 | file.write(fileData) 11 | file.close() 12 | 13 | end 14 | 15 | local function handleAnswer(msg,forMsg) 16 | if msg and msg.data then 17 | local i = 0 18 | if msg.data[1] == "FILE" then 19 | i = i + 1 20 | print(i, "RECEIVED",msg.data[2].name) 21 | importFile(msg.data[2].name, msg.data[2].data) 22 | elseif msg.data[1] == "FOLDERS" then 23 | local start = osEpoch("utc") 24 | for folderName, folder in pairs(msg.data[2]) do 25 | if fs.isDir(folderName) then 26 | fs.delete(folderName) 27 | end 28 | for fileName,file in pairs(folder) do 29 | importFile(folderName.."/"..fileName, file.data) 30 | i = i + 1 31 | print(i, "RECEIVED", folderName.."/"..fileName) 32 | if osEpoch("utc") - start > 1000 then 33 | print("IMPORTED", i, "FILES") 34 | start = osEpoch("utc") 35 | sleep(0) 36 | end 37 | end 38 | end 39 | else 40 | print(msg.data[1], textutils.serialize(msg.data[2])) 41 | return false 42 | end 43 | end 44 | return true 45 | end 46 | 47 | local function transferFiles(node) 48 | local result = true 49 | local waitTime = 5 50 | local folders = { "runtime/map/chunks" } 51 | -- only for testing purposses update pocket from 0 52 | if pocket then 53 | folders = { "runtime/map/chunks", 54 | "general", 55 | "gui", 56 | "host", 57 | "pocket", 58 | "turtle", 59 | "storage", 60 | } 61 | end 62 | local files = { 63 | "runtime/turtles.txt", 64 | "runtime/stations.txt", 65 | "runtime/taskGroups.txt", 66 | "runtime/alerts.txt", 67 | "runtime/config.lua" 68 | } 69 | 70 | for _,file in ipairs(files) do 71 | -- local modified = nil 72 | -- if fs.exists(file) then modified = fs.attributes(file).modified end 73 | print("FILE_REQUEST", file) 74 | local data = { "FILE_REQUEST", { fileName = file, modified = nil } } 75 | local answer, forMsg = node:send(node.differentHost, data, true, true, waitTime) 76 | if not handleAnswer(answer, forMsg) then 77 | result = false 78 | end 79 | end 80 | 81 | -- relevant file transfer done 82 | -- optionally try and get map chunks as well 83 | 84 | local ts = os.epoch("utc") 85 | -- unsure if this is perhaps too much data 86 | print("FOLDERS_REQUEST", textutils.serialize(folders)) 87 | local data = { "FOLDERS_REQUEST", { folderNames = folders, files = files } } 88 | local answer, forMsg = node:send(node.differentHost, data, true, true, 60) 89 | print("ANSWER TIME", os.epoch("utc") - ts) 90 | ts = os.epoch("utc") 91 | if not handleAnswer(answer, forMsg) then 92 | result = false 93 | print("folder failed", answer and answer.data[1] or "no answer") 94 | end 95 | print("IMPORT TIME", os.epoch("utc") - ts) 96 | 97 | return result 98 | end 99 | 100 | local function checkForHostTransfer() 101 | local node = global.nodeUpdate 102 | local waitTime = 5 103 | local flagFile = "runtime/hostTransferFlag.txt" 104 | 105 | if fs.exists(flagFile) then 106 | fs.delete(flagFile) 107 | print("HOST TRANSFER IN PROGRESS") 108 | --display:showPopUp (gui.Label:new(2,2,display.width-2,1,"This computer has been set as the new host. Press any key to continue.")) 109 | 110 | -- notify old host that this is ready to accept turtles clients 111 | local tempWait = 5 112 | for _,turt in pairs(global.turtles) do tempWait = tempWait + 2 end 113 | print("HOST_TRANSFER_COMPLETE") 114 | local answer = node:send(node.differentHost, {"HOST_TRANSFER_COMPLETE"}, true, true, waitTime) 115 | if answer and answer.data[1] == "HOST_TRANSFER_COMPLETE_OK" then 116 | print(answer.data[1]) 117 | local noAck = answer.data[2] and answer.data[2].noAck or nil 118 | if noAck then 119 | for id in ipairs(noAck) do 120 | if global.turtles[id] then 121 | global.turtles[id].needsHostNotify = true 122 | end 123 | end 124 | end 125 | 126 | -- alternatively keep old host online to redirect turtles to new host 127 | print("HOST_TRANSFER_SHUTDOWN") 128 | local answer = node:send(node.differentHost, {"HOST_TRANSFER_SHUTDOWN"}, true, true, waitTime) 129 | if answer and answer.data[1] == "HOST_TRANSFER_SHUTDOWN_OK" then 130 | print(answer.data[1]) 131 | print("HOST TRANSFER DONE") 132 | return true 133 | -- done 134 | else 135 | print("HOST_TRANSFER_SHUTDOWN_UNSUCCESSFUL", answer and answer.data[1] or "no answer") 136 | return false 137 | end 138 | else 139 | print("HOST_TRANSFER_COMPLETION_UNSUCCESSFUL", answer and answer.data[1] or "no answer") 140 | return false 141 | end 142 | 143 | elseif node.differentHost then 144 | local display = global.display 145 | 146 | -- TODO: implement proper GUI prompt 147 | --display:showPopUp (gui.Label:new(2,2,display.width-2,1,"Host transfer requested from another host. Accept? (y/n)")) 148 | print("\n-------------------------------------------") 149 | print("DIFFERENT HOST DETECTED:", node.differentHost) 150 | print("-------------------------------------------") 151 | write("REQUEST TRANSFER? (y/n): ") 152 | local answer = read() 153 | if answer:lower() ~= "y" then 154 | print("HOST_TRANSFER_DENIED") 155 | return false 156 | end 157 | 158 | print("HOST_TRANSFER_REQUEST") 159 | local answer = node:send(node.differentHost, {"HOST_TRANSFER_REQUEST"}, true, true, 5) 160 | if answer and answer.data[1] == "HOST_TRANSFER_OK" then 161 | print(answer.data[1]) 162 | print("HOST_TRANSFER_PREPARE") 163 | local answer = node:send(node.differentHost, {"HOST_TRANSFER_PREPARE"}, true, true, 5) 164 | if answer and answer.data[1] == "HOST_TRANSFER_PREPARE_OK" then 165 | print(answer.data[1]) 166 | -- host stops serving turtles etc. 167 | 168 | -- request files from old host 169 | if transferFiles(node) then 170 | print("FILE_TRANSFER_COMPLETE") 171 | -- set flag file to indicate host mode on reboot 172 | local f = fs.open(flagFile,"w") 173 | f.write("transfer") 174 | f.close() 175 | os.reboot() 176 | else 177 | -- TODO: inform old host whenever the process failed 178 | local answer = node:send(node.differentHost, {"HOST_TRANSFER_FAILED"}, true, true, waitTime) 179 | print("HOST_TRANSFER_FAILED") 180 | return false 181 | end 182 | else 183 | print("HOST_TRANSFER_PREPARATION_UNSUCCESSFUL", answer and answer.data[1] or "no answer") 184 | return false 185 | end 186 | else 187 | print("HOST_TRANSFER_UNSUCCESSFUL", answer and answer.data[1] or "no answer") 188 | return false 189 | end 190 | end 191 | return true 192 | end 193 | 194 | return checkForHostTransfer() -------------------------------------------------------------------------------- /general/bluenet.lua: -------------------------------------------------------------------------------- 1 | 2 | -- bluenet, a modified rednet for better performance 3 | 4 | 5 | local bluenet = {} 6 | 7 | local default = { 8 | typeSend = 1, 9 | typeAnswer = 2, 10 | typeDone = 3, 11 | waitTime = 1, 12 | 13 | channels = { 14 | max = 65400, 15 | broadcast = 65401, 16 | repeater = 65402, 17 | host = 65403, 18 | refuel = 65404, 19 | storage = 65405, 20 | } 21 | } 22 | bluenet.default = default 23 | --msg = { id, time, sender, recipient, protocol, type, data, answer, wait, distance} 24 | 25 | local receivedMessages = {} 26 | local receivedTimer = nil -- does that work? 27 | local osEpoch = os.epoch 28 | 29 | 30 | local opened = false 31 | local modem = nil 32 | local ownChannel = nil 33 | bluenet.ownChannel = nil 34 | local computerId = os.getComputerID() 35 | 36 | function bluenet.idAsChannel(id) 37 | return (id or os.getComputerID()) % default.channels.max 38 | end 39 | local idAsChannel = bluenet.idAsChannel 40 | 41 | function bluenet.findModem() 42 | for _,modem in ipairs(peripheral.getNames()) do 43 | local modemType, subType = peripheral.getType(modem) 44 | if modemType == "modem" and peripheral.call(modem, "isWireless") then 45 | return modem 46 | end 47 | end 48 | return nil 49 | end 50 | local findModem = bluenet.findModem 51 | 52 | function bluenet.open(modem) 53 | if not opened then 54 | 55 | if not modem then 56 | print("NO MODEM") 57 | opened = false 58 | end 59 | peripheral.call(modem, "open", ownChannel) 60 | peripheral.call(modem, "open", default.channels.broadcast) 61 | print("opened",ownChannel,default.channels.broadcast) 62 | 63 | end 64 | opened = true 65 | return true 66 | end 67 | local open = bluenet.open 68 | 69 | function bluenet.close(modem) 70 | if modem then 71 | if peripheral.getType(modem) == "modem" then 72 | peripheral.call(modem, "close", ownChannel) 73 | peripheral.call(modem, "close", default.channels.broadcast) 74 | opened = false 75 | end 76 | else 77 | for _,modem in ipairs(peripheral.getNames()) do 78 | if isOpen(modem) then 79 | close(modem) 80 | end 81 | end 82 | end 83 | end 84 | local close = bluenet.close 85 | 86 | local function isOpen(modem) 87 | if modem then 88 | if peripheral.getType(modem) == "modem" then 89 | return peripheral.call(modem, "isOpen", ownChannel) 90 | and peripheral.call(modem, "isOpen", default.channels.broadcast) 91 | end 92 | else 93 | for _,modem in ipairs(peripheral.getNames()) do 94 | if isOpen(modem) then 95 | return true 96 | end 97 | end 98 | end 99 | return false 100 | end 101 | bluenet.isOpen = isOpen 102 | 103 | function bluenet.isChannelOpen(modem, channel) 104 | if not modem then 105 | print("NO MODEM", modem) 106 | return false 107 | end 108 | return peripheral.call(modem, "isOpen", channel) 109 | end 110 | local isChannelOpen = bluenet.isChannelOpen 111 | 112 | function bluenet.openChannel(modem, channel) 113 | if not isChannelOpen(modem, channel) then 114 | if not modem then 115 | print("NO MODEM") 116 | return false 117 | end 118 | peripheral.call(modem, "open", channel) 119 | print("opened", channel) 120 | end 121 | return true 122 | end 123 | local openChannel = bluenet.openChannel 124 | 125 | function bluenet.closeChannel(modem, channel) 126 | if not modem then 127 | print("NO MODEM", modem) 128 | return false 129 | end 130 | if isChannelOpen(modem, channel) then 131 | print("closed", channel) 132 | return peripheral.call(modem, "close", channel) 133 | end 134 | return true 135 | end 136 | local closeChannel = bluenet.closeChannel 137 | 138 | 139 | 140 | 141 | local startTimer = os.startTimer 142 | local cancelTimer = os.cancelTimer 143 | local osClock = os.clock 144 | local timerClocks = {} 145 | local timers = {} 146 | local pullEventRaw = os.pullEventRaw 147 | local type = type 148 | 149 | function bluenet.receive(protocol, waitTime) 150 | local timer = nil 151 | local eventFilter = nil 152 | 153 | -- CAUTION: if bluenet is loaded globally, 154 | -- TODO: the timers must be distinguished by protocol/coroutine 155 | -- leads to host being unable to reboot!!! 156 | -- is the protocol ever nil? if so, this code wont work! 157 | 158 | if waitTime then 159 | local t = osClock() 160 | local clocks, tmrs = timerClocks[protocol], timers[protocol] 161 | if not clocks then 162 | clocks = {} 163 | tmrs = {} 164 | timerClocks[protocol] = clocks 165 | timers[protocol] = tmrs 166 | end 167 | if clocks[waitTime] ~= t then 168 | --cancel the previous timer and create a new one 169 | cancelTimer((tmrs[waitTime] or 0)) 170 | timer = startTimer(waitTime) 171 | --print( protocol, "cancelled", tmrs[waitTime], "created", timer, "diff", timer - (timers[waitTime]or 0)) 172 | clocks[waitTime] = t 173 | tmrs[waitTime] = timer 174 | else 175 | timer = tmrs[waitTime] 176 | --print( protocol, "reusing", timer) 177 | end 178 | 179 | eventFilter = nil 180 | else 181 | eventFilter = "modem_message" 182 | end 183 | 184 | --print("receiving", protocol, waitTime, timer, eventFilter) 185 | while true do 186 | local event, modem, channel, sender, msg, distance = pullEventRaw(eventFilter) 187 | --if event == "modem_message" then print(os.clock(),event, modem, channel, sender) end 188 | 189 | if event == "modem_message" 190 | --and ( channel == ownChannel or channel == default.channels.broadcast 191 | -- or channel == default.channels.host ) 192 | and type(msg) == "table" 193 | --and type(msg.id) == "number" and not receivedMessages[msg.id] 194 | and ( type(msg.recipient) == "number" and msg.recipient 195 | and ( msg.recipient == computerId 196 | or msg.recipient == default.channels.broadcast 197 | or msg.recipient == default.channels.host 198 | or msg.recipient == default.channels.refuel 199 | or msg.recipient == default.channels.storage ) ) 200 | -- WHY EVEN CHECK THE CHANNEL? only those channels are opened anyways so we wont receive any other 201 | and ( protocol == nil or protocol == msg.protocol ) 202 | -- just to make sure its a bluenet message 203 | then 204 | msg.distance = distance 205 | -- event, modem, channel, replyChannel, message, distance 206 | --print("received", msg.id, msg.protocol) 207 | --receivedMessages[msg.id] = os.clock() + 9.5 208 | --resetTimer() 209 | --cancelTimer(timer) 210 | -- if osEpoch() > t then 211 | -- print("cancel old timer") 212 | -- cancelTimer(timer) 213 | -- end 214 | return msg 215 | 216 | elseif event == "timer" then 217 | --print(os.clock(),event, modem, channel, sender, timer) 218 | 219 | if modem == timer then -- must be equal! >= geht nicht 220 | --print("returning nil") 221 | return nil 222 | end 223 | elseif event == "terminate" then 224 | error("Terminated",0) 225 | end 226 | 227 | end 228 | 229 | end 230 | 231 | function bluenet.resetTimer() 232 | if not receivedTimer then receivedTimer = os.startTimer(10) end 233 | end 234 | 235 | function bluenet.clearReceivedMessages() 236 | receivedTimer = nil 237 | local time, hasMore = os.clock(), nil 238 | for id, deadline in pairs(receivedMessages) do 239 | if deadline <= now then receivedMessages[id] = nil 240 | else hasMore = true end 241 | end 242 | receivedTimer = hasMore and os.startTimer(10) 243 | end 244 | 245 | 246 | modem = findModem() 247 | bluenet.modem = modem 248 | ownChannel = idAsChannel() 249 | bluenet.ownChannel = ownChannel 250 | 251 | 252 | return bluenet --------------------------------------------------------------------------------