Advertisement
nonogamer9

OC-DALNET: DALNET For OpenComputers

Jul 24th, 2024 (edited)
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.36 KB | Software | 0 0
  1. local component = require("component")
  2. local term = require("term")
  3. local event = require("event")
  4. local keyboard = require("keyboard")
  5. local gpu = component.gpu
  6. local internet = component.internet
  7. local filesystem = require("filesystem")
  8. local computer = require("computer")
  9.  
  10. local function getGPUTier()
  11.   local w, h = gpu.maxResolution()
  12.   if w == 50 and h == 16 then
  13.     return 1
  14.   elseif w == 80 and h == 25 then
  15.     return 2
  16.   else
  17.     return 3
  18.   end
  19. end
  20.  
  21. local isColorSupported = false
  22. if gpu and gpu.maxDepth then
  23.     isColorSupported = gpu.maxDepth() > 1
  24. end
  25.  
  26. local servers = {
  27.   {address = "atw.hu.eu.dal.net", port = 6667},
  28.   {address = "bifrost.ca.us.dal.net", port = 6667},
  29.   {address = "bitcoin.uk.eu.dal.net", port = 6667},
  30.   {address = "choopa.nj.us.dal.net", port = 6667},
  31.   {address = "halcyon.il.us.dal.net", port = 6667},
  32.   {address = "istana.il.us.dal.net", port = 6667},
  33.   {address = "lair.nl.eu.dal.net", port = 6667},
  34.   {address = "lion.tx.us.dal.net", port = 6667},
  35.   {address = "punch.wa.us.dal.net", port = 6667},
  36.   {address = "sakura.jp.as.dal.net", port = 6667},
  37.   {address = "serenity.fl.us.dal.net", port = 6667},
  38.   {address = "nonstop.ix.me.dal.net", port = 6667},
  39. }
  40.  
  41. local selectedServerIndex = 1
  42. local username = "User"
  43. local socket = nil
  44. local currentChannel = nil
  45.  
  46. local messageBuffer = {}
  47. local maxBufferSize = 49
  48. local currentBufferIndex = 1
  49.  
  50. local function saveUsername()
  51.   local file = io.open("/home/dalnet_username.txt", "w")
  52.   if file then
  53.     file:write(username)
  54.     file:close()
  55.   end
  56. end
  57.  
  58. local function loadUsername()
  59.   local file = io.open("/home/dalnet_username.txt", "r")
  60.   if file then
  61.     username = file:read("*all")
  62.     file:close()
  63.   end
  64. end
  65.  
  66. loadUsername()
  67.  
  68. local function drawLogo()
  69.   if getGPUTier() == 1 then
  70.     return
  71.   end
  72.  
  73.   local logo = {
  74.     " ________  ________          ________  ________  ___       ________   _______  _________   ",
  75.     "|\\   __  \\|\\   ____\\        |\\   ___ \\|\\   __  \\|\\  \\     |\\   ___  \\|\\  ___ \\|\\___   ___\\ ",
  76.     "\\ \\  \\|\\  \\ \\  \\___|        \\ \\  \\_|\\ \\ \\  \\|\\  \\ \\  \\    \\ \\  \\\\ \\  \\ \\   __/\\|___ \\  \\_| ",
  77.     " \\ \\  \\\\\\  \\ \\  \\            \\ \\  \\ \\\\ \\ \\   __  \\ \\  \\    \\ \\  \\\\ \\  \\ \\  \\_|/__  \\ \\  \\  ",
  78.     "  \\ \\  \\\\\\  \\ \\  \\____        \\ \\  \\_\\\\ \\ \\  \\ \\  \\ \\  \\____\\ \\  \\\\ \\  \\ \\  \\_|\\ \\  \\ \\  \\ ",
  79.     "   \\ \\_______\\ \\_______\\       \\ \\_______\\ \\__\\ \\__\\ \\_______\\ \\__\\\\ \\__\\ \\_______\\  \\ \\__\\",
  80.     "    \\|_______|\\|_______|        \\|_______|\\|__|\\|__|\\|_______|\\|__| \\|__|\\|_______|   \\|__|"
  81.   }
  82.  
  83.   local width, height = gpu.getResolution()
  84.   local startY = height - #logo - 1
  85.  
  86.   for i, line in ipairs(logo) do
  87.     gpu.set(1, startY + i, line)
  88.   end
  89. end
  90.  
  91. local function drawServerList()
  92.   local oldForeground = gpu.getForeground()
  93.   local oldBackground = gpu.getBackground()
  94.  
  95.   gpu.setBackground(0x000000)
  96.   term.clear()
  97.  
  98.   for i, server in ipairs(servers) do
  99.     if i == selectedServerIndex then
  100.       if getGPUTier() == 1 then
  101.         gpu.set(1, i, "-> " .. string.format("%d. %s:%d", i, server.address, server.port))
  102.       else
  103.         gpu.setForeground(0x00FF00)
  104.         gpu.set(1, i, string.format("%d. %s:%d", i, server.address, server.port))
  105.         gpu.setForeground(0xFFFFFF)
  106.       end
  107.     else
  108.       gpu.set(1, i, string.format("%d. %s:%d", i, server.address, server.port))
  109.     end
  110.   end
  111.  
  112.   gpu.setForeground(0xFFFFFF)
  113.   gpu.set(1, #servers + 2, "Press N to change username. Current username: " .. username)
  114.   gpu.set(1, #servers + 3, "Use arrow keys to navigate, Enter to connect, X to exit")
  115.  
  116.   drawLogo()
  117.  
  118.   gpu.setForeground(oldForeground)
  119.   gpu.setBackground(oldBackground)
  120. end
  121.  
  122. local function changeNickname()
  123.   term.write("\nEnter new nickname: ")
  124.   local newNick = term.read()
  125.   newNick = newNick:gsub("\n", "")
  126.   if socket then
  127.     socket.write("NICK " .. newNick .. "\r\n")
  128.   end
  129.   username = newNick
  130.   saveUsername()
  131.   return newNick
  132. end
  133.  
  134. local function readWithTimeout(socket, timeout)
  135.   local start = computer.uptime()
  136.   local buffer = ""
  137.   while computer.uptime() - start < timeout do
  138.     local chunk = socket.read(1024)
  139.     if chunk then
  140.       buffer = buffer .. chunk
  141.       if buffer:find("\n") then
  142.         return buffer
  143.       end
  144.     end
  145.     os.sleep(0.1)
  146.   end
  147.   return buffer ~= "" and buffer or nil
  148. end
  149.  
  150. local function addMessage(message)
  151.   table.insert(messageBuffer, message)
  152.   if #messageBuffer > maxBufferSize then
  153.     table.remove(messageBuffer, 1)
  154.   end
  155.   currentBufferIndex = #messageBuffer
  156. end
  157.  
  158. local function displayBuffer()
  159.   term.clear()
  160.   local startIndex = math.max(1, currentBufferIndex - maxBufferSize + 1)
  161.   for i = startIndex, currentBufferIndex do
  162.     print(messageBuffer[i] or "")
  163.   end
  164. end
  165.  
  166. local function connectToServer(server)
  167.   term.clear()
  168.   addMessage("Connecting to " .. server.address .. " as " .. username)
  169.   displayBuffer()
  170.  
  171.   socket = internet.connect(server.address, server.port)
  172.   if not socket then
  173.     addMessage("Failed to connect to " .. server.address)
  174.     displayBuffer()
  175.     return nil
  176.   end
  177.  
  178.   local timeout = 10
  179.   local start = computer.uptime()
  180.   while not socket.finishConnect() do
  181.     if computer.uptime() - start > timeout then
  182.       addMessage("Connection timed out")
  183.       displayBuffer()
  184.       return nil
  185.     end
  186.     os.sleep(0.1)
  187.   end
  188.  
  189.   socket.write("NICK " .. username .. "\r\n")
  190.   socket.write("USER " .. username .. " 0 * :" .. username .. "\r\n")
  191.  
  192.   local connected = false
  193.   local timeout = 30
  194.   local start = computer.uptime()
  195.  
  196.   while computer.uptime() - start < timeout do
  197.     local response = readWithTimeout(socket, 1)
  198.     if response then
  199.       for line in response:gmatch("[^\r\n]+") do
  200.         addMessage(line)
  201.         if line:find("433") then
  202.           addMessage("Nickname is already in use. Please choose a different nickname.")
  203.           displayBuffer()
  204.           username = changeNickname()
  205.           socket.write("NICK " .. username .. "\r\n")
  206.         elseif line:find("001") then
  207.           addMessage("Successfully connected to " .. server.address .. " as " .. username)
  208.           connected = true
  209.           break
  210.         end
  211.       end
  212.       displayBuffer()
  213.     end
  214.     if connected then break end
  215.   end
  216.  
  217.   if not connected then
  218.     addMessage("Connection timed out or failed")
  219.     displayBuffer()
  220.     socket.close()
  221.     return nil
  222.   end
  223.  
  224.   return socket
  225. end
  226.  
  227. local function disconnectFromServer()
  228.   if socket then
  229.     socket.write("QUIT :Disconnecting\r\n")
  230.     socket.close()
  231.     socket = nil
  232.     currentChannel = nil
  233.     addMessage("Disconnected from server.")
  234.     displayBuffer()
  235.     return true
  236.   end
  237.   return false
  238. end
  239.  
  240. local function exitChannel()
  241.   if currentChannel then
  242.     socket.write("PART " .. currentChannel .. " :Leaving\r\n")
  243.     addMessage("Left channel: " .. currentChannel)
  244.     currentChannel = nil
  245.     displayBuffer()
  246.     return true
  247.   end
  248.   return false
  249. end
  250.  
  251. local function ping()
  252.   if not socket then
  253.     addMessage("Not connected to a server.")
  254.     return
  255.   end
  256.  
  257.   local serverStart = computer.uptime()
  258.   socket.write("PING :serverping\r\n")
  259.  
  260.   local serverPingReceived = false
  261.   local timeout = computer.uptime() + 5
  262.  
  263.   while computer.uptime() < timeout do
  264.     local response = readWithTimeout(socket, 0.1)
  265.     if response then
  266.       for line in response:gmatch("[^\r\n]+") do
  267.         if line:find("PONG :serverping") then
  268.           local serverEnd = computer.uptime()
  269.           local serverPing = (serverEnd - serverStart) * 1000
  270.           addMessage(string.format("Server ping: %.2f ms", serverPing))
  271.           serverPingReceived = true
  272.           break
  273.         end
  274.       end
  275.     end
  276.     if serverPingReceived then break end
  277.   end
  278.  
  279.   if not serverPingReceived then
  280.     addMessage("Server ping timed out.")
  281.   end
  282.  
  283.   if currentChannel then
  284.     local channelStart = computer.uptime()
  285.     socket.write("PRIVMSG " .. currentChannel .. " :\001PING " .. channelStart .. "\001\r\n")
  286.    
  287.     local channelPingReceived = false
  288.     timeout = computer.uptime() + 5
  289.  
  290.     while computer.uptime() < timeout do
  291.       local response = readWithTimeout(socket, 0.1)
  292.       if response then
  293.         for line in response:gmatch("[^\r\n]+") do
  294.           if line:find("NOTICE .* :\001PING (.+)\001") then
  295.             local channelEnd = computer.uptime()
  296.             local pingTime = line:match("NOTICE .* :\001PING (.+)\001")
  297.             local channelPing = (channelEnd - tonumber(pingTime)) * 1000
  298.             addMessage(string.format("Channel ping: %.2f ms", channelPing))
  299.             channelPingReceived = true
  300.             break
  301.           end
  302.         end
  303.       end
  304.       if channelPingReceived then break end
  305.     end
  306.  
  307.     if not channelPingReceived then
  308.       addMessage("Channel ping timed out.")
  309.     end
  310.   else
  311.     addMessage("Not connected to a channel.")
  312.   end
  313.  
  314.   displayBuffer()
  315. end
  316.  
  317. local function showHelp()
  318.   addMessage("Available commands:")
  319.   addMessage(":helpoc - Show this help message")
  320.   addMessage("connect #channel - Join a channel")
  321.   addMessage("exit - Leave the current channel")
  322.   addMessage("disconnect - Disconnect from the server")
  323.   addMessage("ping - Ping the server and current channel")
  324.   displayBuffer()
  325. end
  326.  
  327. local function handleUserInput(isCommand)
  328.   local prefix = isCommand and "Command" or "Chat"
  329.   term.write("\n" .. prefix .. "> ")
  330.   local input = term.read()
  331.   if input then
  332.     input = input:gsub("\n", "")
  333.     if isCommand then
  334.       if input:match("^connect #") then
  335.         currentChannel = input:match("^connect (.+)$")
  336.         socket.write("JOIN " .. currentChannel .. "\r\n")
  337.       elseif input == "disconnect" then
  338.         return disconnectFromServer()
  339.       elseif input == "exit" then
  340.         return exitChannel()
  341.       elseif input == ":helpoc" then
  342.         showHelp()
  343.       elseif input == "ping" then
  344.         ping()
  345.       else
  346.         socket.write(input .. "\r\n")
  347.       end
  348.     else
  349.       if currentChannel then
  350.         socket.write("PRIVMSG " .. currentChannel .. " :" .. input .. "\r\n")
  351.         addMessage("<" .. username .. "> " .. input)
  352.       else
  353.         addMessage("Not connected to a channel. Use 'connect #channel' to join one.")
  354.       end
  355.     end
  356.     displayBuffer()
  357.   end
  358.   return false
  359. end
  360.  
  361. local function handleServerCommunication()
  362.   addMessage("Connected to server. Press Ctrl for chat, Alt for commands.")
  363.   addMessage("Use 'connect #channel' to join a channel, 'exit' to leave a channel, and 'disconnect' to disconnect from the server.")
  364.   addMessage("Use 'ping' to ping the server and current channel.")
  365.   addMessage("Use Up/Down arrows or PageUp/PageDown to scroll through messages.")
  366.   displayBuffer()
  367.  
  368.   while true do
  369.     local data = readWithTimeout(socket, 0.1)
  370.     if data then
  371.       for line in data:gmatch("[^\r\n]+") do
  372.         if line:find("PING") then
  373.           local pingId = line:match("PING :(.+)")
  374.           socket.write("PONG :" .. pingId .. "\r\n")
  375.         elseif line:match("PRIVMSG .* :\001PING ") then
  376.           local user = line:match("^:([^!]+)")
  377.           local pingTime = line:match("PRIVMSG .* :\001PING (.+)\001")
  378.           socket.write("NOTICE " .. user .. " :\001PING " .. pingTime .. "\001\r\n")
  379.         else
  380.           addMessage(line)
  381.         end
  382.       end
  383.       displayBuffer()
  384.     end
  385.  
  386.     local eventName, _, char, code = event.pull(0.1)
  387.     if eventName == "key_down" then
  388.       if code == 29 then
  389.         if handleUserInput(false) then return end
  390.       elseif code == 56 then
  391.         if handleUserInput(true) then return end
  392.       elseif code == 200 then
  393.         currentBufferIndex = math.max(1, currentBufferIndex - 1)
  394.         displayBuffer()
  395.       elseif code == 208 then
  396.         currentBufferIndex = math.min(#messageBuffer, currentBufferIndex + 1)
  397.         displayBuffer()
  398.       elseif code == 201 then
  399.         currentBufferIndex = math.max(1, currentBufferIndex - maxBufferSize)
  400.         displayBuffer()
  401.       elseif code == 209 then
  402.         currentBufferIndex = math.min(#messageBuffer, currentBufferIndex + maxBufferSize)
  403.         displayBuffer()
  404.       end
  405.     end
  406.   end
  407. end
  408.  
  409. local function main()
  410.   while true do
  411.     drawServerList()
  412.     local eventName, _, char, code = event.pull("key_down")
  413.  
  414.     if char == 120 or char == 88 then
  415.       print("Exiting program...")
  416.       os.exit()
  417.     elseif code == 200 then
  418.       selectedServerIndex = math.max(1, selectedServerIndex - 1)
  419.     elseif code == 208 then
  420.       selectedServerIndex = math.min(#servers, selectedServerIndex + 1)
  421.     elseif code == 203 then
  422.       selectedServerIndex = math.max(1, selectedServerIndex - 1)
  423.     elseif code == 205 then
  424.       selectedServerIndex = math.min(#servers, selectedServerIndex + 1)
  425.     elseif char == 110 or char == 78 then
  426.       username = changeNickname()
  427.     elseif code == 28 then
  428.       term.clear()
  429.       socket = connectToServer(servers[selectedServerIndex])
  430.       if not socket then
  431.         addMessage("Connection failed. Press any key to return to server list.")
  432.         displayBuffer()
  433.         event.pull("key_down")
  434.       else
  435.         if isColorSupported then
  436.           gpu.setResolution(gpu.maxResolution())
  437.           gpu.setBackground(0x000000)
  438.           gpu.setForeground(0xFFFFFF)
  439.         end
  440.         handleServerCommunication()
  441.       end
  442.     end
  443.   end
  444. end
  445.  
  446. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement