This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
MysticT's profile picture

GChat - chat with all your friends (in-game)

Started by MysticT, 04 April 2012 - 09:09 PM
MysticT #1
Posted 04 April 2012 - 11:09 PM
Hello everyone!
This is a little program I made when I decided to take a little break from working on my OS (wich will be updated soon). It's a chat program that let's you chat (obviously) with everyone who are connected. It doesn't require a server, it connects to everyone in range.

Features:
* Easy to use and configure.
* Easy to add functionality.
* Works with modems and bundled cable (although not recomended).
* Opens connection on every side so you don't have to choose wich one to use.
* Chat history (with configurable maximum size).

How to use:
Just install the program and run it. It will ask your name, and when you enter a valid name it connects to let you chat. Just type any message and press enter to send it. You can go through the chat history with the up/down arrow keys to see messages out of the screen. When you want to exit, just press Ctrl to open the menu and press enter (Exit is the only menu option).

How to Install:
- Get the code at the end of the post or from pastebin (you can use the pastebin program, code: q13Pv8JD)
- Save it to a file on the computer.
- Change any configuration options you want (at the start of the file)
- That's it, enjoy :D/>/>

Feel free to modify it in any way, just don't forget to give credit :)/>/>
It's very easy to add menu functions, the code has comments to help you know where to add the code.
If you make some modification you can post it here if you want.

Any feedback and suggestions are welcome.

Spoiler

-- GChat - chat program
-- by MysticT

-- Config
local nMinNameLen = 3 -- minimum user name lenght
local nMaxNameLen = 8 -- maximum user name lenght
local nMaxHistory = 50 -- maximum chat history size, set to nil to disable

-- System vars
local nScreenW, nScreenH = term.getSize()
local tUsers = {}
-- User message vars
local sUsrName = ""
local sUsrMsg = ""
local nPos = 0
-- Received messages vars
local tMessages = {}
local nMsg = 1
-- Menu vars
local bMenu = false
local nSelected = 1
local tMenuFunctions = {}
local tMenuOptions = {}
-- Menu functions vars
-- Add any variable you need here
local bExit = false

local function Clear()
	term.clear()
	term.setCursorPos(1, 1)
end

local function OpenAll()
	for _,side in ipairs(rs.getSides()) do
		rednet.open(side)
	end
end

local function AddMessage(sMsg, sName)
	if #sMsg > 0 then
		local msg
		if sName then
			msg = sName..": "..sMsg
		else
			msg = "<"..sMsg..">"
		end
		table.insert(tMessages, msg)
		if #tMessages - nMsg >= nScreenH - 1 then
			nMsg = nMsg + 1
		end
		if nMaxHistory ~= nil and #tMessages > nMaxHistory then
			table.remove(tMessages, 1)
			if nMsg > 1 then
				nMsg = nMsg - 1
			end
		end
	end
end

local function AddUser(nID, sName)
	tUsers[nID] = sName
	AddMessage("User "..sName.." connected from "..tostring(nID))
end

local function RemoveUser(nID)
	AddMessage("User "..tUsers[nID].." disconnected")
	tUsers[nID] = nil
end

