Advertisement
ColdIV

cldvChat

Jul 11th, 2021 (edited)
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.77 KB | None | 0 0
  1. local programName = "cldvChat"
  2. local args = {...}
  3. local dtype = args[1]
  4.  
  5. local modemPosition
  6. if pocket then
  7.     modemPosition = "back"
  8. else
  9.     modemPosition = "right"
  10. end
  11.  
  12. ---
  13. -- Helper Functions
  14. function findDeviceIndex (t, target)
  15.     for i = 1, #t, 1 do
  16.         if t[i].id == target then
  17.             return i
  18.         end
  19.     end
  20.     return 0
  21. end
  22.  
  23. function prettyPrint (prefix, text, prefixColor, textColor, bgColor)
  24.     local colors = {
  25.         ["white"] = "0",
  26.         ["0"] = "0",
  27.         ["orange"] = "1",
  28.         ["1"] = "1",
  29.         ["magenta"] = "2",
  30.         ["2"] = "2",
  31.         ["lightblue"] = "3",
  32.         ["3"] = "3",
  33.         ["yellow"] = "4",
  34.         ["4"] = "4",
  35.         ["lime"] = "5",
  36.         ["5"] = "5",
  37.         ["pink"] = "6",
  38.         ["6"] = "6",
  39.         ["gray"] = "7",
  40.         ["7"] = "7",
  41.         ["lightgray"] = "8",
  42.         ["8"] = "8",
  43.         ["cyan"] = "9",
  44.         ["9"] = "9",
  45.         ["purple"] = "a",
  46.         ["a"] = "a",
  47.         ["blue"] = "b",
  48.         ["b"] = "b",
  49.         ["brown"] = "c",
  50.         ["c"] = "c",
  51.         ["green"] = "d",
  52.         ["d"] = "d",
  53.         ["red"] = "e",
  54.         ["e"] = "e",
  55.         ["black"] = "f",
  56.         ["f"] = "f"
  57.     }
  58.    
  59.     prefixColor = colors[prefixColor] or "b"
  60.     textColor = colors[textColor] or "0"
  61.     bgColor = colors[bgColor] or "f"
  62.    
  63.     local deviceWidth, _ = term.current().getSize()
  64.    
  65.     local texts = {}
  66.     texts[1] = text
  67.    
  68.     local idx = 1
  69.     local maxLength = deviceWidth - #prefix
  70.    
  71.     -- Split text after last space or after maxLength if the string is too long
  72.     -- Note: The prefix has to be smaller than the maxLength.
  73.     while (#texts[idx] > maxLength) do
  74.         local lastSpace = nil
  75.         local offset = 0
  76.        
  77.         lastSpace = string.sub(texts[idx], 1, maxLength):match'^.*() '
  78.        
  79.         if string.find(texts[idx], "\n") then
  80.             local start, _ = string.find(texts[idx], "\n")
  81.             offset = 1
  82.             lastSpace = math.min(lastSpace, start - 1)
  83.         end
  84.        
  85.         if lastSpace == nil then lastSpace = maxLength end
  86.         if idx == 1 then maxLength = deviceWidth end
  87.        
  88.         texts[idx + 1] = string.sub(texts[idx], lastSpace + 1 + offset)
  89.         texts[idx] = string.sub(texts[idx], 1, lastSpace)
  90.         idx = idx + 1
  91.     end
  92.    
  93.     -- Setup color strings
  94.     local tColorS = ""
  95.     local bgColorS = ""
  96.    
  97.     for i = 1, #prefix, 1 do
  98.         tColorS = tColorS .. prefixColor
  99.         bgColorS = bgColorS .. bgColor
  100.     end
  101.    
  102.     -- Print prefix
  103.     term.blit(prefix, tColorS, bgColorS)
  104.    
  105.     -- Print texts
  106.     for i = 1, #texts, 1 do
  107.         tColorS = ""
  108.         bgColorS = ""
  109.         for j = 1, #texts[i], 1 do
  110.             tColorS = tColorS .. textColor
  111.             bgColorS = bgColorS .. bgColor
  112.         end
  113.        
  114.         term.blit(texts[i], tColorS, bgColorS)
  115.         print("")
  116.     end
  117.    
  118.     return #texts
  119. end
  120.  
  121. function printMessage (name, message, sender)
  122.     sender = sender or false
  123.     local nameColor = "b"
  124.    
  125.     if sender then
  126.         nameColor = "5"
  127.     end
  128.    
  129.     name = name .. ": "
  130.     return prettyPrint(name, message, nameColor)
  131. end
  132. ---
  133.  
  134. function client ()
  135.     local protocol = args[2] or "cldvChat"
  136.     local hostname = args[3] or "cldvChatServer"
  137.     local clientName = args[4] or nil
  138.    
  139.     if not clientName then
  140.         prettyPrint ("", "Please enter your name: ", nil, "8")
  141.         clientName = read()
  142.     end
  143.    
  144.     while #clientName > 20 do
  145.         prettyPrint ("", "Your name is too long! Enter a smaller name: ", nil, "8")
  146.         clientName = read()
  147.     end
  148.    
  149.     local hosts = rednet.lookup(protocol, hostname)
  150.     if tonumber(hosts) then
  151.         local tmpHosts = hosts
  152.         hosts = {}
  153.         hosts[1] = tmpHosts
  154.     end
  155.    
  156.     for i = 1, #hosts, 1 do
  157.         if not rednet.send(hosts[i], "/" .. clientName, protocol)  then
  158.             error("Could not send message.")
  159.         else
  160.             prettyPrint ("", "Connected! Type /quit to disconnect", nil, "8")
  161.         end
  162.     end
  163.    
  164.    
  165.     parallel.waitForAny(
  166.         -- Receive messages
  167.         function ()
  168.             local message
  169.             while true do
  170.                 _, message, _ = rednet.receive(protocol)
  171.                 local separator, _ = string.find(message, ":")
  172.                 local isCommand, _ = string.find(message, "/")
  173.                 if separator and not isCommand then
  174.                     local name = string.sub(message, 1, separator - 1)
  175.                     message = string.sub(message, separator + 2)
  176.                     term.clearLine()
  177.                     local x, y = term.getCursorPos()
  178.                     term.setCursorPos(1, y)
  179.                     printMessage(name, message, false)
  180.                 end
  181.                 --print (message)
  182.             end
  183.         end,
  184.         -- Send messages
  185.         function ()
  186.             local message
  187.             while true do
  188.                 message = read()
  189.                 if message == "/quit" then
  190.                     prettyPrint ("", "Disconnected!", nil, "8")
  191.                     return
  192.                 end
  193.                
  194.                 -- Clear read output and write it prettier
  195.                 local x, y = term.getCursorPos()
  196.                 term.setCursorPos(x, y - 1)
  197.                 term.clearLine()
  198.                 local _, maxHeight = term.current().getSize()
  199.                 local offset = printMessage(clientName, message, true) - 1
  200.                 y = math.min(y + offset, maxHeight)
  201.                 term.setCursorPos(x, y)
  202.                
  203.                 for i = 1, #hosts, 1 do
  204.                     if not rednet.send(hosts[i], message, protocol)  then
  205.                         error("Could not send message.")
  206.                     end
  207.                 end
  208.             end
  209.         end
  210.     )
  211.    
  212.     for i = 1, #hosts, 1 do
  213.         if not rednet.send(hosts[i], "/quit", protocol)  then
  214.             error("Could not send message.")
  215.         end
  216.     end
  217. end
  218.  
  219. function server ()
  220.     local protocol = args[2] or "cldvChat"
  221.     local name = args[3] or "cldvChatServer"
  222.     local devices = {}
  223.     rednet.host(protocol, name)
  224.     prettyPrint ("", "Server running!", nil, "8")
  225.    
  226.     while true do
  227.         local deviceID
  228.         local message
  229.         deviceID, message, _ = rednet.receive(protocol)
  230.    
  231.         local index = findDeviceIndex(devices, deviceID)
  232.        
  233.         local isCommand, _ = string.find(message, "/")
  234.        
  235.         -- Add device
  236.         if index == 0 then
  237.             local device = {
  238.                 name = string.sub(message, 2),
  239.                 id = deviceID
  240.             }
  241.             table.insert(devices, device)
  242.             prettyPrint ("", "Add client " .. device.name .. " with ID " .. tostring(deviceID), nil, "8")
  243.         -- Remove device
  244.         elseif message == "/quit" then
  245.             if index == 0 then
  246.                 error("Could not remove device, index not found.")
  247.             else
  248.                 local device = devices[index]
  249.                 table.remove(devices, index)
  250.                 prettyPrint ("", device.name .. " with ID " .. tostring(deviceID) .. " disconnected.", nil, "8")
  251.                 device = nil
  252.             end
  253.         elseif isCommand then
  254.             prettyPrint ("", devices[index].name .. " tried to connect but is already connected.", nil, "8")
  255.         -- Send message to all connected devices
  256.         else
  257.             -- Print to server log
  258.             printMessage(devices[index].name, message, false)
  259.             message = devices[index].name .. ": " .. message
  260.             -- Send message to all clients
  261.             for i = 1, #devices, 1 do
  262.                 if deviceID ~= devices[i].id then
  263.                     if not rednet.send(devices[i].id, message, protocol) then
  264.                         error("Could not send message.")
  265.                     end
  266.                 end
  267.             end
  268.         end
  269.        
  270.     end
  271.    
  272.    
  273.     rednet.unhost(protocol)
  274. end
  275.  
  276. function main ()
  277.     if not rednet.isOpen(modemPosition) then
  278.         error("Could not open modem '".. modemPosition .. "'")
  279.         return
  280.     end
  281.    
  282.     if dtype == "client" then
  283.         client()
  284.     elseif dtype == "server" then
  285.         server()
  286.     elseif dtype == "update" then
  287.         shell.run("pastebin", "run", "FuQ3WvPs 4izkdH5g " .. programName)
  288.     elseif dtype == "help" then
  289.         prettyPrint ("", "Arguments:\n - " .. programName .. " server <protocol> <hostname>\n - " .. programName .. " client <protocol> <hostname> <username>\n - " .. programName .. " update\n - " .. programName .. " help\n", nil, "8")
  290.     else
  291.         error("Please specify the device type as 'server' or 'client' by passing it as the first argument.")
  292.     end
  293. end
  294.  
  295. rednet.open(modemPosition)
  296. main()
  297. rednet.close(modemPosition)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement