DorianH935

Untitled

Nov 10th, 2025
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.05 KB | None | 0 0
  1. -- Global Chat Client for ComputerCraft
  2. -- Connects automatically to the "global" chat host
  3. -- Remembers username, supports -log option, clears screen on start
  4.  
  5. term.clear()
  6. term.setCursorPos(1,1)
  7.  
  8. local tArgs = { ... }
  9.  
  10. -- Logging feature
  11. local bLogging = false
  12. for i = 1, #tArgs do
  13. if tArgs[i] == "-log" then
  14. bLogging = true
  15. table.remove(tArgs, i)
  16. break
  17. end
  18. end
  19.  
  20. local logFile
  21. if bLogging then
  22. logFile = fs.open("chat_log.txt", "a")
  23. local oldPrint = print
  24. local oldWrite = write
  25.  
  26. local function logWrite(text)
  27. if logFile then
  28. logFile.write(text)
  29. logFile.flush()
  30. end
  31. end
  32.  
  33. function write(...)
  34. local t = table.pack(...)
  35. for i = 1, t.n do
  36. oldWrite(t[i])
  37. logWrite(t[i])
  38. end
  39. end
  40.  
  41. function print(...)
  42. local t = table.pack(...)
  43. local text = table.concat(t, " ")
  44. oldPrint(text)
  45. logWrite(text .. "\n")
  46. end
  47.  
  48. print("Logging enabled. Output will be written to chat_log.txt")
  49. end
  50.  
  51. -- Utility functions
  52. local sOpenedModem = nil
  53. local function openModem()
  54. for _, sModem in ipairs(peripheral.getNames()) do
  55. if peripheral.getType(sModem) == "modem" then
  56. if not rednet.isOpen(sModem) then
  57. rednet.open(sModem)
  58. sOpenedModem = sModem
  59. end
  60. return true
  61. end
  62. end
  63. print("No modems found.")
  64. return false
  65. end
  66.  
  67. local function closeModem()
  68. if sOpenedModem ~= nil then
  69. rednet.close(sOpenedModem)
  70. sOpenedModem = nil
  71. end
  72. end
  73.  
  74. -- Colours
  75. local highlightColour, textColour
  76. if term.isColour() then
  77. textColour = colours.white
  78. highlightColour = colours.yellow
  79. else
  80. textColour = colours.white
  81. highlightColour = colours.white
  82. end
  83.  
  84. -- Always connect to global
  85. local sHostname = "global"
  86.  
  87. -- Username handling
  88. local sUsername
  89. if fs.exists("chat_username.txt") then
  90. local f = fs.open("chat_username.txt", "r")
  91. sUsername = f.readAll()
  92. f.close()
  93. sUsername = sUsername:gsub("%s+$", "")
  94. print("Using saved username: " .. sUsername)
  95. else
  96. write("Enter your username: ")
  97. sUsername = read()
  98. local f = fs.open("chat_username.txt", "w")
  99. f.write(sUsername)
  100. f.close()
  101. end
  102.  
  103. -- Connect to global chat
  104. if not openModem() then return end
  105. write("Looking up " .. sHostname .. "... ")
  106. local nHostID = rednet.lookup("chat", sHostname)
  107. if not nHostID then
  108. print("Failed to find host '" .. sHostname .. "'.")
  109. return
  110. else
  111. print("Success.")
  112. end
  113.  
  114. -- Login
  115. local nUserID = math.random(1, 2147483647)
  116. rednet.send(nHostID, {
  117. sType = "login",
  118. nUserID = nUserID,
  119. sUsername = sUsername,
  120. }, "chat")
  121.  
  122. -- Setup ping-pong to keep connection alive
  123. local bPingPonged = true
  124. local pingPongTimer = os.startTimer(0)
  125. local function ping()
  126. rednet.send(nHostID, {
  127. sType = "ping to server",
  128. nUserID = nUserID,
  129. }, "chat")
  130. bPingPonged = false
  131. pingPongTimer = os.startTimer(15)
  132. end
  133.  
  134. -- UI setup
  135. local w, h = term.getSize()
  136. local parentTerm = term.current()
  137. local titleWindow = window.create(parentTerm, 1, 1, w, 1, true)
  138. local historyWindow = window.create(parentTerm, 1, 2, w, h - 2, true)
  139. local promptWindow = window.create(parentTerm, 1, h, w, 1, true)
  140. historyWindow.setCursorPos(1, h - 2)
  141.  
  142. term.clear()
  143. term.setTextColour(textColour)
  144. term.redirect(promptWindow)
  145. promptWindow.restoreCursor()
  146.  
  147. local function drawTitle()
  148. local w = titleWindow.getSize()
  149. local sTitle = sUsername .. " on " .. sHostname
  150. titleWindow.setTextColour(highlightColour)
  151. titleWindow.setCursorPos(math.floor(w / 2 - #sTitle / 2), 1)
  152. titleWindow.clearLine()
  153. titleWindow.write(sTitle)
  154. promptWindow.restoreCursor()
  155. end
  156.  
  157. local function printMessage(sMessage)
  158. term.redirect(historyWindow)
  159. print()
  160. if string.match(sMessage, "^%*") then
  161. term.setTextColour(highlightColour)
  162. write(sMessage)
  163. term.setTextColour(textColour)
  164. else
  165. local sUsernameBit = string.match(sMessage, "^<[^>]*>")
  166. if sUsernameBit then
  167. term.setTextColour(highlightColour)
  168. write(sUsernameBit)
  169. term.setTextColour(textColour)
  170. write(string.sub(sMessage, #sUsernameBit + 1))
  171. else
  172. write(sMessage)
  173. end
  174. end
  175. term.redirect(promptWindow)
  176. promptWindow.restoreCursor()
  177. end
  178.  
  179. drawTitle()
  180.  
  181. -- Run client logic
  182. local ok, error = pcall(parallel.waitForAny,
  183. function() -- timer handler
  184. while true do
  185. local sEvent, timer = os.pullEvent()
  186. if sEvent == "timer" then
  187. if timer == pingPongTimer then
  188. if not bPingPonged then
  189. printMessage("Server timeout.")
  190. return
  191. else
  192. ping()
  193. end
  194. end
  195. elseif sEvent == "term_resize" then
  196. local w, h = parentTerm.getSize()
  197. titleWindow.reposition(1, 1, w, 1)
  198. historyWindow.reposition(1, 2, w, h - 2)
  199. promptWindow.reposition(1, h, w, 1)
  200. end
  201. end
  202. end,
  203. function() -- receive messages
  204. while true do
  205. local nSenderID, tMessage = rednet.receive("chat")
  206. if nSenderID == nHostID and type(tMessage) == "table" and tMessage.nUserID == nUserID then
  207. if tMessage.sType == "text" then
  208. local sText = tMessage.sText
  209. if sText then printMessage(sText) end
  210. elseif tMessage.sType == "ping to client" then
  211. rednet.send(nSenderID, { sType = "pong to server", nUserID = nUserID }, "chat")
  212. elseif tMessage.sType == "pong to client" then
  213. bPingPonged = true
  214. elseif tMessage.sType == "kick" then
  215. return
  216. end
  217. end
  218. end
  219. end,
  220. function() -- send messages
  221. local tSendHistory = {}
  222. while true do
  223. promptWindow.setCursorPos(1, 1)
  224. promptWindow.clearLine()
  225. promptWindow.setTextColor(highlightColour)
  226. promptWindow.write(": ")
  227. promptWindow.setTextColor(textColour)
  228.  
  229. local sChat = read(nil, tSendHistory)
  230. if string.match(sChat, "^/logout") then
  231. break
  232. else
  233. rednet.send(nHostID, {
  234. sType = "chat",
  235. nUserID = nUserID,
  236. sText = sChat,
  237. }, "chat")
  238. table.insert(tSendHistory, sChat)
  239. end
  240. end
  241. end
  242. )
  243.  
  244. term.redirect(parentTerm)
  245. local _, h = term.getSize()
  246. term.setCursorPos(1, h)
  247. term.clearLine()
  248. term.setCursorBlink(false)
  249. if not ok then printError(error) end
  250.  
  251. -- Logout
  252. rednet.send(nHostID, { sType = "logout", nUserID = nUserID }, "chat")
  253. closeModem()
  254. print("Disconnected.")
  255.  
Advertisement
Add Comment
Please, Sign In to add comment