local function WriteMsg(sText)
	local x, y = term.getCursorPos()
	local function newLine()
		x = 1
		y = y + 1
		term.setCursorPos(x, y)
		if y < nScreenH - 2 then
			return true
		end
		return false
	end
	while #sText > 0 do
		local whitespace = string.match(sText, "^[ t]+")
		if whitespace then
			term.write(whitespace)
			x, y = term.getCursorPos()
			sText = string.sub(sText, #whitespace + 1)
		end
		local newline = string.match(sText, "^n")
		if newline then
			if not newLine() then
				return true
			end
			sText = string.sub(sText, 2)
		end
		local text = string.match(sText, "^[^ tn]+")
		if text then
			sText = string.sub(sText, #text + 1)
			if #text > nScreenW then
				while #text > 0 do
					if x > nScreenW then
						if not newLine() then
							return true
						end
					end
					term.write(text)
					text = string.sub(text, (nScreenW - x) + 2)
					x, y = term.getCursorPos()
				end
			else
				if x + #text > nScreenW then
					if not newLine() then
						return true
					end
				end
				term.write(text)
				x, y = term.getCursorPos()
			end
		end
	end
	return false
end

local function WriteMessages()
	local i = 0
	while nMsg + i <= #tMessages and i < nScreenH - 1 do
		if WriteMsg(tMessages[nMsg + i]) then
			break
		end
		local x, y = term.getCursorPos()
		term.setCursorPos(1, y + 1)
		i = i + 1
	end
end

local function RedrawUserMsg()
	local nScroll = 0
	if nPos + 3 >= nScreenW then
		nScroll = nPos + 3 - nScreenW
	end
	term.setCursorPos(1, nScreenH)
	write("> ")
	write(string.sub(sUsrMsg, nScroll + 1))
	term.setCursorPos(nPos + 3 - nScroll, nScreenH)
end

local function RedrawMenu()
	term.setCursorPos(1, nScreenH)
	for i, s in ipairs(tMenuOptions) do
		if i == nSelected then
			term.write("["..s.."]")
		else
			term.write(s)
		end
		term.write(" ")
	end
end

local function Redraw()
	Clear()
	WriteMessages()
	if bMenu then
		RedrawMenu()
	else
		RedrawUserMsg()
	end
end

local function ParseMsg(nID, sMsg)
	local sAction, sArgs = string.match(sMsg, "(%a+): (.+)")
	if sAction == "MSG" then
		AddMessage(sArgs, tUsers[nID])
	elseif sAction == "PONG" then
		AddUser(nID, sArgs)
	elseif sAction == "PING" then
		AddUser(nID, sArgs)
		rednet.send(nID, "PONG: "..sUsrName)
	elseif sAction == "QUIT" then
		RemoveUser(nID)
	end
end

local function Ping()
	rednet.broadcast("PING: "..sUsrName)
end

local function Disconnect()
	for id,_ in pairs(tUsers) do
		rednet.send(id, "QUIT: "..sUsrName)
	end
end

local function SendMsg()
	AddMessage(sUsrMsg, sUsrName)
	for id,_ in pairs(tUsers) do
		rednet.send(id, "MSG: "..sUsrMsg)
	end
	sUsrMsg = ""
	nPos = 0
end

local function DoMenuItem()
	tMenuFunctions[nSelected]()
	nSelected = 1
end

function KeyPress(key)
	if key == 28 then -- Enter
		if bMenu then
			DoMenuItem()
		else
			SendMsg()
		end
	elseif key == 203 then -- Left
		if bMenu then
			if nSelected > 1 then
				nSelected = nSelected - 1
			end
		else
			if nPos > 0 then
				nPos = nPos - 1
			end
		end
	elseif key == 205 then -- Right
		if bMenu then
			if nSelected < #tMenuOptions then
				nSelected = nSelected + 1
			end
		else
			if nPos < #sUsrMsg then
				nPos = nPos + 1
			end
		end
	elseif key == 14 then -- Backspace
		if not bMenu then
			if nPos > 0 then
				sUsrMsg = string.sub(sUsrMsg, 1, nPos - 1)..string.sub(sUsrMsg, nPos + 1)
				nPos = nPos - 1
			end
		end
	elseif key == 211 then -- Delete
		if not bMenu then
			sUsrMsg = string.sub(sUsrMsg, 1, nPos)..string.sub(sUsrMsg, nPos + 2)
		end
	elseif key == 199 then -- Start
		if bMenu then
			nSelected = 1
		else
			nPos = 0
		end
	elseif key == 207 then -- End
		if bMenu then
			nSelected = #tMenuOptions
		else
			nPos = #sUsrMsg
		end
	elseif key == 200 then -- Up
		if nMsg > 1 then
			nMsg = nMsg - 1
		end
	elseif key == 208 then -- Down
		if nMsg < #tMessages then
			nMsg = nMsg + 1
		end
	elseif key == 29 then -- Ctrl
		bMenu = not bMenu
		term.setCursorBlink(not bMenu)
	end
end

local function AddChar(sChar)
	sUsrMsg = string.sub(sUsrMsg, 1, nPos)..sChar..string.sub(sUsrMsg, nPos + 1)
	nPos = nPos + 1
end

local function CheckUserName()
	if #sUsrName < nMinNameLen then
		return false, "Name too short."
	elseif #sUsrName > nMaxNameLen then
		return false, "Name too long."
	end
	return true
end

-- Menu

-- Add Menu functions here --
--[[
tMenuOptions[n] = "your option name"
tMenuFunctions[n] = function()
	-- Your code here
end
--]]

table.insert(tMenuOptions, "Exit")
table.insert(tMenuFunctions, function()
	bExit = true
end )

-- Main loop

repeat
	Clear()
	print("- Welcome to GChat -")
	write("Enter your name: ")
	sUsrName = read()
	local bValid, err = CheckUserName()
	if not bValid then
		print(err)
		sleep(2)
	end
until bValid
OpenAll()
Ping()
term.setCursorBlink(true)

while not bExit do
	Redraw()
	local evt, arg1, arg2 = os.pullEvent()
	if evt == "key" then
		KeyPress(arg1)
	elseif evt == "char" then
		AddChar(arg1)
	elseif evt == "rednet_message" then
		ParseMsg(arg1, arg2)
	end
end
Disconnect()
Clear()

Edit: just fixed a little error (calling Ping before connecting)
Edited on 05 April 2012 - 12:29 AM
MysticT #2
Posted 09 April 2012 - 01:24 AM
I know it's not a big project (took less than 3 hours to make), but some feedback would be nice, even if you don't like it, you can say why.
I won't update this unless someone asks for some feature or there's a bug.
tazyload #3
Posted 13 April 2012 - 12:27 AM
Great work, I'm putting it on a server to see what people think and have added your name to the welcome screen. If we come up with any ideas for features we will be sure to let you know.
EmTeaKay #4
Posted 13 April 2012 - 01:27 AM
This is good for CC/RP/BC/IC2 servers as this will let factory managers talk to their workers with out clogging up the chat. How would I get this on my server without having to type 100+ lines of code?
MysticT #5
Posted 13 April 2012 - 01:37 AM
Great work, I'm putting it on a server to see what people think and have added your name to the welcome screen. If we come up with any ideas for features we will be sure to let you know.
Thanks, i'll try to add any idea posted here.
This is good for CC/RP/BC/IC2 servers as this will let factory managers talk to their workers with out clogging up the chat. How would I get this on my server without having to type 100+ lines of code?
You can use the pastebin program if the http api is enabled, otherwise you'll have to ask someone with access to the server to copy the file.
mister_s #6
Posted 11 July 2012 - 11:17 PM
It's good, but couldn't you just press T in a server to chat?
I don't quite understand the difference…nice work though! :)/>/>
MysticT #7
Posted 11 July 2012 - 11:33 PM
It's good, but couldn't you just press T in a server to chat?
I don't quite understand the difference…nice work though! B)/>/>
lol, yes, but now you can do it on your CC computer :)/>/>
mister_s #8
Posted 11 July 2012 - 11:47 PM
lol, yes, but now you can do it on your CC computer :)/>/>
True, and it could make it more private! I downloaded it, (or pasted it, whatever.) works well!
ParanoidPlayer1 #9
Posted 15 July 2012 - 06:34 AM
Next step: encryption? or somehow make it private :P/>/>
AKman1984 #10
Posted 15 July 2012 - 05:46 PM
Hello MysticT awesome code I have an idea for you. Have the chat be displayed on to a monitor so that others can see. I wanted to ask you if I could feature your program on my youtube channel. I would obviously give you all the credit and tell people about your work. Anyways let me know.
MysticT #11
Posted 15 July 2012 - 08:28 PM
Hello MysticT awesome code I have an idea for you. Have the chat be displayed on to a monitor so that others can see.
Well, you could use the monitor program to run it on the monitor, but it would be hard to write. If I make a version for my os, this could be really easy, since it has synchronized output.

