SHOW:
|
|
- or go back to the newest paste.
| 1 | --[[ | |
| 2 | ARC: AR Client | |
| 3 | Uses Plethora overlay glasses and modems to display 3D signage transmitted from local "beacons" | |
| 4 | ]] | |
| 5 | ||
| 6 | local m = peripheral.find "modem" | |
| 7 | local mods = peripheral.wrap "back" | |
| 8 | ||
| 9 | if not m then error "Modem required." end | |
| 10 | if not mods then error "Is this even on a neural interface?" end | |
| 11 | if not mods.canvas3d then error "Overlay glasses required." end | |
| 12 | ||
| 13 | local canv = mods.canvas3d() | |
| 14 | ||
| 15 | local object_channel = 666 | |
| 16 | ||
| 17 | m.open(object_channel) | |
| 18 | ||
| 19 | local x, y, z | |
| 20 | ||
| 21 | -- convert position to string for use as table key | |
| 22 | local function serialize_position(p) | |
| 23 | return string.format("%f,%f,%f", p[1], p[2], p[3])
| |
| 24 | end | |
| 25 | ||
| 26 | -- Generate a string representation of a table, for easy comparison. Not really hashing, I guess. | |
| 27 | local function hash_table(x) | |
| 28 | if type(x) == "table" then | |
| 29 | local out = "" | |
| 30 | for k, v in pairs(x) do | |
| 31 | if type(k) ~= "string" or not k:match "^_" then -- ignore keys beginning with _ | |
| 32 | out = out .. hash_table(k) .. ":" .. hash_table(v) .. ";" | |
| 33 | end | |
| 34 | end | |
| 35 | return out | |
| 36 | else | |
| 37 | return tostring(x) | |
| 38 | end | |
| 39 | end | |
| 40 | ||
| 41 | -- honestly not that elegant, but it works | |
| 42 | -- TODO: do this more efficiently/nicely somehow? | |
| 43 | local function tables_match(x, y) | |
| 44 | return hash_table(x) == hash_table(y) | |
| 45 | end | |
| 46 | ||
| 47 | local objects = {}
| |
| 48 | local timers = {}
| |
| 49 | ||
| 50 | local function redraw(object) | |
| 51 | local frame = object._frame | |
| 52 | frame.clear() | |
| 53 | end | |
| 54 | ||
| 55 | local function process_object(object) | |
| 56 | local pos = serialize_position(object.position) | |
| 57 | if objects[pos] then | |
| 58 | if not tables_match(object, objects[pos]) then | |
| 59 | print("redrawing", pos)
| |
| 60 | objects[pos] = object | |
| 61 | redraw(objects[pos]) | |
| 62 | end | |
| 63 | local t = os.startTimer(20) | |
| 64 | timers[t] = pos | |
| 65 | else | |
| 66 | print("new object at", pos)
| |
| 67 | if x then | |
| 68 | local frame = | |
| 69 | else | |
| 70 | print("GPS error, cannot create object")
| |
| 71 | end | |
| 72 | end | |
| 73 | end | |
| 74 | ||
| 75 | local function main_loop() | |
| 76 | while true do | |
| 77 | local event, timer, channel, reply_channel, message, distance = os.pullEvent() | |
| 78 | if event == "modem_message" and channel == object_channel and distance and type(message) == "table" then -- ensure message is from this dimension and otherwise valid | |
| 79 | for _, object in pairs(msg) do | |
| 80 | local ok, err = pcall(process_object, object) | |
| 81 | if not ok then printError(err) end | |
| 82 | end | |
| 83 | elseif event == "timer" then | |
| 84 | local objpos = timers[timer] | |
| 85 | if objpos then | |
| 86 | local obj = objects[objpos] | |
| 87 | if obj then | |
| 88 | print(objpos, "timed out") | |
| 89 | obj._frame.remove() | |
| 90 | objects[objpos] = nil | |
| 91 | end | |
| 92 | end | |
| 93 | end | |
| 94 | end | |
| 95 | end | |
| 96 | ||
| 97 | -- Request location every second | |
| 98 | local function GPS_loop() | |
| 99 | while true do | |
| 100 | x, y, z = gps.locate() | |
| 101 | sleep(1) | |
| 102 | end | |
| 103 | end | |
| 104 | ||
| 105 | parallel.waitForAll(GPS_loop, main_loop) |