Help fixing my rainbow server message

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

Hey, I have code which makes a server message rainbow, but what it does now is: lag the game and make the chat bubble white, I need help optimising the code and making it so the chat bubble text doesn’t go white

local TextChatService = game:GetService("TextChatService")
local ChatWindowConfiguration = TextChatService.ChatWindowConfiguration
local hue = 0

TextChatService.OnIncomingMessage = function(textChatMessage)
	if textChatMessage.Metadata == "specialCard" then
		while task.wait(0.1) do
			hue += 0.01
			local color = Color3.fromHSV(hue, 1, 1)
			ChatWindowConfiguration.TextColor3 = color
			if hue >= 1 then
				hue = 0

			end
		end
	else
		local overrideProperties = Instance.new("TextChatMessageProperties")
		overrideProperties.Text = string.format("<font color='#FFFFFF'>%s</font>", textChatMessage.Text)
		return overrideProperties
	end
end
2 Likes

Can you show a video of what it looks like?

sure, also one thing to now is that the while loop is actually a :Heartbeat function

1 Like

Oh, hmm, idk what is it, but can you show the updated script, so i can take a better look of what changes you did, and stuff?

1 Like
local TextChatService = game:GetService("TextChatService")
local ChatWindowConfiguration = TextChatService.ChatWindowConfiguration
local hue = 0

TextChatService.OnIncomingMessage = function(textChatMessage)
	if textChatMessage.Metadata == "specialCard" then
		game["Run Service"].Heartbeat:Connect(function()
			hue += 0.01
			local color = Color3.fromHSV(hue, 1, 1)
			ChatWindowConfiguration.TextColor3 = color
			if hue >= 1 then
				hue = 0

			end
		end)
	else
		local overrideProperties = Instance.new("TextChatMessageProperties")
		overrideProperties.Text = string.format("<font color='#FFFFFF'>%s</font>", textChatMessage.Text)
		return overrideProperties
	end
end
1 Like

wow, you are not a basic scripter, i am, so… i think i can’t help with it :frowning:
sorry.

1 Like

it’s alright, i appreciate your help!

1 Like

@24redii Thanks, btw i need some help on my script that i’m having problem on. if you want to see it, go ahead, i need help with a powerbox door script, it’s not working correctly.

1 Like

Oh, no problem, sorry if i can’t help you too.

It’s executing the else statement, which means textChatMessage.Metadata is not specialCard. Comment out the else and the stuff in it, it looks like you’re turning all text chats that aren’t ‘specialCard’ into white.

1 Like

So you’re gonna have a new heartbeat connection running an infinite loop on the server for every ‘special’ chat that comes in?

IDK, but if so, that doesn’t seem like a good idea.

so I made two versions, both work.
they are both optimizations of your script, using only one while loop, and running it on a background thread.

or tweenservice, though sadly tweenservice doesn’t display all colors.

spawn version:

local TextChatService = game:GetService("TextChatService")
local ChatWindowConfiguration = TextChatService:WaitForChild("ChatWindowConfiguration")
local hue = 0


TextChatService.OnIncomingMessage = function(msg)
	if msg.Metadata ~= "Test123" then return end--replace with actual data
		
	local props = Instance.new("TextChatMessageProperties")
	props.Text = string.format("<font color='#0000FF'>%s</font>", msg.Text)--replace with your color
	return props
end

spawn(function() 
	while task.wait(0.1) do
		hue += 0.01

		local color = Color3.fromHSV(hue, 1, 1)
		ChatWindowConfiguration.TextColor3 = color

		if hue >= 1 then
			hue = 0
		end
	end
end)

ts version:

local TextChatService = game:GetService("TextChatService")
local ts = game:GetService("TweenService")

local ChatWindowConfiguration = TextChatService:WaitForChild("ChatWindowConfiguration")
local tsinf = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.In, -1, true, 0)

TextChatService.OnIncomingMessage = function(msg)
	if msg.Metadata ~= "Test123" then return end--replace with actual data
		
	local props = Instance.new("TextChatMessageProperties")
	props.Text = string.format("<font color='#0000FF'>%s</font>", msg.Text)--replace with your color
	return props
end

ChatWindowConfiguration.TextColor3 = Color3.fromRGB(255, 0, 0)
ts:Create(ChatWindowConfiguration, tsinf, {TextColor3 = Color3.fromRGB(67, 255, 233)}):Play()

the spawn version ensures that it is running in the background, with only one while loop per client.
The tweenservice is roblox api, so you can assume it is optimized, but it doesn’t cover all colors.
here is a quick showcase of spawn:

if this doesn’t work then idk

