LegacyChat ported to TextChatService

Header

This is a full port of LegacyChat, and not a recreation of LegacyChat

Current version: 1.1
Unstableish: use at your own risk, but core features seem stable. I’ll be testing it on my own, and I’ll be listening to bugs reported on this thread

Here is a list of changes done to the default LegacyChat


Pre 1.0

See previous module

Replaced the deprecated draggable property that was used with a custom drag function
New features (Font objects, Chat Translation & more!) and bug fixes
Implemented :CanUserDirectChatAsync()


1.0

– Ported LegacyChat to TextChatService’s api (includes modification of the PrivateMessaging module, for whisper, and removal of almost all text filtering functions)
– Moved all the Fast Flags (FFlags) into a FFlags module
– Added the EchoMessagesFromHiddenChannels setting, for use with the HiddenChannels setting
– Bug fixes related to HiddenChannels and dynamic resizing of message’s TextSize
– Some cleanup of the code


1.1

– Fixed error when sending a message in the system channel
– Fixed whisper not working due to me forgetting to add Chat:CanUsersDirectChatAsync() …
– Fixed Chat:CanUsersChatAsync() checking userIdTo twice, instead of userIdFrom and userIdTo
This could have been bad, but thankfully TextChatService:CanUsersChatAsync() was used internally instead
– Fixed the error message occurring when a player was leaving

– Destroying a TextSource now causes the associated speaker to leave the associated channel.
This behaviour also exists for TextChannels, destroying a TextChannel deletes the associated ChannelObj

– Added padding settings for the message log display (scrolling frame)
– Added texture settings for the underline bar of ChannelTabs
These two settings now allow for obtaining the exact look of the old LegacyChat


Up coming features:
– Support to make the OnIncomingMessage callbacks be able to modify the look of messages
– More settings to customize the visual look of the chat (exact LegacyChat look, and using images on the background frames)
– System messages currently don’t go through TextChannels. I’ll make them go through TextChannels to allow OnIncomingMessage callbacks to format the messages
– Adding types for MessageObj, and stuff
– Possibly getting the old bubble chat script working, if there is demand for it. I don’t really like the old bubble chat, so it’s not a priority

Known bugs:
– MessageHistoryLog is disabled by default. This is the last feature that is still using the legacy chat filtering system, as TextChatService doesn’t have an api to store previous messages. You can enable it in the FFlags module, but make sure to disable it before April 30th
TextChannel:SetDirectChatRequester() is currently throwing the error SetDirectChatRequester is not enabled. I wrapped it in pcalls, and whisper already uses :CanUsersDirectChatAsync() so should be fine. I assume this is a roblox bug…
– The lock for keeping the scrolling frame at the bottom sometimes fail when resizing the chat

Things people will think are bugs:
– Text messages are stuck as being a ___ placeholder if TextChatService blocks the message from being delivered (ChatCommands, ShouldDeliverCallback, etc). Set ShowUnfilteredMessagePlaceholder to false in the Settings module to fix


Introduction

If you’ve been living under a rock, I announce to you the deprecation of the LegacyChat system. Well, it’s not just a deprecation, everyone will have to migrate to the TextChatService api before april 30th, aka LegacyChat can’t be used past that date

Last year, I posted a custom version of the LegacyChat in community resources, which provides a more modern look, bug fixes, features, and chat translation (which was a built in feature of LegacyChat, just had to overwrite some FFlags and add a bool value to get it working :P). This resource is built on top of that

I like the LegacyChat, has it is built fully in lua and accessible by developers, it is probably one of (if not the) most advanced chat system on Roblox, and is fully customizable. The code is quite daunting at first, but it’s definitely not messy code, and isn’t so hard to build onto.
This resource is not just for people looking to maintain compatibility with old code that relied on the LegacyChat, this resource is a custom chat, for those looking to customize their game’s chat

TextChatService, I don’t like so much as it’s less customizable, Player.Chatted has inconsistent behavious (doesn’t fire on the client for the LocalPlayer, but fires for other players? What?), which breaks older chat commands scripts, getting the unfiltered version of messages is a pain in the ass, TextChatCommands only accept two aliases and basically lacks customizability, and I don’t like that roblox is kinda forcing it onto us

I will refer to my custom chat as a custom Lua chat system, as it was named the Lua chat system before TextChatService arrived, and my custom chat is a modernized version :P

Files

By default, the chat looks like this
LuaChatSystem_DefaultLook

The chat should go into ReplicatedStorage (although any container that replicates to the client will work)
image
ChatSettings is THE module for customizing the chat. It contains a lot of settings for the look of the chat and behaviour, most of which are from the original Lua chat system, but it also contains new settings I added
If you plan to use the TextChatService’s api (TextChatCommands, ShouldDeliverCallback, OnIncomingMessage, etc), set the setting module.ShowUnfilteredMessagePlaceholder = false


