LegacyChat ported to TextChatService

I’ve tested it to give a proper answer and it does work with some huge caveats.

To get it to work is to set the Chat ScreenGui Enable property (from the lua chat system) to false, and you need to enable ChatWindowConfiguration, ChatInputBarConfiguration, and ChannelsTabConfiguration (which are objects inside of TextChatService)

However, this has the major caveat of completely bypassing the server side processing of messages, as the default ui calls :SendAsync() directly, rather than the remote event from the Lua Chat System. The client side processing is also rendered useless, as it can no longer detect when messages are initially sent, and only detects the reception of the filtered message (which it then promptly ignores, as the message is lacking the ID necessary to associated the filtered message to the original message that went through the lua chat system)

So TL;DR, it doesn’t work. Any other chat system that provides features on top of the TextChatService api also wont work with the default UI, as these features are built on top of the TextChatService api, requiring a custom message sending process
The TextChatService api provides basically no customization or processing capability on the server, which is very annoying

image
Pretty much anything is possible with the lua chat system, some things are just much harder to achieve, or at least require good knowledge of how the lua chat system is structured

What I’ve done, is, in this module
image

I’ve modified the :AddNameButtonToBaseMessage() function to add a gradient to the player’s name

function methods:AddNameButtonToBaseMessage(BaseMessage, nameColor, formatName, playerName)
	local speakerNameSize = self:GetStringTextBounds(formatName, BaseMessage.FontFace, BaseMessage.TextSize)
	local NameButton = self:GetFromObjectPool("TextButton")
	NameButton.Selectable = false
	NameButton.Size = UDim2.new(0, speakerNameSize.X, 0, speakerNameSize.Y)
	NameButton.Position = UDim2.new(0, 0, 0, 0)
	NameButton.BackgroundTransparency = 1
	NameButton.FontFace = BaseMessage.FontFace
	NameButton.TextSize = BaseMessage.TextSize
	NameButton.TextXAlignment = BaseMessage.TextXAlignment
	NameButton.TextYAlignment = BaseMessage.TextYAlignment
	NameButton.TextTransparency = BaseMessage.TextTransparency
	NameButton.TextStrokeTransparency = BaseMessage.TextStrokeTransparency
	NameButton.TextColor3 = nameColor
	NameButton.Text = formatName
	NameButton.Visible = true
	
	local IsActive = true -- Variable I added to handle when the Text is deleted
	
	do -- Player gradient
		
		-- Function that returns a triangle waveform from a time t
		-- There are 1 triangle per second, with slopes 2 and -2
		-- If you have a cyclic color sequence, you might not need a triangle waveform, but rather just a floored (x % 1) function
		local function TriangleFunction(t)
			return t % 1 < 1/2 and (t % (1/2))*2 or 1 - (t % (1/2))*2
		end
		
		local UIGradient = Instance.new("UIGradient")
		UIGradient.Color = ColorSequence.new({
			ColorSequenceKeypoint.new(0, Color3.fromRGB(183, 1, 255)),
			ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 11, 117))
		})
		UIGradient.Parent = NameButton
		NameButton.TextColor3 = Color3.new(1,1,1) -- Set the player's color to white so the gradient isn't affected by it

		task.defer(function() 
			while IsActive do 
				UIGradient.Offset = Vector2.one*(TriangleFunction(os.clock()/3)*2 - 1) -- Oscillates between -1 and 1
				task.wait()
			end
		end)
	end
	NameButton.Parent = BaseMessage

	local clickedConn = NameButton.MouseButton1Click:connect(function()
		self:NameButtonClicked(NameButton, playerName)
	end)

	local changedConn = nil
	changedConn = NameButton.Changed:connect(function(prop)
		if prop == "Parent" then
			IsActive = false
			clickedConn:Disconnect()
			changedConn:Disconnect()
		end
	end)

	return NameButton
end

I also made the gradient move over time, for a cool effect


Something that would be useful would be to have the messageData.ExtraData available to those functions (something I might add to this port), as that would allow for much more in depth customizability that can be specified when creating/sending the messages (messageData.ExtraData can be accessed by callback functions when a message is sent, making it ideal for adding tags or changing various things about a message)

This is something I really like with the lua chat system, everything is possible if you’re able to make it. The way it was built allowed for these features without forking the whole thing (which is good and bad, as the roblox team were limited in the changes they could do). From the customization system alone the lua chat system is very feature rich, but if you allow yourself to fork it, then the possibilities are endless
Of course, the downside is that these aren’t accessible to less advanced scripters, without a youtube tutorial or something, unlike TextChatService’s default ui which is more limited but much more beginner friendly

1 Like