edit: forgot to say, the button uses this code to access the cool rainbow color:

--in a local script parented under the button
script.Parent.Activated:Connect(function()
 local chnl : TextChannel = game.TextChatService:FindFirstChild("TextChannels"):FindFirstChild("RBXGeneral")
chnl:DisplaySystemMessage("hello", "Test123") -- replace with your data
end)

edit: not to access the rainbow colors, but to override to make sure they are white or something.

edit: I just realized I scripted the opposite of what you want hahah,
no worries because I’m assuming you want the server to type in those rainbow fonts, but the players need white text right?

I modified the task . spawn script to only allow the server to type in that nice color:

local TextChatService = game:GetService("TextChatService")
local ChatWindowConfiguration = TextChatService:WaitForChild("ChatWindowConfiguration")

local General : TextChannel = TextChatService:WaitForChild("TextChannels"):WaitForChild("RBXGeneral")
local hue = 0

TextChatService.OnIncomingMessage = function(msg)
	
	if msg.Metadata ~= "Test123" then--check if it has the 123 metadata, if not check if it is a plr.
		if not msg.TextSource or not game.Players:GetPlayerByUserId(msg.TextSource.UserId) then 
			return 
		end
	end
--[[
so now all players will be white, but server messages will be rainbow, 
i made it so you can pass as metadata "test123" in server messages if you need server texts
 that aren't colored rainbow!
]]

	local props = Instance.new("TextChatMessageProperties")
	props.Text = string.format("<font color='#0000FF'>%s</font>", msg.Text)
    return props
end

spawn(function()
	while task.wait(0.1) do
		hue += 0.01

		local color = Color3.fromHSV(hue, 1, 1)
		ChatWindowConfiguration.TextColor3 = color

		if hue >= 1 then
			hue = 0
		end
	end
end)

Maybe I can help? What is it?
I consider myself decent at cframe calculations.

Thank you! It works, but the chat bubble has the same colour as the text. This is a problem as it appears as if the chat bubble is broken, do you have any ideas?

you can use bubblechatproperties of the textchatmessage to keep the text the same.

where would i put that? i have this right now but the colour is still white:

	TextChatService.OnBubbleAdded = function(bubble)
			local props = Instance.new("BubbleChatMessageProperties")
			props.TextColor3 =Color3.new(0.219608, 0.231373, 0.239216)
			print(props.TextColor3)
			return props
		end

right now i’m, putting it between the onincomingmessage and spawn function

1 Like

What about putting it on the server script service? (yeah i’m back)

oh dear, my bad.
I forgot text embed overrides any properties!

but I haven’t been sleeping or doing nothing about it!
as soon as i realized, i searched for a solution!
Roblox does not allow for modifying text of a bubble, so we can’t really remove the text embed.
So what is the solution?
Reroute all chat messages to our very own custom chat system!
for the past night I have been cooking up a new chat system,
very simple and easy to remake!

it requires one module script with a data structure we use for passing our data.
one localscript for client handling,
one server script for text filtering.

and then boom you get this:
(ill share my hierarchy, my scripts, and a video of how it looks)

scripts:
module:

local ChatMessage = {}
ChatMessage.__index = ChatMessage

function ChatMessage.new(msg : string, userId : number, font : Enum.Font, textColor : Color3, textSize : number, isWhisper : boolean, whisperId : number, bold : boolean, italic : boolean, israinbow : boolean)
	local newMsg = {}
	setmetatable(newMsg, ChatMessage)
	
	newMsg.Message = msg
	newMsg.Source = userId
	newMsg.Font = font
	newMsg.TextColor = textColor
	newMsg.TextSize = textSize
	newMsg.IsWhisper = isWhisper
	newMsg.Bold = bold
	newMsg.Italic = italic
	newMsg.WhisperId = whisperId
	newMsg.IsRainBow = israinbow
	
	return newMsg
end

function ChatMessage.default()
	local newMsg = {}
	setmetatable(newMsg, ChatMessage)
	
	newMsg.Message = ""
	newMsg.Source = -1
	newMsg.Font = Enum.Font.Gotham
	newMsg.TextColor = Color3.fromRGB(255, 255, 255)
	newMsg.TextSize = 14
	newMsg.IsWhisper = false
	newMsg.WhisperId = -1
	newMsg.Bold = false
	newMsg.Italic = false
	newMsg.IsRainBow = false
	
	return newMsg
end

function ChatMessage:With(property : string, value : any)
	local newCopy = self:Clone()
	
	newCopy[property] = value
	return newCopy
end

