MineOS/lib/modemConnection.lua
2016-03-02 13:19:36 +03:00

332 lines
11 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 modemConnection = {}
----------------------------------------------------------------------------------------------------------------------------------
local infoMessages = {
userTriesToConnectNoGUI = "Пользователь %s желает установить с вами соединение. Разрешить?",
noModem = "Этой библиотеке требуется сетевая карта для работы",
}
modemConnection.port = 322
modemConnection.sendingDataDelay = 1.0
modemConnection.receiveMessagesFromRobots = true
modemConnection.receiveMessagesFromTablets = true
modemConnection.receiveMessagesFromComputers = true
----------------------------------------------------------------------------------------------------------------------------------
local xSize, ySize = gpu.getResolution()
local computerIcon, robotIcon, tabletIcon
if not component.isAvailable("robot") then
image = require("image")
ecs = require("ECSAPI")
computerIcon = image.load("MineOS/System/OS/Icons/Script.pic")
robotIcon = image.load("MineOS/System/OS/Icons/Robot.pic")
tabletIcon = image.load("MineOS/System/OS/Icons/Tablet.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 == modemConnection.port then
if messages[1] == "requestingPermissionToConnect" then
askForConnection(messages[2])
elseif messages[1] == "iAmHereAddMePlease" then
if not modemConnection.availableUsers[remoteAddress] then
local userData = serialization.unserialize(messages[2])
if
(not userData.isRobot and not userData.isTablet and modemConnection.receiveMessagesFromComputers)
or
(userData.isRobot and modemConnection.receiveMessagesFromRobots)
or
(userData.isTablet and modemConnection.receiveMessagesFromTablets)
then
modemConnection.availableUsers[userData.address] = userData
modem.send(remoteAddress, modemConnection.port, "iAmHereAddMePlease", modemConnection.dataToSend)
computer.pushSignal("userlistChanged")
end
end
elseif messages[1] == "iAmDisconnecting" then
if modemConnection.availableUsers[remoteAddress] then
modemConnection.availableUsers[remoteAddress] = nil
computer.pushSignal("userlistChanged")
end
end
end
end
end
local function createSendingArray()
modemConnection.dataToSend = {}
modemConnection.dataToSend.address = modemConnection.localAddress
modemConnection.dataToSend.name = component.filesystem.getLabel()
if component.isAvailable("robot") then
modemConnection.dataToSend.isRobot = true
if component.isAvailable("inventory_controller") then
modemConnection.dataToSend.inventoryController = true
end
if component.isAvailable("tank_controller") then
modemConnection.dataToSend.tankController = true
end
if component.isAvailable("crafting") then
modemConnection.dataToSend.crafting = true
end
if component.isAvailable("redstone") then
modemConnection.dataToSend.redstone = true
end
end
if component.isAvailable("tablet") then
modemConnection.dataToSend.isTablet = true
if component.isAvailable("navigation") then
modemConnection.dataToSend.navigation = true
end
if component.isAvailable("piston") then
modemConnection.dataToSend.piston = true
end
end
if component.isAvailable("geolyzer") then
modemConnection.dataToSend.geolyzer = true
end
modemConnection.dataToSend = serialization.serialize(modemConnection.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, userData)
if userData.isRobot then
image.draw(x + 3, y, robotIcon)
elseif userData.isTablet then
image.draw(x + 3, y, tabletIcon)
else
image.draw(x + 3, y, computerIcon)
end
ecs.colorTextWithBack(x, y + 5, foreground, background, ecs.stringLimit("end", userData.address, 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(modemConnection.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(modemConnection.availableUsers) do
if counter < limit then
newObj("Users", address, drawIconAndAddress(x, y, background, 0xFFFFFF, modemConnection.availableUsers[address]))
end
x = x + iconWidth + spaceBetween
counter = counter + 1
end
end
local function drawSelectedIcon(x, y, background, foreground, userData)
local selectionWidth = 16
local skokaOtnat = (selectionWidth - 14) / 2
local oldPixels = ecs.rememberOldPixels(x - skokaOtnat, y, x + selectionWidth - 2, y + 13)
ecs.square(x - skokaOtnat, y, selectionWidth, 8, background)
drawIconAndAddress(x, y + 1, background, foreground, userData)
obj.CykaKnopkaInfo = { ecs.drawButton(x - skokaOtnat, y + 8, selectionWidth, 3, "Информация", 0xff6699, 0xFFFFFF) }
obj.CykaKnopkaConnect = { ecs.drawButton(x - skokaOtnat, 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, {address = modemConnection.localAddress})
while true do
if ecs.getArraySize(modemConnection.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(modemConnection.availableUsers) <= 0 then
ecs.square(1, 1, xSize, ySize, 0xEEEEEE)
drawIconAndAddress(xCircle - 6, ySize - 6, 0xEEEEEE, 0x262626, {address = modemConnection.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, modemConnection.availableUsers[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 modemConnection.stopReceivingData()
event.ignore("modem_message", modemMessageHandler)
end
function modemConnection.startReceivingData()
modemConnection.stopReceivingData()
event.listen("modem_message", modemMessageHandler)
end
function modemConnection.disconnect()
modem.broadcast(modemConnection.port, "iAmDisconnecting")
end
function modemConnection.sendPersonalData()
modemConnection.disconnect()
modem.broadcast(modemConnection.port, "iAmHereAddMePlease", modemConnection.dataToSend)
end
function modemConnection.changePort(newPort)
modem.close(modemConnection.port)
modem.open(newPort)
modemConnection.port = newPort
modemConnection.remoteAddress = nil
modemConnection.localAddress = component.getPrimary("modem").address
modemConnection.availableUsers = {}
createSendingArray()
end
function modemConnection.search()
modemConnection.sendPersonalData()
connectionGUI()
end
function modemConnection.init()
if component.isAvailable("modem") then
modemConnection.changePort(modemConnection.port)
modemConnection.startReceivingData()
else
ecs.error(infoMessages.noModem)
return
end
end
----------------------------------------------------------------------------------------------------------------------------------
modemConnection.init()
modemConnection.sendPersonalData()
modemConnection.search()
----------------------------------------------------------------------------------------------------------------------------------
return modemConnection