Something I wanted to ask: are all the settings currently present in the “ChatSettings” Module compliant with Roblox’s restrictions, as I seem to recall in an area(s) of the module when I last checked, a bit of an unsurety when it came to some of the settings being compliant with Roblox’s ToS. I might be making this up, I’m not sure, however I just want to be safe with what I’m planning for implementing this system.

There were a few things I was planning to do with the system, such as handling RichText support, which would involve me having to develop a TextMarkdown module for handling the display of things such as bolding text via surrounding a selection with two asterisks, for example, and for managing other things such as a typing indicator.

I’m probably overthinking things as I usually do, but I just want to be on the safe side.

1 Like

Could you pin point which settings you are unsure about. None of them are of concern to me
For legal reasons, I am not a lawyer and am not responsible if your game is moderated because of my port of the chat. I should probably add a MIT licence to my port

The only setting that you might be concerned about is this one

-- Shows _ before the message gets filtered. The placeholder message is displayed before it is sent to TextChatService
-- Set to false if using TextChatService's api (ie TextChatCommands, ShouldDeliverCallback, OnIncomingMessage, ...)
module.ShowUnfilteredMessagePlaceholder = true

But this one all it does is either make the message look like “_____” or if set to false, it just wont be shown until the filtered version is received

The only one I know wont be allowed is this one, from the FFlag module

-- /!\ Don't think this is allowed past april 30th (as it is probably considered a "chat"). It uses the usual filtering function, 
-- and not TextChannels, as TextChannels (or TextChatService in general) doesn't have anything for storing previously sent messages and displaying them to new users
FFlags.HistoryLogEnabled = false

The module does have access to the unfiltered version of messages from other players on the client (passed to the custom Players.Chatted), but I think that’s fine

Hey, great resource!!

Just a minor issue though - characters like < and > display like this (html entity issue I assume)

External Media
1 Like

This is an issue with TextChatService, those characters are replaced to prevent users from using rich text, however, this behaviour cannot be disabled for custom chats

I could create a substitution system to fix this, I could… I don’t like it

1 Like

hi! would this work with let’s say a script that changes the speaker’s name? great resource btw :slight_smile: i think textchatservice screwed us all over, haha

1 Like

Honestly, yeah.

It really has. It’s an unfinished buggy mess on the client-side with missing features, notorious issues and overall an awful UI/UX experience.

I still want to like it, and I hope it gets good enough to the point community replacements aren’t necessary. Though I feel like the engineers aren’t given enough time to work on it, and that’s the result we got.

I don’t dislike the engineers for trying, I just feel like they were rushed to get it out before they were happy with it.

3 Likes

It is possible, but not by chaning the speaker’s name

The Lua Chat System relies a lot of the name of the speaker, channel, or whatever, to get said speaker or channel, so changing the name of the speaker would break that, unless the name of the speaker is changed as it is created

How to achieve it, you’d have to use :RegisterFilterMessageFunction() on either ChatService or ChatChannel, and modify the SpeakerDisplayName of the MessageObj:

local Chat = require(game.ReplicatedStorage.Chat)

local ChatService = Chat:GetChatService()
ChatService:RegisterFilterMessageFunction("SpeakerDisplayNameOverwrite", function(speakerName: string, messageObj: Chat.MessageObj, channel: string)  
	messageObj.SpeakerDisplayName = "CustomName"
end)



Alternatively, it would be possible to add a DisplayName field to the speaker, and make the message creator use that for the messageObj.SpeakerDisplayName. I might do that in a future release

Client side, it is also possible to mess with the message creator modules. I also would like to make the ExtraData table or more, accessible within the utils module, for more customization

This is the function responsible for creating the label with the player’s name, inside of utils

image

Currently, the SpeakerName (formatName in the util function) is being set in the DefaultChatMessage and WhisperMessage message creator modules (ideally I would like this to be inside of utils)

So you could play with this

1 Like

Update:
image
The LegacyChat actually already escapes those characters, when the FFlag something something (for right to left support I think) is enabled (which it is by default). I also noticed that, those escaped sequences actually display correctly with rich text enabled (which it is if the FFlag is set to true)

image

So why does it not work?

<font dir="ltr">                                                         </font>&amp;gt;

The & is getting substituted twice, once by the Lua Chat System, and then by TextChatService, so &gt; ends up being &amp;gt;

When creating chat channels, you may have a problem that the normal TextChatService channel tabs overlap the chat port, in this case just disable TextChatService.ChannelTabsConfiguration.Enabled and the problem should disappear, it worked for me

P.S. i think author just forgot to mention this step in the installation section but it’s alright
image

Is there any way to make non-player speakers? i think i’m doing all right, but the message is just don’t showing, like i receive a notification about it (1 symbol near the channel tab)
image
image

but when i go to this channel there’s nothing new, i tried both on client and server

