Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Global Chat Client for ComputerCraft
- -- Connects automatically to the "global" chat host
- -- Remembers username, supports -log option, clears screen on start
- term.clear()
- term.setCursorPos(1,1)
- local tArgs = { ... }
- -- Logging feature
- local bLogging = false
- for i = 1, #tArgs do
- if tArgs[i] == "-log" then
- bLogging = true
- table.remove(tArgs, i)
- break
- end
- end
- local logFile
- if bLogging then
- logFile = fs.open("chat_log.txt", "a")
- local oldPrint = print
- local oldWrite = write
- local function logWrite(text)
- if logFile then
- logFile.write(text)
- logFile.flush()
- end
- end
- function write(...)
- local t = table.pack(...)
- for i = 1, t.n do
- oldWrite(t[i])
- logWrite(t[i])
- end
- end
- function print(...)
- local t = table.pack(...)
- local text = table.concat(t, " ")
- oldPrint(text)
- logWrite(text .. "\n")
- end
- print("Logging enabled. Output will be written to chat_log.txt")
- end
- -- Utility functions
- local sOpenedModem = nil
- local function openModem()
- for _, sModem in ipairs(peripheral.getNames()) do
- if peripheral.getType(sModem) == "modem" then
- if not rednet.isOpen(sModem) then
- rednet.open(sModem)
- sOpenedModem = sModem
- end
- return true
- end
- end
- print("No modems found.")
- return false
- end
- local function closeModem()
- if sOpenedModem ~= nil then
- rednet.close(sOpenedModem)
- sOpenedModem = nil
- end
- end
- -- Colours
- local highlightColour, textColour
- if term.isColour() then
- textColour = colours.white
- highlightColour = colours.yellow
- else
- textColour = colours.white
- highlightColour = colours.white
- end
- -- Always connect to global
- local sHostname = "global"
- -- Username handling
- local sUsername
- if fs.exists("chat_username.txt") then
- local f = fs.open("chat_username.txt", "r")
- sUsername = f.readAll()
- f.close()
- sUsername = sUsername:gsub("%s+$", "")
- print("Using saved username: " .. sUsername)
- else
- write("Enter your username: ")
- sUsername = read()
- local f = fs.open("chat_username.txt", "w")
- f.write(sUsername)
- f.close()
- end
- -- Connect to global chat
- if not openModem() then return end
- write("Looking up " .. sHostname .. "... ")
- local nHostID = rednet.lookup("chat", sHostname)
- if not nHostID then
- print("Failed to find host '" .. sHostname .. "'.")
- return
- else
- print("Success.")
- end
- -- Login
- local nUserID = math.random(1, 2147483647)
- rednet.send(nHostID, {
- sType = "login",
- nUserID = nUserID,
- sUsername = sUsername,
- }, "chat")
- -- Setup ping-pong to keep connection alive
- local bPingPonged = true
- local pingPongTimer = os.startTimer(0)
- local function ping()
- rednet.send(nHostID, {
- sType = "ping to server",
- nUserID = nUserID,
- }, "chat")
- bPingPonged = false
- pingPongTimer = os.startTimer(15)
- end
- -- UI setup
- local w, h = term.getSize()
- local parentTerm = term.current()
- local titleWindow = window.create(parentTerm, 1, 1, w, 1, true)
- local historyWindow = window.create(parentTerm, 1, 2, w, h - 2, true)
- local promptWindow = window.create(parentTerm, 1, h, w, 1, true)
- historyWindow.setCursorPos(1, h - 2)
- term.clear()
- term.setTextColour(textColour)
- term.redirect(promptWindow)
- promptWindow.restoreCursor()
- local function drawTitle()
- local w = titleWindow.getSize()
- local sTitle = sUsername .. " on " .. sHostname
- titleWindow.setTextColour(highlightColour)
- titleWindow.setCursorPos(math.floor(w / 2 - #sTitle / 2), 1)
- titleWindow.clearLine()
- titleWindow.write(sTitle)
- promptWindow.restoreCursor()
- end
- local function printMessage(sMessage)
- term.redirect(historyWindow)
- print()
- if string.match(sMessage, "^%*") then
- term.setTextColour(highlightColour)
- write(sMessage)
- term.setTextColour(textColour)
- else
- local sUsernameBit = string.match(sMessage, "^<[^>]*>")
- if sUsernameBit then
- term.setTextColour(highlightColour)
- write(sUsernameBit)
- term.setTextColour(textColour)
- write(string.sub(sMessage, #sUsernameBit + 1))
- else
- write(sMessage)
- end
- end
- term.redirect(promptWindow)
- promptWindow.restoreCursor()
- end
- drawTitle()
- -- Run client logic
- local ok, error = pcall(parallel.waitForAny,
- function() -- timer handler
- while true do
- local sEvent, timer = os.pullEvent()
- if sEvent == "timer" then
- if timer == pingPongTimer then
- if not bPingPonged then
- printMessage("Server timeout.")
- return
- else
- ping()
- end
- end
- elseif sEvent == "term_resize" then
- local w, h = parentTerm.getSize()
- titleWindow.reposition(1, 1, w, 1)
- historyWindow.reposition(1, 2, w, h - 2)
- promptWindow.reposition(1, h, w, 1)
- end
- end
- end,
- function() -- receive messages
- while true do
- local nSenderID, tMessage = rednet.receive("chat")
- if nSenderID == nHostID and type(tMessage) == "table" and tMessage.nUserID == nUserID then
- if tMessage.sType == "text" then
- local sText = tMessage.sText
- if sText then printMessage(sText) end
- elseif tMessage.sType == "ping to client" then
- rednet.send(nSenderID, { sType = "pong to server", nUserID = nUserID }, "chat")
- elseif tMessage.sType == "pong to client" then
- bPingPonged = true
- elseif tMessage.sType == "kick" then
- return
- end
- end
- end
- end,
- function() -- send messages
- local tSendHistory = {}
- while true do
- promptWindow.setCursorPos(1, 1)
- promptWindow.clearLine()
- promptWindow.setTextColor(highlightColour)
- promptWindow.write(": ")
- promptWindow.setTextColor(textColour)
- local sChat = read(nil, tSendHistory)
- if string.match(sChat, "^/logout") then
- break
- else
- rednet.send(nHostID, {
- sType = "chat",
- nUserID = nUserID,
- sText = sChat,
- }, "chat")
- table.insert(tSendHistory, sChat)
- end
- end
- end
- )
- term.redirect(parentTerm)
- local _, h = term.getSize()
- term.setCursorPos(1, h)
- term.clearLine()
- term.setCursorBlink(false)
- if not ok then printError(error) end
- -- Logout
- rednet.send(nHostID, { sType = "logout", nUserID = nUserID }, "chat")
- closeModem()
- print("Disconnected.")
Advertisement
Add Comment
Please, Sign In to add comment