Hey there, cool tutorial!
There’s some feedback I would like to provide about this tutorial to better the experience of using the Lua Chat System to accomplish chat tags, primarily in the realm of API usage. I would encourage you to take a look at some of the docs, since they do have some very useful functions that you can use to your advantage. You can also avoid being dependent on things you don’t need.
GetService
Please use GetService to remain consistent in how you get services. As some services can be renamed, do not have proper names (e.g. RunService has a space in it) or cannot be accessed through direct indexing, GetService is your friend for remaining consistent in how you fetch services.
WaitForChild use
ChatService does not need a WaitForChild chained off of ChatServiceRunner. When ChatServiceRunner is available, ChatService will also be. I don’t know where the guarantee lies here or if there is one, but I believe it comes from Clone. You can directly access ChatService when its parent is available, like so:
local ServerScriptService = game:GetService("ServerScriptService")
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)
Contain your function in a variable
ChatSpeakers can represent both players and non-player entities. You can also have unexpected cases in which you need to account for existing speakers, but cannot due to the way the code is set up. For any added event, there will typically always be a get event, so contrast that where possible.
-- speakerAdded fires with the name of the speaker, not players
local function speakerAdded(speakerName)
doCodeOnSpeaker()
end
ChatService.SpeakerAdded:Connect(speakerAdded)
for _, speaker in ipairs(ChatService:GetSpeakerList()) do
speakerAdded(speaker)
end
Use the API available to you
ChatSpeaker objects contain a GetPlayer method to fetch an associated player object. You need this, because your code currently assumes that all new speakers are players. If you do not account for the case of a non-player speaker, your code will error. You should almost never have to use the Players service when working with the ChatService.
local speaker = ChatService:GetSpeaker(speakerName)
local player = speaker:GetPlayer()
if player and TAGS[player.UserId] then
-- SetExtraData
end
Putting the feedback all together
With this feedback in mind, you can have a renewed code sample that allows you to set chat tags for players without any added bulk and you can also account for overlooked cases, such as the aforementioned non-player speaker case. Putting it all together, you can have a code sample that looks a bit like the following:
--- Allow a player to occupy a single chat tag
-- @author colbert2677
local ServerScriptService = game:GetService("ServerScriptService")
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)
local TAGS = {
[0] = {TagText = "TUTORIAL", TagColor = Color3.new(1, 0, 0)},
}
--- Call on chat speakers to apply their tags
-- For player speakers only
local function speakerAdded(speakerName)
local speaker = ChatService:GetSpeaker(speakerName)
local player = speaker:GetPlayer()
-- Safe, as if statement fails if first condition is falsy
if player and TAGS[player.UserId] then
-- Wrap tag in table, as Tags expects a table value worth of tags
speaker:SetExtraData("Tags", {TAGS[player.UserId]})
end
end
ChatService.SpeakerAdded:Connect(speakerAdded)
for _, speaker in ipairs(ChatService:GetSpeakerList()) do
speakerAdded(speaker)
end
If you wanted to add multiple tags, you could change the structure of the dictionary but you would also have to reflect that in the SetExtraData call so that it isn’t creating a table for something that has already been wrapped in a table.
I hope this feedback will prove useful towards improving the way you work with the chat system.