diff --git a/Applications/modemConnection.lua b/Applications/modemConnection.lua new file mode 100644 index 00000000..a66cfa2d --- /dev/null +++ b/Applications/modemConnection.lua @@ -0,0 +1,293 @@ + +local event = require("event") +local computer = require("computer") +local component = require("component") +local serialization = require("serialization") +local unicode = require("unicode") +local ecs, image +local modem = component.modem +local gpu = component.gpu +local wirelessConnection = {} + +---------------------------------------------------------------------------------------------------------------------------------- + +local infoMessages = { + userTriesToConnectNoGUI = "Пользователь %s желает установить с вами соединение. Разрешить?", + noModem = "Этой библиотеке требуется сетевая карта для работы", +} + +wirelessConnection.port = 322 +wirelessConnection.sendingDataDelay = 1.0 +wirelessConnection.receiveMessagesFromRobots = true + +---------------------------------------------------------------------------------------------------------------------------------- + +local xSize, ySize = gpu.getResolution() +local computerIcon +if not component.isAvailable("robot") then + image = require("image") + ecs = require("ECSAPI") + computerIcon = image.load("MineOS/System/OS/Icons/Script.pic") +end + +---------------------------------------------------------------------------------------------------------------------------------- + +local obj = {} +local function newObj(class, name, ...) + obj[class] = obj[class] or {} + obj[class][name] = {...} +end + +local function askForConnection(userData) + local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, + {"EmptyLine"}, + {"CenterText", ecs.colors.orange, "WirelessConnection"}, + {"EmptyLine"}, + {"CenterText", 0xffffff, "Пользователь " .. ecs.stringLimit("end", userData.address, 6) .. " желает" }, + {"CenterText", 0xffffff, "установить с вами беспроводное соединение." }, + {"EmptyLine"}, + {"CenterText", 0xffffff, "Разрешить подключение?" }, + {"EmptyLine"}, + {"Button", {ecs.colors.orange, 0x262626, "Да"}, {0x999999, 0xffffff, "Нет"}} + ) +end + +local function modemMessageHandler(_, localAddress, remoteAddress, port, distance, ...) + local messages = {...} + if #messages > 0 then + if port == wirelessConnection.port then + if messages[1] == "requestingPermissionToConnect" then + askForConnection(messages[2]) + elseif messages[1] == "iAmHereAddMePlease" then + if not wirelessConnection.availableUsers[remoteAddress] then + local userData = serialization.unserialize(messages[2]) + if not userData.isRobot or (userData.isRobot and wirelessConnection.receiveMessagesFromRobots) then + wirelessConnection.availableUsers[userData.address] = userData + modem.send(remoteAddress, wirelessConnection.port, "iAmHereAddMePlease", wirelessConnection.dataToSend) + computer.pushSignal("userlistChanged") + end + end + elseif messages[1] == "iAmDisconnecting" then + if wirelessConnection.availableUsers[remoteAddress] then + wirelessConnection.availableUsers[remoteAddress] = nil + computer.pushSignal("userlistChanged") + end + end + end + end +end + +local function createSendingArray() + wirelessConnection.dataToSend = {} + wirelessConnection.dataToSend.address = wirelessConnection.localAddress + wirelessConnection.dataToSend.name = component.filesystem.getLabel() + if component.isAvailable("robot") then + wirelessConnection.dataToSend.isRobot = true + if component.isAvailable("inventory_controller") then + wirelessConnection.dataToSend.inventoryController = true + end + if component.isAvailable("tank_controller") then + wirelessConnection.dataToSend.tankController = true + end + if component.isAvailable("crafting") then + wirelessConnection.dataToSend.crafting = true + end + if component.isAvailable("redstone") then + wirelessConnection.dataToSend.redstone = true + end + end + wirelessConnection.dataToSend = serialization.serialize(wirelessConnection.dataToSend) +end + +--Нарисовать окружность, алгоритм спизжен с вики +local function circle(xCenter, yCenter, radius, color) + gpu.setBackground(color) + local function insertPoints(x, y) + gpu.set(xCenter + x * 2, yCenter + y, " ") + gpu.set(xCenter + x * 2, yCenter - y, " ") + gpu.set(xCenter - x * 2, yCenter + y, " ") + gpu.set(xCenter - x * 2, yCenter - y, " ") + + gpu.set(xCenter + x * 2 + 1, yCenter + y, " ") + gpu.set(xCenter + x * 2 + 1, yCenter - y, " ") + gpu.set(xCenter - x * 2 + 1, yCenter + y, " ") + gpu.set(xCenter - x * 2 + 1, yCenter - y, " ") + end + + local x = 0 + local y = radius + local delta = 3 - 2 * radius; + while (x < y) do + insertPoints(x, y); + insertPoints(y, x); + if (delta < 0) then + delta = delta + (4 * x + 6) + else + delta = delta + (4 * (x - y) + 10) + y = y - 1 + end + x = x + 1 + end + + if x == y then insertPoints(x, y) end +end + +local function drawCircles(xCircle, yCircle, minumumRadius, maximumRadius, step, currentRadius) + for radius = minumumRadius, maximumRadius, step do + if radius == currentRadius then + circle(xCircle, yCircle, radius, 0xAAAAAA) + else + circle(xCircle, yCircle, radius, 0xDDDDDD) + end + end +end + +local function drawIconAndAddress(x, y, background, foreground, text) + image.draw(x + 3, y, computerIcon) + ecs.colorTextWithBack(x, y + 5, foreground, background, ecs.stringLimit("end", text, 14)) + return x, y, x + 13, y + 5 +end + +local function drawHorizontalIcons() + local height = 8 + local y = math.floor(ySize / 2 - height / 2) + local background = 0x66A8FF + ecs.square(1, y, xSize, height, background) + + local iconWidth = 14 + local spaceBetween = 2 + local totalWidth = ecs.getArraySize(wirelessConnection.availableUsers) * (iconWidth + spaceBetween) - spaceBetween + local x = math.floor(xSize / 2 - totalWidth / 2) + 1 + + obj.Users = {} + + local counter = 0 + local limit = math.floor(xSize / (iconWidth + spaceBetween)) + y = y + 1 + for address in pairs(wirelessConnection.availableUsers) do + if counter < limit then + newObj("Users", address, drawIconAndAddress(x, y, background, 0xFFFFFF, address)) + end + x = x + iconWidth + spaceBetween + counter = counter + 1 + end +end + +local function drawSelectedIcon(x, y, background, foreground, text) + local selectionWidth = 16 + local oldPixels = ecs.rememberOldPixels(x - 1, y, x + selectionWidth - 2, y + 13) + ecs.square(x - 1, y, selectionWidth, 8, background) + drawIconAndAddress(x, y + 1, background, foreground, text) + obj.CykaKnopkaInfo = { ecs.drawButton(x - 1, y + 8, selectionWidth, 3, "Информация", 0xff6699, 0xFFFFFF) } + obj.CykaKnopkaConnect = { ecs.drawButton(x - 1, y + 11, selectionWidth, 3, "Подключиться", 0xff3333, 0xFFFFFF) } + return oldPixels +end + +local function connectionGUI() + ecs.square(1, 1, xSize, ySize, 0xEEEEEE) + + local xCircle, yCircle = math.floor(xSize / 2), ySize - 3 + local minumumRadius, maximumRadius = 7, xCircle * 0.8 + local step = 4 + local currentRadius = minumumRadius + + drawIconAndAddress(xCircle - 6, ySize - 6, 0xEEEEEE, 0x262626, wirelessConnection.localAddress) + + while true do + if ecs.getArraySize(wirelessConnection.availableUsers) > 0 then + currentRadius = 0 + drawCircles(xCircle, yCircle, minumumRadius, maximumRadius, step, currentRadius) + + drawHorizontalIcons() + + local oldPixels, needToUpdate + while true do + if not oldPixels and needToUpdate then + if ecs.getArraySize(wirelessConnection.availableUsers) <= 0 then + ecs.square(1, 1, xSize, ySize, 0xEEEEEE) + drawIconAndAddress(xCircle - 6, ySize - 6, 0xEEEEEE, 0x262626, wirelessConnection.localAddress) + currentRadius = minumumRadius + break + else + drawHorizontalIcons() + needToUpdate = false + end + end + + local e = { event.pull() } + if e[1] == "touch" then + if oldPixels then ecs.drawOldPixels(oldPixels); oldPixels = nil end + for address in pairs(obj.Users) do + if ecs.clickedAtArea(e[3], e[4], obj.Users[address][1], obj.Users[address][2], obj.Users[address][3], obj.Users[address][4]) then + oldPixels = drawSelectedIcon(obj.Users[address][1], obj.Users[address][2] - 1, 0xCCCCFF, 0x262626, address) + break + end + end + elseif e[1] == "userlistChanged" then + needToUpdate = true + end + end + else + drawCircles(xCircle, yCircle, minumumRadius, maximumRadius, step, currentRadius) + currentRadius = currentRadius + step + if currentRadius > (maximumRadius + step) then currentRadius = minumumRadius end + os.sleep(0) + end + end +end + +---------------------------------------------------------------------------------------------------------------------------------- + +function wirelessConnection.stopReceivingData() + event.ignore("modem_message", modemMessageHandler) +end + +function wirelessConnection.startReceivingData() + wirelessConnection.stopReceivingData() + event.listen("modem_message", modemMessageHandler) +end + +function wirelessConnection.disconnect() + modem.broadcast(wirelessConnection.port, "iAmDisconnecting") +end + +function wirelessConnection.sendPersonalData() + wirelessConnection.disconnect() + modem.broadcast(wirelessConnection.port, "iAmHereAddMePlease", wirelessConnection.dataToSend) +end + +function wirelessConnection.changePort(newPort) + modem.close(wirelessConnection.port) + modem.open(newPort) + wirelessConnection.port = newPort + wirelessConnection.remoteAddress = nil + wirelessConnection.localAddress = component.getPrimary("modem").address + wirelessConnection.availableUsers = {} + createSendingArray() +end + +function wirelessConnection.connect() + wirelessConnection.sendPersonalData() + connectionGUI() +end + +function wirelessConnection.init() + if component.isAvailable("modem") then + wirelessConnection.changePort(wirelessConnection.port) + wirelessConnection.startReceivingData() + else + ecs.error(infoMessages.noModem) + return + end +end + +---------------------------------------------------------------------------------------------------------------------------------- + +wirelessConnection.init() +wirelessConnection.sendPersonalData() +-- wirelessConnection.connect() + +---------------------------------------------------------------------------------------------------------------------------------- + +return wirelessConnection +