function ChatMessage:Clone()
	local newCopy = {}
	setmetatable(newCopy, ChatMessage)

	newCopy.Message = self.Message
	newCopy.Source = self.Source
	newCopy.Font = self.Font
	newCopy.TextColor = self.TextColor
	newCopy.TextSize = self.TextSize
	newCopy.IsWhisper = self.IsWhisper
	newCopy.WhisperId = self.WhisperId
	newCopy.Bold = self.Bold
	newCopy.Italic = self.Italic
	newCopy.IsRainBow = self.IsRainBow
	
	return newCopy
end

function ChatMessage.CopyFrom(arr) 
	local newCopy = {}
	local defaultArr = ChatMessage.default()
	setmetatable(newCopy, ChatMessage)
	
	newCopy.Message = arr["Message"] or defaultArr["Message"]
	newCopy.Source = arr["Source"] or defaultArr["Source"]
	newCopy.Font = arr["Font"] or defaultArr["Font"]
	newCopy.TextColor = arr["TextColor"] or defaultArr["TextColor"]
	newCopy.TextSize = arr["TextSize"] or defaultArr["TextSize"]
	newCopy.IsWhisper = arr["IsWhisper"] or defaultArr["IsWhisper"]
	newCopy.WhisperId = arr["WhisperId"] or defaultArr["WhisperId"]
	newCopy.Bold = arr["Bold"] or defaultArr["Bold"]
	newCopy.Italic = arr["Italic"] or defaultArr["Italic"]
	newCopy.IsRainBow = arr["IsRainBow"] or defaultArr["IsRainBow"]
	
	return newCopy
end

return ChatMessage

this defines a new class called ChatMessage! with some instance and some static methods.
With method- returns a new copy of the chatmessage but with the given property changed.
new- creates a new chatmessage with the given properties
default- creates a new chatmessage with default properties
clone- clones a chatmessage
copyfrom- clones a chatmessage from a given array, if values are nil, it puts in the default value!

localscript, handles rendering and sending to server, also decorating messages based on chatmessage settings:

local Rep = game.ReplicatedStorage
local core = game.StarterGui
local tweenss = game:GetService("TweenService")
local col = game:GetService("CollectionService")
local contextActions = game:GetService("ContextActionService")

local SendChat = Rep:WaitForChild("SendChat")
local ChatMessage = require(Rep:WaitForChild("ChatMessage"))

local ChatUI = script.Parent
local Input = ChatUI.InputFrame.input
local Output = ChatUI.Output

local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
local rainBows = {}
local hue = 0
local debounce = false

local function onSendRequest()
	if debounce then return end
	print("ran")
	debounce = true
	
	local msg = ChatMessage.default()
		:With("Message", Input.Text)
		:With("Source", game.Players.LocalPlayer.UserId)
	
	SendChat:FireServer(msg)
	Input.Text = ""

	task.wait(1)
	debounce = false
end

core:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false)
contextActions:BindAction("ChatSend", onSendRequest, false, Enum.KeyCode.Return)

SendChat.OnClientEvent:Connect(function(usermsg)
	local sender = "System"
	local posplr = game.Players:GetPlayerByUserId(usermsg["Source"])
	if posplr then sender = posplr.Name end
	
	local newDisplay = script.Message:Clone()
	newDisplay.Internal.Text = sender..":".." \n"..usermsg["Message"]
	newDisplay.Internal.Font = usermsg["Font"]
	newDisplay.Internal.TextSize = usermsg["TextSize"]
	newDisplay.Internal.TextColor3 = usermsg["TextColor"]
	
	if usermsg["Source"] == game.Players.LocalPlayer.UserId then newDisplay.BackgroundColor3 = Color3.fromRGB(0, 170, 255) end
	if usermsg["IsRainBow"] == true then newDisplay:AddTag("Rainbow") end
	
	newDisplay.Parent = Output
end)

spawn(function() 
	while task.wait(0.1) do
		hue += 0.01

		local color = Color3.fromHSV(hue, 1, 1)
		
		for i,v in pairs(col:GetTagged("Rainbow")) do--for every rainbow, set its color
			local int : TextLabel = v["Internal"]
			if not int then return end
			
			int.TextColor3 = color
		end
		
		if hue >= 1 then
			hue = 0
		end
	end
end)

and the server, which handles text filtering! because it is important to protect our users! the server also handles broadcasting the message to every player, or only the whispered player.

local SendChat = game.ReplicatedStorage.SendChat
local Chat = game:GetService("Chat")
local ChatMessage = require(game.ReplicatedStorage.ChatMessage)

SendChat.OnServerEvent:Connect(function(plr, umsg)
	print("ran")
	local succes, errorMsg = pcall(function()
		if umsg["Source"] == -1 then return umsg["Message"] end--message came from server
		return Chat:FilterStringForBroadcast(umsg["Message"], game.Players:GetPlayerByUserId(umsg["Source"]))
	end)
	
	if not succes then print(errorMsg) return end
	print("sending...")
	local new = ChatMessage.CopyFrom(umsg)
		:With("Message", errorMsg)
	
	for i,v in pairs(game.Players:GetPlayers()) do
		if new["IsWhisper"] then 
			if v.UserId ~= new["WhisperId"] and v.UserId ~= new["Source"] then continue end
		end
		
		SendChat:FireClient(v, new)
	end
end)

and then a local script for the button on screen, showing how to send a system message:

local chtmsg = require(game.ReplicatedStorage:WaitForChild("ChatMessage"))
local send = game.ReplicatedStorage:WaitForChild("SendChat")

script.Parent.Activated:Connect(function()
	local msg = chtmsg.default()
		:With("Message", "hello there!")
		:With("IsRainBow", true)
	
	send:FireServer(msg)
end)

now this is my hierarchy, useful information so you can see where every object resides:

alright and now here is a video:

it is a bit janky i know, it is because autosize on frames does not resize again when the children become smaller, only when they become bigger, but i’ll find a solution i swear!

what do you think?

i’ll extend it to include bubble chat soon, hold on a minute…
edit:

alright i have returned with bubble chat!
here is the modified client script, server script & the module stays the same.

local Rep = game.ReplicatedStorage
local core = game.StarterGui
local tweenss = game:GetService("TweenService")
local col = game:GetService("CollectionService")
local contextActions = game:GetService("ContextActionService")
local debris = game:GetService("Debris")

local SendChat = Rep:WaitForChild("SendChat")
local ChatMessage = require(Rep:WaitForChild("ChatMessage"))
local bubble = script:WaitForChild("ChatBubble")

local ChatUI = script.Parent
local Input = ChatUI.InputFrame.input
local Output = ChatUI.Output

local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
local rainBows = {}
local hue = 0
local debounce = false

local function onSendRequest()
	if debounce then return end
	print("ran")
	debounce = true
	
	local msg = ChatMessage.default()
		:With("Message", Input.Text)
		:With("Source", game.Players.LocalPlayer.UserId)
	
	SendChat:FireServer(msg)
	Input.Text = ""

	task.wait(1)
	debounce = false
end

core:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false)
contextActions:BindAction("ChatSend", onSendRequest, false, Enum.KeyCode.Return)

SendChat.OnClientEvent:Connect(function(usermsg)
	local sender = "System"
	local posplr = game.Players:GetPlayerByUserId(usermsg["Source"])
	if posplr then sender = posplr.Name end
	
	local newDisplay = script.Message:Clone()
	newDisplay.Internal.Text = sender..":".." \n"..usermsg["Message"]
	newDisplay.Internal.Font = usermsg["Font"]
	newDisplay.Internal.TextSize = usermsg["TextSize"]
	newDisplay.Internal.TextColor3 = usermsg["TextColor"]
	
	if usermsg["Source"] == game.Players.LocalPlayer.UserId then newDisplay.BackgroundColor3 = Color3.fromRGB(0, 170, 255) end
	if usermsg["IsRainBow"] == true then newDisplay:AddTag("Rainbow") end
	
	newDisplay.Parent = Output
	
	if sender == "System" then return end
	local newBubble = bubble:Clone()
	debris:AddItem(newBubble, 20)--change lifetime of bubble here...
	newBubble.MyFrame.Text.Text = usermsg["Message"]
	
	newBubble.Parent = posplr.Character.Head
	newBubble.Adornee = posplr.Character.Head
	newBubble.MyFrame.Visible = true--show bubble
end)

spawn(function() 
	while task.wait(0.1) do
		hue += 0.01

		local color = Color3.fromHSV(hue, 1, 1)
		
		for i,v in pairs(col:GetTagged("Rainbow")) do--for every rainbow, set its color
			local int : TextLabel = v["Internal"]
			if not int then return end
			
			int.TextColor3 = color
		end
		
		if hue >= 1 then
			hue = 0
		end
	end
end)

here is my new hierarchy:


sorry for my horrible ui design choices, but the scripting matters.
you can style the window however you like,
i’ll report back once i’ve finished fixing the ui auto size bug.

edit: my brother said: "blud made an entire new chat system just to color text rainbow :skull: " :frowning:

2 Likes

textchatservice handling needs to be on the client, that’s where the chatwindow resides and where the chat ui is drawn.
the server just saves it in a chat history and filters it, then sends it back to the client for rendering.

1 Like

oh, that’s explains it. thanks for answering me

1 Like