-- server script in serverscriptservice
local Chat = require(game.ReplicatedStorage.Chat)
local ChatService = Chat:GetChatService()
local ShowBroadcastMsgEvent = game.ReplicatedStorage.Events:WaitForChild("ShowBroadcastMsg")
local BroadcastChannel = ChatService:AddChannel("Broadcast", true)
BroadcastChannel.Leavable = false
BroadcastChannel.WelcomeMessage = "Welcome to Broadcast tune!"
BroadcastChannel.AutoJoin = true

BroadcastChannel.SpeakerJoined:Connect(function(speaker, ...: any) 
	print("speaker join to broadcast: "..speaker)
end)


local MeteorologicalCenterSpeaker = ChatService:AddSpeaker("Meteorological Center")
MeteorologicalCenterSpeaker:JoinChannel("Broadcast")
MeteorologicalCenterSpeaker:SetMainChannel("Broadcast")


game.Players.PlayerAdded:Connect(function(player: Player) 
	task.wait(5)
	MeteorologicalCenterSpeaker:SayMessage("Storm", BroadcastChannel.Name)	
	ShowBroadcastMsgEvent:FireAllClients(MeteorologicalCenterSpeaker.Name)
	print("message sent")
end)
--local script in starterplayerscripts
local Chat = require(game.ReplicatedStorage.Chat)
local ChatService = Chat:GetChatService()
local ShowBroadcastMsgEvent = game.ReplicatedStorage.Events:WaitForChild("ShowBroadcastMsg")

ShowBroadcastMsgEvent.OnClientEvent:Connect(function(speakername, ...: any) 
	local speaker = ChatService:GetSpeaker(speakername)
	speaker:SayMessage("Storm", "Broadcast")
	speaker:SendSystemMessage("test", "Broadcast")
end)

That is odd, when I tested it, I received the message, but ran into another issue, that is, the message was waiting to be filtered, which never happened since it isn’t a player… So the message was displaying as “____”

I would suggest looking for errors, but other than that I really have no idea as I cannot replicate your specific issue

About the other issue of the message being “____”, I will look into it this weekend. I’m pretty sure this is an issue with how I remade the filtering system, I did not consider chat bots, and I don’t actually know how they are handled by the LegacyChat

In the mean time, you can use this. The name of the ChatBot doesn’t appear, as it is, well, not being used, but it’s something…

game.Players.PlayerAdded:Connect(function(player: Player) 
	task.wait(5)
	
	local speaker = ChatService:GetSpeaker(player.Name)
	speaker:SendSystemMessage("Storm", BroadcastChannel.Name)
	
	print("message sent")
end)

Also, sending the message to the client is not needed (or shouldn’t be), I assume you added that as you were trying everything to get it working…

1 Like

Оh! I noticed that the message is now being sent successfully, it looks like it was some one-time roblox bug, but the filtering issue is still relevant
image

1 Like

thankies for the help!! would u mind helping me and someone else through this process? it would be greatly appreciated :smiley: if ur interested in payment for it too we can work that out

Did you try :RegisterFilterMessageFunction() and the code snippet I sent? Send me a dm and I can help you further. Also don’t worry about a payement, but I might take some time for lengthy answers as summer break isn’t quite there yet

there was an attempt to get it done, LOL. where do you want me to shoot you a dm?

On the forum, you can click on my profile and there is a “Message” button

– UPDATE –

The initial file for this version had a bug,

– Fixed the system attempting to remove the speaker twice when leaving a channel
– Fixed some types having not being quite right

– Added a check to throw an error if using Chat:GetChatService() from the client
– Added a check for received messages that lack metadata (likely not sent through the lua chat system)
– Added checks for non-disabled parts of TextChatService that should be disabled (ie the chat window, default channels, etc)

– Added support for WinryVirtualKeyboard & Gamepad support
(This includes a modification to the ChatLocalization table, to make the base Textbox message show the proper keybind. Don’t reuse the old localization table
– Added ChatSettings.ChatHotKeyKeyboard & ChatSettings.ChatHotKeyGamepad, to customize the keybinds.
These can be changed at runtime, for example, to let players chose their prefered keybind. (Previous ChatSettings modules without those field still work)

– Added the FixDoubleRichTextSanitization FFlag, in the FFlags module, which fixes <, > and & appearing as > or whatever
– Fixed an oversight in the new filtering system leading to messages from bot speakers always displaying as “______”


@Shake_Official, you might like this one

2 Likes

Instantly put it into a place to try and yep, it works!

It’s nice to see another integration of the keyboard with an alternative Luau-exclusive API. I’ll look at including a proper WVK Luau API in the next release (One that, of course, takes into account the intricacies you’ve done to make your wrapper work).

2 Likes