How to get the old chat look

Download this settings file: ChatSettings.lua (6.6 KB)
and replace the contents of ChatSettings with the contents of this file

To disable chat translations, you can either set TextChatService.ChatTranslationEnabled to false, or go into the FFlags module and set FFlags.UserIsChatTranslationEnabled to false


Download:
Creator store: https://create.roblox.com/store/asset/75678628110599
rbxm: Chat.rbxm (131.5 KB)

– Set TextChatService.ChatVersion to TextChatService
– Disable TextChatService.CreateDefaultCommands, and TextChatService.CreateDefaultTextChannels
– Disable TextChatService.ChatWindowConfiguration.Enabled, and TextChatService.ChatInputBarConfiguration.Enabled

Legacy Chat Compatibility & Changes Made

Here is a list of changes you’ll have to make to get your code working with this custom Lua chat system. You can use ctrl + shift + f to find and replace these in your scripts

LegacyChat Custom Lua chat system
Chat = game:GetService("Chat") Chat = require(game.ReplicatedStorage.Chat)
Player.Chatted Chat:GetPlayerChattedEvent(Player)
Or Chat:GetChattedEvent()
Chat:RegisterChatCallback(Enum.ChatCallbackType, func) Chat:RegisterChatCallback(ChatCallbackType, func)
ChatCallbackType is the name of the corresponding enum, as a string
StarterGui:SetCore(...) StarterGui:SetCore(...)
StarterGui:GetCore(...) StarterGui:GetCore(...)

Other methods from the Chat service that aren’t related to the lua chat system are not included in this custom chat.
The chat scripts use the new RunContext property, this means ChatServiceRunner and ChatScript are no longer getting cloned into ServerScriptService and PlayerScripts. So if you are requiring ChatService, require it inside ReplicatedStorage
Chat:GetChattedEvent() fires for any player and passes the player who chatted as the first argument. The arguments are Player : Player, Message : string and Recipient : Player?. Recipient was a deprecated argument, but I brought it back.
– I’ve changed Chat:RegisterChatCallback(...) to use a string instead of the ChatCallbackType Enum if I ever want to add more chat callback types in the future. You can do something like Enum.ChatCallbackType.[...].Name to get the appropriate string for the new method
StarterGui:SetCore() and StarterGui:GetCore() havn’t changed, I acutally forgot about those until I realized my game uses StarterGui:SetCore("ChatMakeSystemMessage",{...}). They still work as they used to, but there is no garantee they’ll work past april 30th. If it does end up breaking, I’ll do a custom api for it


Deeper integration with the LegacyChat system

Now, if your code has a deeper integration with the LegacyChat system, such as custom channels, custom commands, etc, be wary of the following:

For this port of the Lua chat system, I modified the chat itself, instead of recreating it. This means that in theory, everything should work out of the box (after doing the changes mentioned above). However, that was in theory, and that theory got broken quite quickly when I had to fix the whisper system

The custom Lua chat system relies on two important things to work alongside TextChannels.

  • First, the same message cannot be turned into multiple messageObjs (to be sent through different channels, in the case of whisper), since the TextChatService port requires that the ID of the messageObj received by the original sender is the same as the ID received by the receivers. When the sender receives back the messageObj from the server, it sends it through the associated TextChannel, with the ID as metadata, and the receivers will get the filtered message, and use the ID to associate it with their received messageObj
  • Second, a player must be in the TextChannel as a TextSource to send a message and receive filtered messages, whilst LegacyChat is allowed to send a messageObj from speaker A using speaker B, making it so a speaker doesn’t need to be in the channel in which the message is sent

These issues were a problem because whisper uses two channels, one being To Player1, the other being To Player2, where Player2 is the only speaker of the To Player1 channel, and same for Player1
Because of this, two messageObj used to be created for the same message, and then would be sent to the two channels. Moreover, messages between speakers are sent through channels that only have one of the two speakers.
That doesn’t work with TextChatService. I had to come up with solutions for these two problems, and if you encounter the same issues with your custom channel (if anyone went that far…), here were the solutions:

  • I moved the messageObj creation to an independant module, so whisper can create the messageObj directly in the command processor module script, and added speaker:SendMessageObj(message, messageObj, channelName, fromSpeaker) and channel:SendMessageObjToSpeaker(message, messageObj, speakerName, fromSpeakerName), so the same messageObj can be sent to different channels
  • I added speaker:JoinChannelAsListener(channelName), speaker:LeaveChannelAsListener(channelName), channel:InternalAddListenerSpeaker(speaker) and channel:InternalRemoveListenerSpeaker(speaker), which add a TextSource of the corresponding speaker to the TextChannel for TextChatService compatibility, without adding the speaker to the Lua chat system channel object

Other resources

