MoonlightOwl

SmartLock 0.3 by Totoro

Sep 30th, 2014
94
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --                SmartLock 0.3               --
  2. -- advances lock system by Totoro; 10/01/2014 --
  3.  
  4. local event = require('event')
  5. local serial = require('serialization')
  6. local sides = require('sides')
  7. local term = require('term')
  8. local fs = require('filesystem')
  9. local com = require('component')
  10. local comp = require('computer')
  11.  
  12. -- Таблица констант --
  13. OWNER = 'Totoro'
  14. DEFAULT_USER = 'Noname'
  15. DEFAULT_LEVEL = 1
  16. DEFAULT_DOOR = 'Door X'
  17. OPEN_TIME = 1
  18. RED_STRENGTH = 1
  19. PORT = 27
  20. ALLOW = "。◕‿◕。"
  21. WAIT  = "(⊙_◎)"
  22. DENY  = "(¬_¬)"
  23. GLASSX = 240
  24. GLASSY = 55
  25. GLASS_TIME = 2
  26. -- Таблица цветов --
  27. forecolor  = 0xFFFFFF
  28. backcolor  = 0x000000
  29. allowcolor = 0x00FF00
  30. errorcolor = 0xFF0000
  31. warncolor = 0xCCCC00
  32. infocolor = 0x398eb5
  33. --
  34.  
  35. function trytofind(name)
  36.   if com.isAvailable(name) then
  37.     return com.getPrimary(name)
  38.   else
  39.     return nil
  40.   end
  41. end
  42.  
  43. local modem = trytofind('modem')
  44. local glass = trytofind('openperipheral_glassesbridge')
  45. local mgpu  = trytofind('gpu')
  46.  
  47. term.clear()
  48. function errout(message)
  49.   mgpu.setForeground(errorcolor)
  50.   print('[ERROR] '..message)
  51.   mgpu.setForeground(forecolor)
  52. end
  53. function warnout(message)
  54.   mgpu.setForeground(warncolor)
  55.   print('[WARNING] '..message)
  56.   mgpu.setForeground(forecolor)
  57. end
  58. function infout(message)
  59.   mgpu.setForeground(infocolor)
  60.   print('[INFO] '..message)
  61.   mgpu.setForeground(forecolor)
  62. end
  63.  
  64. local agpu = nil
  65. for a,b in com.list('gpu') do
  66.   if a ~= mgpu.address then agpu = com.proxy(a); break end
  67. end
  68. if agpu == nil then
  69.   errout("Не обнаружена вторая видеокарта!")
  70.   return
  71. end
  72.  
  73. if modem ~= nil then infout("Обнаружен модем. Активирован сетевой интерфейс.") end
  74. if glass ~= nil then infout("Вы можете использовать удаленный интерфейс через очки.")
  75. else warnout("Очки не обнаружены. Удаленный интерфейс недоступен.") end
  76.  
  77. width, height = mgpu.getResolution()
  78.  
  79. -- создаем папку для логов
  80. if not fs.exists("logs") then
  81.   fs.makeDirectory("logs")
  82. end
  83.  
  84. -- ======================================== L I S T   M A N A G E R S ======================================== --
  85. function readList(filename)
  86.   if fs.exists(filename) then
  87.     local file = io.open(filename, "r")
  88.     local data = file:read("*a")
  89.     local list = serial.unserialize(data)
  90.     file:close()
  91.     return list
  92.   else
  93.     errout("Файл "..filename.." не найден, создан пустой список!")
  94.     return {}
  95.   end
  96. end
  97. function saveList(list, filename)
  98.   local file = io.open(filename, "w")
  99.   data = serial.serialize(list)
  100.   file:write(data)
  101.   file:close()
  102. end
  103. function toList(list, name, data)
  104.   if data == nil then data = true end
  105.   list[name] = data
  106.   return true
  107. end
  108. function fromList(list, name)
  109.   if list[name] then
  110.     list[name] = nil
  111.     return true
  112.   end
  113.   return false
  114. end
  115. function contains(list, name)
  116.   return list[name] ~= nil
  117. end
  118. function printlist(list)
  119.   if next(list) == nil then print("Таблица пуста.")
  120.   else
  121.     c = 1
  122.     for a,b in pairs(list) do
  123.       print(a, b)
  124.       c = c + 1
  125.       if c > height-3 then
  126.         print("Любая клавиша для продолжения...")
  127.         event.pull('key_down')
  128.         c = 1
  129.       end
  130.     end
  131.   end
  132. end
  133.  
  134. -- ================================================= L O G S ================================================= --
  135. log = {}
  136. log_new = 1
  137.  
  138. function toLog(message)
  139.   table.insert(log, message)
  140.   local name = 'logs/'..string.gsub(os.date('%x'), '/', '_')..'.log'
  141.   local file = nil
  142.   if fs.exists(name) then
  143.     file = io.open(name, 'a')
  144.   else
  145.     file = io.open(name, 'w')
  146.   end
  147.   file:write(message..'\n')
  148.   file:close()
  149. end
  150. function printlog(index)
  151.   if index == nil then
  152.     infout(" Лог событий (целиком):")
  153.   else
  154.     infout(" Лог событий (новое):")
  155.   end
  156.   c = 0
  157.   for i=index or 1, #log do
  158.     print(log[i])
  159.       c = c + 1
  160.       if c > height-3 then
  161.         print("Любая клавиша для продолжения...")
  162.         event.pull('key_down')
  163.         c = 1
  164.       end
  165.   end
  166.   if c == 0 then print("Лог пуст.") end
  167.   log_new = #log + 1
  168. end
  169.  
  170. -- =========================================== P R O C E S S I N G =========================================== --
  171. function trytoopen(data)
  172.   if data == nil then
  173.     if last_door ~= nil then
  174.       ginfout("Открыто: "..doorlist[last_door].name)
  175.       open(last_door)
  176.     else
  177.       gerrout("Уточните код замка.")
  178.     end
  179.   else
  180.     local screen = com.get(data)
  181.     if screen == nil then
  182.       gerrout("Замок "..data.." не найден.")
  183.     else
  184.       if contains(doorlist, screen) then
  185.         open(screen)
  186.         ginfout("Открыто: "..doorlist[screen].name)
  187.       else
  188.         gerrout("Замок отсутствует в таблице.")
  189.       end
  190.     end
  191.   end
  192. end
  193.  
  194. function split(str)
  195.   local result = {}
  196.   for i in string.gmatch(str, "%S+") do
  197.     table.insert(result, i)
  198.   end
  199.   return result
  200. end
  201. function process(command, console)
  202.   -- разбивка строки-команды
  203.   local data = split(command)
  204.  
  205.   -- команда на открытие двери
  206.   if data[1] == 'open' then
  207.     trytoopen(data[2])
  208.   -- добавление нового игрока в таблицу / изменение существующего
  209.   elseif data[1] == 'set' or data[1] == 'user' then
  210.     local name = data[2] or DEFAULT_USER
  211.     local level = tonumber(data[3]) or DEFAULT_LEVEL
  212.     toList(userlist, name, level)
  213.     ginfout("Уровень доступа "..name..": "..level)
  214.   -- добавление новой двери в список / изменение уровня или названия существующей
  215.   elseif data[1] == 'door' then
  216.     local screen = com.get(data[2], 'screen')
  217.     if screen == nil then
  218.       gerrout("Монитор с адресом "..data[2].." не найден.")
  219.     else
  220.       local red = com.get(data[3], 'redstone')
  221.       if red == nil then
  222.         if contains(doorlist, screen) then
  223.           local level = tonumber(data[3])
  224.           if level == nil then
  225.             doorlist[screen].name = data[3]
  226.             ginfout("Название для "..string.sub(screen, 1, 4).." изменено: "..data[3].." ("..doorlist[screen].level..")")
  227.           else
  228.             doorlist[screen].level = level
  229.             ginfout("Уровень изменен: "..doorlist[screen].name.." ("..level..")")
  230.           end
  231.         else
  232.           gerrout("Этот монитор отсутствует в таблице.")
  233.         end
  234.       else
  235.         local name = data[4] or DEFAULT_DOOR
  236.         local level = tonumber(data[5]) or DEFAULT_LEVEL
  237.         toList(doorlist, screen, {name = name, red = red, level = level})
  238.         ginfout("Новый замок: "..name.." ("..level..")")
  239.       end
  240.     end
  241.   -- вывод на экран/очки списков
  242.   elseif data[1] == 'list' then
  243.     if data[2] == 'door' or data[2] == 'doors' then
  244.       if next(doorlist) == nil then ginfout("Таблица пуста.")
  245.       else
  246.         ginfout(" Таблица замков:")
  247.         for a,b in pairs(doorlist) do
  248.           print(string.sub(a, 1, 4), string.sub(b.red, 1, 4), b.name, b.level)
  249.         end
  250.       end
  251.     else
  252.       ginfout(" Таблица пользователей:")
  253.       printlist(userlist)
  254.     end
  255.   elseif data[1] == 'get' then
  256.     if contains(userlist, data[2]) then
  257.       ginfout("Пользователь "..data[2]..", уровень доступа "..userlist[data[2]])
  258.     else
  259.       local screen = com.get(data[2], 'screen')
  260.       if screen ~= nil then
  261.         if contains(doorlist, screen) then
  262.           ginfout("\n"..string.sub(screen, 1, 4), string.sub(doorlist[screen].red, 1, 4), doorlist[screen].name, doorlist[screen].level)
  263.         else
  264.           gerrout("Этот замок в таблице отсутствует.")
  265.         end
  266.       else
  267.         gerrout("Такого не существует.")
  268.       end
  269.     end
  270.   -- удаление двери или игрока из списка
  271.   elseif data[1] == 'delete' or data[1] == 'remove' then
  272.     local screen = com.get(data[2], 'screen')
  273.     if screen == nil then
  274.       if contains(userlist, data[2]) then
  275.         fromList(userlist, data[2])
  276.         ginfout("Игрок "..data[2].." успешно удален из списка.")
  277.       else
  278.         gerrout("Неверное имя/адрес.")
  279.       end
  280.     else
  281.       fromList(doorlist, screen)
  282.       ginfout("Замок по адресу "..data[2].." успешно удален из списка.")
  283.     end
  284.   -- вывод лога
  285.   elseif data[1] == 'log' then
  286.     if data[2] == 'clear' then
  287.       log = {}
  288.       log_new = 1
  289.       ginfout("Лог очищен.")
  290.     elseif data[2] == 'all' then
  291.       printlog()
  292.     else
  293.       printlog(log_new)
  294.     end
  295.   -- выход из программы
  296.   elseif data[1] == 'exit' or data[1] == 'quit' or data[1] == 'q' then return false
  297.   else gerrout("Команда не знакома.") end
  298.   -- успешное выполнение
  299.   return true
  300. end
  301.  
  302. function open(address, flag)
  303.   local red = com.proxy(doorlist[address].red)
  304.   if red == nil then
  305.     gerrout("Проверьте данные для "..doorlist[address].name.." ("..string.sub(address, 1, 4)..")!")
  306.   else
  307.     -- если дверь открывается - показываем смайлик и записываем время
  308.     if not flag then
  309.       show(address, ALLOW)
  310.       doorlist[address].time = comp.uptime()
  311.     end
  312.    
  313.     for i=0, 5 do
  314.       if flag then
  315.         red.setOutput(i, 0)
  316.       else
  317.         red.setOutput(i, RED_STRENGTH)
  318.       end
  319.     end
  320.   end
  321. end
  322.  
  323. -- ============================================ E M O T I C O N S ============================================ --
  324. function show(address, str)
  325.   agpu.bind(address)
  326.   agpu.setResolution(5,1)
  327.   if str == ALLOW then
  328.     agpu.setForeground(allowcolor)
  329.   elseif str == WAIT then
  330.     agpu.setForeground(warncolor)
  331.   else
  332.     agpu.setForeground(errorcolor)
  333.   end
  334.   agpu.set(1, 1, str)
  335. end
  336.  
  337. -- ============================================== G L A S S E S ============================================== --
  338. glass_uptime = 0
  339.  
  340. function glass_clear()
  341.   if glass ~= nil then
  342.     glass.clear()
  343.   end
  344. end
  345. function glass_addText(x, y, text, color)
  346.   if glass ~= nil then
  347.     obj = {}
  348.     obj[0] = glass.addText(x+1, y+1, text, 0x000000)
  349.     obj[1] = glass.addText(x, y, text, color)
  350.     return obj
  351.   end
  352. end
  353. function glass_splash(message, app)
  354.   if glass ~= nil then
  355.     glass_clear()
  356.  
  357.     local width = #message*5.3; title = '[ Message ]'; color = 0xFFFFFF
  358.     x = GLASSX - width/2; y = GLASSY-10
  359.     if app == 0 then
  360.       color = infocolor
  361.       title = '[ INFO ]'
  362.     elseif app == 1 then
  363.       color = warncolor
  364.       title = '[ WARNING ]'
  365.     else
  366.       color = errorcolor
  367.       title = '[ ERROR ]'
  368.     end
  369.     glass.addBox(x, y, width, 20, color, 0.5)
  370.     glass_addText(GLASSX - 17, GLASSY-11, title, 0xFFFFFF)
  371.     glass_addText(x+10, GLASSY, message, 0xFFFFFF)
  372.     glass_uptime = comp.uptime()
  373.   end
  374. end
  375. function ginfout(message)
  376.   infout(message)
  377.   glass_splash(message, 0)
  378. end
  379. function gwarnout(message)
  380.   warnout(message)
  381.   glass_splash(message, 1)
  382. end
  383. function gerrout(message)
  384.   errout(message)
  385.   glass_splash(message, 2)
  386. end
  387.  
  388. -- ======================================== N E T   I N T E R F A C E ======================================== --
  389. function sendPackage(message)
  390.   if modem ~= nil then
  391.     modem.broadcast(PORT, message)
  392.   end
  393. end
  394.  
  395. -- ================================================= M A I N ================================================= --
  396. if glass ~= nil then glass.clear() end
  397. if modem ~= nil then modem.open(PORT) end
  398.  
  399. userlist = readList('userlist.txt')
  400. doorlist = readList('doorlist.txt')
  401.  
  402. history = {}
  403. infout("Нажмите любую кнопку, чтобы перейти в режим ввода команд.")
  404.  
  405. -- Главный цикл - обновление/обработка --
  406. while true do
  407.   -- ждем событие
  408.   name, add, a, b, c, d = event.pull(OPEN_TIME+0.2)
  409.  
  410.   -- чистим очки
  411.   if glass_uptime ~= 0 then
  412.     if (comp.uptime() - glass_uptime) > GLASS_TIME then
  413.       glass_clear()
  414.       glass_uptime = 0
  415.     end
  416.   end
  417.  
  418.   -- закрываем двери
  419.   for a,b in pairs(doorlist) do
  420.     if b.time ~= nil then
  421.       if (comp.uptime() - b.time) > OPEN_TIME then
  422.         open(a, true)
  423.         b.time = nil
  424.       end
  425.     end
  426.   end
  427.  
  428.   -- обработка пользовательских команд с терминала и очков
  429.   if name == 'key_down' then
  430.     term.write("\n>> ")
  431.     command = term.read(history)
  432.     if not process(command, true) then break end
  433.   elseif name == 'chat_command' then
  434.     if not process(add, false) then break end
  435.  
  436.   -- обработка "звонков в двери"
  437.   elseif name == 'touch' then
  438.     if contains(doorlist, add) then
  439.       -- выводим информацию
  440.       print("\n"..d.." у "..doorlist[add].name.." ("..string.sub(add, 1, 4)..")!")
  441.       -- отчет для лога
  442.       local date = os.date()
  443.       log_message = date..' / '..d..' / '..doorlist[add].name.." ("..string.sub(add, 1, 4)..") | "
  444.       net_message = {date = date, player = d, door = doorlist[add].name, address = add}
  445.  
  446.       -- проверка по списку
  447.       if not contains(userlist, d) then
  448.         glass_splash(log_message..'?', 1)
  449.         show(add, WAIT)
  450.         warnout("В списке его нет. Что делать?")
  451.         toLog(log_message..'?')
  452.         last_door = add
  453.        
  454.         net_message.message = '?'
  455.         sendPackage(serial.serialize(net_message))
  456.       else
  457.         if doorlist[add].level > userlist[d] then
  458.           glass_splash(log_message..'X', 2)
  459.           show(add, DENY)
  460.           print("В доступе отказано!")
  461.           toLog(log_message..'X')
  462.          
  463.           net_message.message = 'X'
  464.           sendPackage(serial.serialize(net_message))
  465.         else
  466.           glass_splash(log_message..'Y', 0)
  467.           open(add)
  468.           print("Доступ разрешен.")
  469.           toLog(log_message..'Y')
  470.  
  471.           net_message.message = 'Y'
  472.           sendPackage(serial.serialize(net_message))
  473.         end
  474.       end
  475.     end
  476.  
  477.   -- обрабатывает сообщения по сети
  478.   elseif name == 'modem_message' then
  479.     local data = serial.unserialize(d)
  480.     if data.command == 'open' then
  481.       trytoopen(data.address)
  482.     end
  483.   end
  484. end
  485.  
  486. -- завершение (сохраняем списки, чистим экран)
  487. if modem ~= nil then modem.close(PORT) end
  488. saveList(userlist, 'userlist.txt')
  489. saveList(doorlist, 'doorlist.txt')
  490. term.clear()
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×