I wanted to ask you if I could feature your program on my youtube channel. I would obviously give you all the credit and tell people about your work. Anyways let me know.
Sure, no problem. Some publicity is always good :P/>/>
AKman1984 #12
Posted 17 July 2012 - 04:31 AM
Here you go hop you like it


https://www.youtube.com/watch?v=nWfPDQgctc0&amp;feature=plcp
UrASmurf #13
Posted 18 July 2012 - 04:26 AM
I can see a lot of forever alone moments arising from this.

Self: Hey
Selfonothercomputer: Hey man, hows it going.
Self: You are my best friend.
koslas #14
Posted 21 July 2012 - 01:19 AM
so we could just put this on a disk, and copy it onto the computer?
came from AKman1982's Video, May I ask how he installed it, onto a server?
Edit: Don't worry, figured it out
ExtraRandom #15
Posted 02 September 2012 - 07:06 PM
Hi there, awesome program, i was wondering can you have one which acts like a monitor but doesn't chat so its like a overview one and doubles up as a log for admins or something
RockLegend2 #16
Posted 22 September 2012 - 10:18 PM
Hey, MysticT.
Like a bunch of other requests on here, I was wondering if this could be made private. I am currently creating a world with a gigantic tower right in the center of the map. It utilizes GChat now, thanks to you, but I want it set up somehow so the GChat in that building is separate from any other buildings using GChat across the world. I thought about using bundled cables, since cables don't transmit outside of the building's walls, though modems will. And if I was to put another GChat-using building next to it, it'd be strange to have both on the same signal. Anyway, if there is any way to make it more private, or if bundled cables are the obvious answer, and I'm just rambling, either way, I would love to know.
Thanks!
MysticT #17
Posted 22 September 2012 - 10:22 PM
Hey, MysticT.
Like a bunch of other requests on here, I was wondering if this could be made private. I am currently creating a world with a gigantic tower right in the center of the map. It utilizes GChat now, thanks to you, but I want it set up somehow so the GChat in that building is separate from any other buildings using GChat across the world. I thought about using bundled cables, since cables don't transmit outside of the building's walls, though modems will. And if I was to put another GChat-using building next to it, it'd be strange to have both on the same signal. Anyway, if there is any way to make it more private, or if bundled cables are the obvious answer, and I'm just rambling, either way, I would love to know.
Thanks!
I was thinking about making a new version of this, but with a server, that should make it more private. I'll update when it's done.
RockLegend2 #18
Posted 22 September 2012 - 10:34 PM
I was thinking about making a new version of this, but with a server, that should make it more private. I'll update when it's done.

