How to fix ChatService:GetSpeaker() returning nil?

I am attempting to mess with the ChatService module so I can change the tag color of players in chat, however, while calling :GetSpeaker(), it returns nil and continues to do so forever as shown it being done in the repeat loop that will never end. How do I fix it?

local ChatService
game.Players.PlayerAdded:Connect(function(player)
	if not ChatService then
		ChatService = require(game:GetService("ServerScriptService"):WaitForChild("ChatServiceRunner").ChatService)
	end
	local speaker = ChatService:GetSpeaker(player.Name) -- site of error
	repeat
		wait() -- never ends
	until speaker 
	wait(5)
    speaker:SetExtraData("ChatColor", Color3.fromHSV(100, 1, 1))
end)

I don’t know much about the chat module itself, but here’s what I can tell you from the logic:

The repeat wait() until speaker loop will never end because the variable speaker is only set once before it, thus the condition the loop is waiting for will not be met. If you want it to change, you’ll have to also be trying to find speaker in the loop itself. A simple change would look like this:

local speaker = ChatService:GetSpeaker(player.Name)
	if not speaker then
		repeat
		wait() 
		speaker = ChatService:GetSpeaker(player.Name)
		until speaker
	end
3 Likes

Thank you, I never thought about it and now I’ll be able to solve a lot of more looping problems in the future now because of that logic I haven’t thought of.

1 Like

Do NOT use loops here. Loops where unnecessary are evil. Use the proper events here as well: do not use PlayerAdded when trying to work with new speakers, use SpeakerAdded of ChatService. The Lua Chat System is an independent system with its own API so it makes sense to check when a speaker is added by the ChatService rather than the Players service which doesn’t weigh in on the former.

If you’re worried about not having access to the player, ChatSpeaker objects have a method of retrieving the player associated with a ChatSpeaker, GetPlayer. You can use this if you need a reference to the player at any point. Judging by your code though, doesn’t seem that way.

local ServerScriptService = game:GetService("ServerScriptService")
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)

local function speakerAdded(speakerName)
    local speaker = ChatService:GetSpeaker(speakerName)
--  local player = speaker:GetPlayer()

    speaker:SetExtraData("ChatColor", Color3.fromHSV(100, 1, 1))
end

ChatService.SpeakerAdded:Connect(speakerAdded)
for _, speaker in ipairs(ChatService:GetSpeakerList()) do
    speakerAdded(speaker)
end
6 Likes

Is there a :Wait() and :Disconnect() method for SpeakerAdded event?

SpeakerAdded is implemented as the .Event of a BindableEvent server-side which behaves like a standard signal. Wait is implemented for it, disconnect isn’t because disconnect is a method of RBXScriptConnections (different from an RBXScriptSignal). Any and all connections have disconnect methods, that’s a separate object class altogether.

1 Like

Forgot about that, thanks for the important information.