love.mqtt = {} local mqttEventChannel local mqttCommandChannel local errorMessage = nil local oldPrint = print function print(...) local string = "" for _, v in ipairs({...}) do string = string .. tostring(v) end love.mqtt.send("controller/stdout", string) oldPrint(...) end function printTable(table, indentation) indentation = indentation or "" for name, value in pairs(table) do print(indentation .. tostring(name) .. ": " .. tostring(value)) end end function safeCall(target, ...) local success, msg = pcall(target, ...) if not success then errorMessage = msg end end function love.draw(...) if love.draw2 and not errorMessage then safeCall(love.draw2, ...) else local text = "Awaiting payload..." local font = love.graphics.getFont() if errorMessage then text = errorMessage end -- Calculate the center of the screen local centerX = love.graphics.getWidth() / 2 local centerY = love.graphics.getHeight() / 2 -- Calculate textX and textY local textX = math.floor(centerX - (font:getWidth(text) / 2)) local textY = math.floor(centerY - (font:getHeight(text) / 2)) local textX, textY = 10, 10 local realText if errorMessage then realText = errorMessage else realText = "Awaiting payload" .. ("."):rep(math.floor(love.timer.getTime() * 4 % 4)) end -- Render text if errorMessage then love.graphics.setBackgroundColor(0.2, 0, 0, 0) else love.graphics.setBackgroundColor(0, 0, 0.2, 0) end love.graphics.print(realText, textX, textY) end end function love.update(...) local message = mqttEventChannel:pop() if message then safeCall(love.mqtt[message.target], unpack(message.args)) end if love.update2 and not errorMessage then safeCall(love.update2, ...) end end function love.gamepadpressed(joystick, button) if button == "guide" then love.event.quit() end if love.gamepadpressed2 then safeCall(love.gamepadpressed2, joystick, button) end end function love.joystickaxis(joystick, axis, value) if love.joystickaxis2 then safeCall(love.joystickaxis2, joystick, axis, value) end end function love.mqtt.onError(message) print("MQTT error: " .. message) end function love.mqtt.connect(connack) if connack.rc ~= 0 then print("Connection to broker failed:", connack:reason_string()) end love.mqtt.subscribe("controller/payload") print("Connected to MQTT") printTable(connack) end function love.mqtt.message2(topic, payload) if topic == "controller/payload" then errorMessage = nil local success = love.filesystem.unmount("client.zip") if not success then print("Could not unmount client.zip") end local archive = love.filesystem.newFileData(payload, "client.zip") local success = love.filesystem.mount(archive, "client", true) if not success then print("Failed to mount archive") return end print("Archive mounted") local chunk, errormsg = love.filesystem.load("client/main.lua", "bt") if errormsg then print(errormsg) errorMessage = errormsg return end love.load = nil chunk() if love.load then safeCall(love.load) end elseif love.mqtt.message then love.mqtt.message(topic, payload) end end function love.mqtt.send(topic, arg) mqttCommandChannel:push { command = "send", topic = topic, arg = arg } end function love.mqtt.subscribe(topic) mqttCommandChannel:push { command = "subscribe", topic = topic, } end function love.load() love.graphics.setFont(love.graphics.newFont(20)) local requirePaths = love.filesystem.getRequirePath() love.filesystem.setRequirePath(requirePaths .. ";client/?.lua;client/?/init.lua") local mqttThread = love.thread.newThread("mqttthread.lua") mqttThread:start(love.math.random(0, 999999)) mqttEventChannel = love.thread.getChannel("mqtt_event") mqttCommandChannel = love.thread.getChannel("mqtt_command") end