There are already a handful of ports of the LegacyChat, but none that I’ve seen actually port LegacyChat as a whole. However, they might fit your needs better anyway, so here they are:
Textchatservice disguised as Legacy Chat
NewOldChat: Legacy Chat ported to TextChatService [BETA]
Basic Legacy Chat Rewrite for TextChatService
Old Chat System - LegacyChatSystem converted to TextChatService API
WinryChat | Open-Source Chat UI for TextChatService (This one isn’t a “LegacyChat”)

There is also this post about using the Lua chat system:
How to make chat-commands using the lua chat system

Here is the documentation page for the Lua chat system:
Legacy chat system
Lua Chat System (older version of the current docs, has some more stuff)

Footnotes

This post took so long to write ;-;

Anyway, I probably forgot some stuff, and I’ll probably rework the post as well. If you have any suggestion, feedback, or whatever, let me know!

If you want to test the chat without downloading it, I’ve added it to one of my games: Roblox - Game Discovery Hub. It will feel just like my custom LegacyChat though (that doesn’t use TextChatService), unless there are bugs

24 Likes

Legendary, thank you for this!

2 Likes

Really good! However, I found an issue with /c system.

External Media

It’s not a major bug, but for those of us with custom admin commands (like me), it’s unfortunate that we can’t use the system channel to hide our messages.

1 Like
Glazing

Very impressive what you have done. This has not been done by any of the other resources.

Personally, when making a resource like this, I found Legacy Chat code really large for no good reason at all, so I just decided recreate it instead.


Overall, it works really well. Only thing I would want here is an easier way to get the old Legacy Chat UI. This will probably come.


You could also add this link in the main post, as it provides some useful code examples and help:

2 Likes

Just a note: WinryChat isn’t a LegacyChat or a port of any chat system.
It’s a new one entirely to fix ROBLOX’s issues with TextChatService and Channel tabs.

3 Likes

It works fine and all but one little problem I saw with it was that when resizeing /activley doing it the scroll list keps moving up like it wont stay at the bottom

1 Like

Could you send a video? I don’t see what the unexpected behaviour is when doing it myself


I saw another post where you posted this old documentation page. I didn’t include it because it seems very similar to the existing documentation page, but there is that figure (the graph of how the chat system works) that is very nice
I do expect the existing documentation page to get removed probably past April 30th, so I will save an html of the page so people can still access it easily, though the new documentation site seems to be full of js…


Will fix! The error is very weird though, and I know /c system was working at some earlier point, unsure why that error is happening

Update: Changing the deprecated :TweenPosition() to TweenService fixed the issue. Cannot tell you why that error happens though

1 Like

1 Like

you should use source sans, the font looks different on this

You can easily change the font in the ChatSettings module. You can use a Font object, or a Font enum, both are supported. The ChatSettings lua file provided to get the Classic look of the chat uses SourceSansBold

I chose Arimo because I used to have GothamSemibold as my font for the custom chat, and Arimo is a font I quite like, as a replacement for Gotham, now that it was removed


@LeoBeomkl, Interesting, it seems like stopping the resizing action and starting it again might be what is causing it. I added it to the list of known bugs, but it’s a low priority bug

– UPDATE –

Fixed multiple bugs (See the version 1.1 section)

This update should make this custom lua chat system stable, will see if more errors pop up though


Added settings for making the chat look like LegacyChat exactly



(These aren’t the settings to make it look like LegacyChat, see the ChatSettings.lua file)

If these settings are missing from your ChatSettings module, a default value is be used instead. You can still use a ChatSettings module from version 1.0

I’ve noticed the size of the chat frame is smaller than how it was in the Legacy Chat when following these steps:

Here’s a comparison:
image

I found that it’s caused by the system using DefaultWindowSizeDesktop from the ChatSettings module. With normal Legacy Chat, it does not use it for some reason.


Also, this works whenever TextChatService.ChatVersion is set to LegacyChatService. Is this intentional?

This is a bug I’ve fixed in my old thread:

Link to the quote above

I’m not quite sure what the correct size would be if you want to have the exact size of the LegacyChat. I think that bug was inconsistent, and so the size was inconsistent, but I am not sure (I went on a game that still used the LegacyChat, and got the DesktopSize). You can try to set DefaultWindowSizeDesktop to be the same as DefaultWindowSizeTablet


I have tried setting TextChatService.ChatVersion to LegacyChatSerive, and disabled Chat.LoadDefaultChat, and I get this error:
TextChatService is not enabled. Check TextChatService.ChatVersion and make sure it is not set as ChatVersion.LegacyChatService.

If I don’t disable Chat.LoadDefaultChat, I don’t get any errors, but every chat message seem to go through LegacyChat. The two are using the same EventFolder, and my guess is that the LegacyChat ends up taking over the CallbackFunction for the RemoteFunctions, making it so the custom Lua chat system isn’t throwing an error?

1 Like