├── 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 | 
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 | 
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 | 
100 | 
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
--------------------------------------------------------------------------------