Awesome! Thank you!
musicgack #19
Posted 25 September 2012 - 09:48 PM
Can I Put This In A Simple Operating System? I Will Put Your Name With The Program… I'm Making…. A Operating System With Apps!
MysticT #20
Posted 25 September 2012 - 10:40 PM
Can I Put This In A Simple Operating System? I Will Put Your Name With The Program… I'm Making…. A Operating System With Apps!
Sure, no problem.
I'm almost done with the new version, it now uses a server and has some features like ban, whitelist, ops and more. I can't work on it now, so I think it will be ready for the next week.
RockLegend2 #21
Posted 27 September 2012 - 02:34 PM
Sure, no problem.
I'm almost done with the new version, it now uses a server and has some features like ban, whitelist, ops and more. I can't work on it now, so I think it will be ready for the next week.

There's no like button here besides the "vote up" button, so I have to comment and say that I can't wait.
MysticT #22
Posted 27 September 2012 - 05:45 PM
Sure, no problem.
I'm almost done with the new version, it now uses a server and has some features like ban, whitelist, ops and more. I can't work on it now, so I think it will be ready for the next week.

There's no like button here besides the "vote up" button, so I have to comment and say that I can't wait.
Well, I'm in the middle of my exams, so it will have to wait at least a week. But don't worry, I will finish it.
koslas #23
Posted 08 December 2012 - 10:06 AM
I am making a program in Computercraft, I was wondering if I could add this program as a selection that you could use?
rick3333 #24
Posted 22 December 2012 - 07:51 PM
can you please add a computer user system so you can have a computer with a single user on it for private computers?
atomhell #25
Posted 02 January 2013 - 03:50 PM
Hi,

Using the 4-April 2012 version, I have found that the letter "n" is causing errors with text. Instead of appearing on the screen, a newline is printed with each instance of n.


User atomhell co

ected ...

Perhaps this is due to the newer computercraft (v1.48)? Previous posts seem to indicate that it was working for them at the time.

Anyways, the rest of it works great!

-atomhell