local socket = require("socket") local network = {} local client -- Packet IDs network.MSG_KEY_PRESS = 1 network.MSG_GAMESTATE = 2 -------------------------------------------------- -- Packing -------------------------------------------------- local function packU16(n) return string.char(math.floor(n / 256) % 256, n % 256) end local function packU32(n) return string.char(math.floor(n / 16777216) % 256, math.floor(n / 65536) % 256, math.floor(n / 256) % 256, n % 256) end local function unpackU16(s) local b1, b2 = s:byte(1, 2) return b1 * 256 + b2 end local function unpackU32(s) local b1, b2, b3, b4 = s:byte(1, 4) return b1 * 16777216 + b2 * 65536 + b3 * 256 + b4 end -------------------------------------------------- -- Connection -------------------------------------------------- function network.connect(ip, port) client = assert(socket.tcp()) client:settimeout(0) local ok, err = client:connect(ip, port) -- Non-blocking connect is expected if not ok and err ~= "timeout" then error(err) end print("Connecting...") end -------------------------------------------------- -- Sending -------------------------------------------------- function network.sendPacket(id, payload) if not client then return end payload = payload or "" local length = 2 + #payload local packet = packU32(length) .. packU16(id) .. payload client:send(packet) end function network.sendKey(key) network.sendPacket(network.MSG_KEY_PRESS, key) end -------------------------------------------------- -- Packet handlers -------------------------------------------------- network.handlers = {} function network.on(id, callback) network.handlers[id] = callback end -------------------------------------------------- -- Receiving -------------------------------------------------- local function receivePacket() local lenData, err = client:receive(4) if not lenData then return nil end local length = unpackU32(lenData) local idData = client:receive(2) if not idData then return nil end local msgID = unpackU16(idData) local payload = "" if length > 2 then payload = client:receive(length - 2) if not payload then return nil end end return msgID, payload end -------------------------------------------------- -- Poll every frame -------------------------------------------------- function network.update() if not client then return end while true do local id, payload = receivePacket() if not id then break end local handler = network.handlers[id] if handler then handler(payload) end end end return network