Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Metadata and Constants
- local authorName = "Rare Corp."
- local logoArt = [[
- ___ _____
- / _ \___ ________ / ___/__ _______
- / , _/ _ `/ __/ -_) /__/ _ \/ __/ _ \
- /_/|_|\_,_/_/ \__/\___/\___/_/ / .__/
- /_/ ]]
- local productVersion = "1.0"
- local productName = "CC-AI Chat Client"
- local rateLimitMs = 2000 -- 2 seconds in milliseconds
- local maxBufferLength = 1000 -- Limit the size of the conversation buffer
- local lastRequestTime = 0
- local rateLimit = 1 -- Rate limit in seconds, change as needed
- -- Colors
- local uiColors = {
- userNameColor = colors.blue,
- userChatColor = colors.lightBlue,
- otherNameColor = colors.orange,
- otherChatColor = colors.yellow,
- commandColor = colors.purple,
- errorColor = colors.red,
- systemColor = colors.green,
- helpColor = colors.cyan,
- }
- -- randomize logo color
- local logoColors = {colors.orange, colors.magenta, colors.lightBlue, colors.yellow, colors.lime, colors.pink, colors.cyan, colors.purple, colors.blue, colors.green, colors.red}
- local logoColor = logoColors[math.random(#logoColors)]
- -- Configuration
- local configFileName = "chat_config.txt"
- local config = {chatChannel = 7, userName = "", uiColors=uiColors}
- local computerid = os.getComputerID()
- -- Peripheral
- local monitor = peripheral.find("monitor")
- local modem = peripheral.find("modem")
- -- Buffer of conversation history
- local conversationBuffer = {}
- local scrollPosition = 1
- -- Track if we've reached max dimensions
- local reachedMaxDims = false
- -- Add a variable to track cursor position
- local cursorAtStartOfLine = true
- -- Update and return current time
- local function updateTime()
- local time = os.time()
- return textutils.formatTime(time, false)
- end
- -- Collect data for API
- local function collectData(msg)
- return {
- username = config.userName,
- msg = msg,
- gameday = os.day(),
- gametime = updateTime(),
- gameuptime = os.clock(),
- computerid = computerid or "Unknown"
- }
- end
- -- Validate configuration data
- local function validateConfig(configData)
- -- Check baseURL
- if type(configData.chatChannel) ~= "number" or configData.chatChannel < 0 then
- print("Invalid baseURL.")
- return false
- end
- -- Check userName
- if type(configData.userName) ~= "string" or configData.userName == "" then
- print("Invalid userName.")
- return false
- end
- return true
- end
- -- Save Config to file
- local function saveConfig(config)
- if validateConfig(config) then
- local configData = textutils.serializeJSON(config)
- local file = fs.open(configFileName, "w")
- file.write(configData)
- file.close()
- else
- print("Invalid configuration data.")
- end
- end
- -- Load Config from file
- local function loadConfig()
- if fs.exists(configFileName) then
- local file = fs.open(configFileName, "r")
- local configData = file.readAll()
- file.close()
- local loadedConfig = textutils.unserializeJSON(configData)
- if validateConfig(loadedConfig) then
- config = loadedConfig
- else
- print("Invalid configuration file.")
- end
- end
- end
- -- Print a character to the monitor and manage line wrapping and scrolling
- local function printCharToMonitor(char, x, y)
- if not monitor then
- return x, y
- end
- local width, height = monitor.getSize()
- if not width or not height then
- return x, y
- end
- if char == "\n" then
- if cursorAtStartOfLine then
- return x, y
- end
- cursorAtStartOfLine = true
- if y < height then
- return 1, y + 1
- else
- monitor.scroll(1)
- return 1, height
- end
- else
- cursorAtStartOfLine = false
- monitor.setCursorPos(x, y)
- monitor.write(char)
- x = x + 1
- if x > width then
- if y < height then
- x = 1
- y = y + 1
- else
- monitor.scroll(1)
- x = 1
- y = height
- end
- end
- return x, y
- end
- end
- -- Buffer of conversation history
- local conversationBuffer = {}
- local scrollPosition = 1
- -- Function to redraw the monitor with the conversation history
- local function redrawMonitor()
- if not monitor then
- return
- end
- monitor.clear()
- local x, y = 1, 1
- monitor.setCursorPos(x, y)
- local lineCount = 0
- for i = scrollPosition, #conversationBuffer do
- local line = conversationBuffer[i]
- for _, segment in ipairs(line) do
- monitor.setTextColor(segment.color)
- for j = 1, #segment.message do
- local char = segment.message:sub(j, j)
- x, y = printCharToMonitor(char, x, y)
- end
- end
- x, y = printCharToMonitor("\n", x, y)
- lineCount = lineCount + 1
- local _, height = monitor.getSize()
- if lineCount >= height then
- scrollPosition = scrollPosition + 1
- break
- end
- end
- end
- -- Initialize user entry to the bottom left
- local function initializeUserEntry()
- term.clearLine()
- local x, y = term.getCursorPos()
- term.setCursorPos(1, y - 1)
- term.setTextColor(colors.gray)
- term.write(config.userName .. ": ")
- end
- -- Print message to both terminal and monitor
- local function printToBoth(message, color, appendToLast)
- term.setTextColor(color)
- write(message)
- if appendToLast == nil then
- appendToLast = false
- end
- if appendToLast and #conversationBuffer > 0 then
- table.insert(conversationBuffer[#conversationBuffer], {message = message, color = color})
- else
- table.insert(conversationBuffer, {{message = message, color = color}})
- end
- redrawMonitor()
- printCharToMonitor("\n", x, y)
- end
- -- Print a message one character at a time
- local function printTyping(message, color)
- if message == nil then
- return
- end
- local isFirstChar = true
- for i = 1, #message do
- local char = message:sub(i, i)
- printToBoth(char, color, not isFirstChar)
- isFirstChar = false
- sleep(0.01)
- end
- printToBoth("\n", color)
- end
- -- Print the welcome message
- local function welcomeMessage()
- printToBoth(logoArt, logoColor)
- printToBoth("\nWelcome to " .. productName .. " by " .. authorName .. " \n(Version " .. productVersion .. ")\n", config.uiColors.systemColor)
- printToBoth("Type /settings to change settings\n", config.uiColors.systemColor)
- printToBoth("Type /help for a list of commands\n", config.uiColors.systemColor)
- printToBoth("Type /exit to exit the program\n\n", config.uiColors.systemColor)
- printToBoth("Conversation starts here:\n", config.uiColors.otherChatColor)
- end
- -- Print the help message
- local function printHelp()
- printToBoth("Config File:" .. configFileName .. "\n", config.uiColors.systemColor)
- printToBoth("Commands:\n", config.uiColors.systemColor)
- printToBoth("/welcome - Print the welcome message\n", config.uiColors.helpColor)
- printToBoth("/settings - Change settings\n", config.uiColors.helpColor)
- printToBoth("/clear - Clear the screen\n", config.uiColors.helpColor)
- printToBoth("/version - Print the version number\n", config.uiColors.helpColor)
- printToBoth("/help - Print this help message\n", config.uiColors.helpColor)
- printToBoth("/exit - Exit the program\n\n", config.uiColors.helpColor)
- end
- -- Read input with a msg
- local function readInput(msg)
- term.setTextColor(colors.gray)
- write(msg)
- local input = read()
- local x, y = term.getCursorPos()
- term.setCursorPos(1, y - 1)
- term.clearLine()
- print()
- return input
- end
- local colorOptions = {"userNameColor", "userChatColor", "otherNameColor", "otherChatColor", "commandColor", "errorColor", "systemColor", "helpColor", "logoColor"}
- -- Function to handle changing colors via a command tree
- local function handleColorChange()
- printToBoth("Color Settings Menu:\n", config.uiColors.systemColor)
- for i, option in ipairs(colorOptions) do
- printToBoth(i .. ". Change " .. option .. "\n", config.uiColors.systemColor)
- end
- printToBoth(#colorOptions + 1 .. ". Set Default Colors\n", config.uiColors.systemColor)
- printToBoth(#colorOptions + 2 .. ". Abort\n", config.uiColors.systemColor)
- local selectedIndex = tonumber(readInput("\nEnter the number of the color setting you'd like to change: "))
- if selectedIndex and selectedIndex >= 1 and selectedIndex <= #colorOptions then
- local selectedOption = colorOptions[selectedIndex]
- printToBoth("Available colors: white, orange, magenta, lightBlue, yellow, lime, pink, gray, lightGray, cyan, purple, blue, brown, green, red, black\n", config.uiColors.helpColor)
- local newColor = readInput("\nEnter the new color name: ")
- if colors[newColor] then
- config.uiColors[selectedOption] = colors[newColor]
- saveConfig(config)
- printToBoth("\nColor for " .. selectedOption .. " changed to " .. newColor, config.uiColors.systemColor)
- else
- printToBoth("\nInvalid color name.", config.uiColors.errorColor)
- end
- elseif selectedIndex == #colorOptions + 1 then
- config.uiColors = uiColors
- saveConfig(config)
- printToBoth("\nDefault colors set.", config.uiColors.systemColor)
- elseif selectedIndex == #colorOptions + 2 then
- printToBoth("\nColor change aborted.", config.uiColors.systemColor)
- else
- printToBoth("\nInvalid option.", config.uiColors.errorColor)
- end
- end
- -- Function to wipe configuration and restart
- local function wipeConfigAndRestart()
- if fs.exists(configFileName) then
- fs.delete(configFileName)
- end
- printToBoth("Configuration wiped. Rebooting now...", config.uiColors.systemColor)
- os.reboot()
- end
- -- Function to handle changing various settings via a command tree
- local function handleSettings()
- printToBoth("Settings Menu:\n", config.uiColors.systemColor)
- printToBoth("1. Change User Name\n", config.uiColors.systemColor)
- printToBoth("2. Change modem channel\n", config.uiColors.systemColor)
- printToBoth("3. Change UI Colors\n", config.uiColors.systemColor)
- printToBoth("4. Wipe Config and Restart\n", config.uiColors.systemColor)
- printToBoth("5. Abort\n", config.uiColors.systemColor)
- local selectedIndex = tonumber(readInput("\nEnter the number of the option you'd like to change: "))
- if selectedIndex == 1 then
- config.userName = readInput("Enter your new name: \n")
- saveConfig(config)
- elseif selectedIndex == 2 then
- config.chatChannel = readInput("Enter the new channel: \n")
- saveConfig(config)
- elseif selectedIndex == 3 then
- handleColorChange()
- elseif selectedIndex == 4 then
- wipeConfigAndRestart()
- elseif selectedIndex == 5 then
- printToBoth("\nSettings change aborted.", config.uiColors.systemColor)
- else
- printToBoth("\nInvalid option.", config.uiColors.errorColor)
- end
- end
- -- Handle command input
- local function handleCommand(msg)
- local changed = false
- if msg == "/welcome" then
- welcomeMessage()
- elseif msg == "/settings" then
- handleSettings()
- elseif msg == "/clear" then
- term.clear()
- welcomeMessage()
- elseif msg == "/version" then
- printTyping(productVersion .. "\n", config.uiColors.systemColor)
- elseif msg == "/help" then
- printHelp()
- elseif msg == "/exit" then
- printToBoth("Exiting...\n\n", config.uiColors.systemColor, true)
- return true
- else
- printToBoth("Invalid command.\n", config.uiColors.errorColor)
- end
- printToBoth("\n", colors.gray, true)
- if changed then
- if validateConfig(config) then
- saveConfig(config)
- else
- printToBoth("Configuration is invalid.\n", config.uiColors.errorColor)
- end
- end
- end
- -- handle incoming messages
- local function handleIncomingMessage(messageTable)
- if messageTable.sender ~= config.userName then -- Filter out own messages
- printToBoth("\n", colors.gray, true)
- printToBoth(messageTable.sender .. ": " .. "\n", config.uiColors.otherNameColor)
- printTyping(messageTable.message .. "\n", config.uiColors.otherChatColor)
- sleep(0.1)
- initializeUserEntry()
- end
- end
- -- Function to listen for incoming messages
- local function listen()
- modem.open(config.chatChannel)
- while true do
- local event, modemSide, senderChannel, replyChannel, messageTable, senderDistance = os.pullEvent("modem_message")
- if senderChannel == config.chatChannel then
- term.clearLine()
- handleIncomingMessage(messageTable)
- end
- end
- end
- -- Handle user input
- local function handleInput(msg)
- if msg:sub(1, 1) == "/" then
- return handleCommand(msg, config)
- else
- modem.transmit(config.chatChannel, config.chatChannel, {message = msg, sender = config.userName})
- printToBoth(config.userName .. ": " .. "\n", config.uiColors.userNameColor)
- printTyping(msg, config.uiColors.userChatColor)
- return false
- end
- end
- -- Main Loop
- local function mainLoop(config)
- parallel.waitForAny(
- function()
- while true do
- local msg = readInput(config.userName .. ": ")
- local shouldExit = handleInput(msg, config)
- if shouldExit then
- printToBoth("Goodbye! Thank you for using " .. productName .. " by " .. authorName, config.uiColors.systemColor)
- break
- end
- end
- end,
- listen
- )
- end
- -- Initialization
- local function initializeClient()
- loadConfig()
- if monitor then
- monitor.setTextScale(1)
- monitor.clear()
- else
- end
- if not config.userName or config.userName == "" then
- config.userName = readInput("Enter your name: ")
- end
- if not config.chatChannel or config.chatChannel == "" then
- config.chatChannel = tonumber(readInput("Enter the chat channel: "))
- end
- if not config.uiColors then
- config.uiColors = uiColors
- end
- saveConfig(config)
- welcomeMessage()
- mainLoop(config)
- end
- -- Entry Point
- initializeClient()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement