Attempt to call a nil value when attempting to send a system message to chat

While looking for a solution to wanting to add a custom message that the system would send to all players in chat I tried this:

While it was marked as the solution on the given post, when I tried to implement it into my own game through a server-side script I got this error:
ServerScriptService.TheGame:35: attempt to call a nil value

I looked for answers and found a post that used the same extract and they had the same issue:

Though the only solution given on the post was one that not only didn’t exactly answer the question but didn’t clearly explain how to implement it, so I was left confused and didn’t know how to add it to the script.

Here is the code:

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

local Owner = {13712786}

local function SendSystemMessageToAllSpeakers(msg, channel)
	for _, v in pairs(ChatService:GetSpeakers()) do -- (This is line 35)
		v:SendSystemMessage(msg, channel)
	end
end

local function onPlayerAdded(player)
	if table.find(Owner, player.UserId) then
		local formatStr = string.format("[Server] THEY HAVE ARRIVED.")
		SendSystemMessageToAllSpeakers(formatStr, "All")
	else
		local formatStr = string.format("[Server] %s has joined the game.",player.Name)
		SendSystemMessageToAllSpeakers(formatStr, "All")
	end
end

local function onPlayerRemoved(player)
	if table.find(Owner, player.UserId) then
		local formatStr = string.format("[Server] jk lol")
		SendSystemMessageToAllSpeakers(formatStr, "All")
	else
		local formatStr = string.format("[Server] %s has left the game.",player.Name)
		SendSystemMessageToAllSpeakers(formatStr, "All")
	end
end

for _, player in pairs(Players:GetPlayers()) do
	onPlayerAdded(player)
end

Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoved)

Any solutions will be appreciated, thank you!

1 Like

Okay a quick look at the Api for ChatService shows that GetSpeakers doesn’t exist, likely you’d need to loop through all the players in the game and use GetSpeaker with their name which gives you a ChatSpeaker that you can use SendSystemMessage on

So would I do that like

for _, player in pairs(Players:GetPlayers()) do
	ChatService:GetSpeaker(player)
end

?

Okay so Iwas bit incorrect on my previous statement, there is a way to get all the speakers through GetSpeakerList, not sure why it isn’t listed on the developer wiki,

I tried this and the furthest I got was a warning that said that I received a system message in a channel I’m not in, which was the channel you were using

I’ll assume you alreayd have that set up, this is what you should use. You dont need to use PlayerAdded and PlayerRemoving since you can listen for when speakers are added and use the GetPlayer method they have

local Players = game:GetService("Players")

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

local Owner = {13712786}

local function SendSystemMessageToAllSpeakers(msg, channel)
	for _, speakerName in pairs(ChatService:GetSpeakerList()) do
		local speaker = ChatService:GetSpeaker(speakerName)
		speaker:SendSystemMessage(msg, channel)
	end
end

local function speakerAdded(speakerName)
	local speaker = ChatService:GetSpeaker(speakerName)
	local player = speaker:GetPlayer()
	if table.find(Owner, player.UserId) then
		local formatStr = string.format("[Server] THEY HAVE ARRIVED.")
		SendSystemMessageToAllSpeakers(formatStr, "All")
	else
		local formatStr = string.format("[Server] %s has joined the game.",player.Name)
		SendSystemMessageToAllSpeakers(formatStr, "All")
	end
end

local function speakerRemoved(speakerName)
	local speaker = ChatService:GetSpeaker(speakerName)
	local player = speaker:GetPlayer()
	if table.find(Owner, player.UserId) then
		local formatStr = string.format("[Server] jk lol")
		SendSystemMessageToAllSpeakers(formatStr, "All")
	else
		local formatStr = string.format("[Server] %s has left the game.",player.Name)
		SendSystemMessageToAllSpeakers(formatStr, "All")
	end
end

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

I think you meant to write all and not All

Edit: The speakerRemoved part is gonna error so not sure how likely you can set that up, you’d probably need to store stuff about the player that joined in a table

would it just be better to find an alternate method instead at this point? I feel like its starting to get into “patch over patch over patch” territory creating a giant mess since I don’t actually have a solution set up for converting “all” into whatever is needed for the players as it wasn’t mentioned in the original thread.

I think that would be a better approach as this is becoming a bit wonky to have to keep patching a lot. A simple way would be to have the server call the clients via remote event to make a system message for everytime a player joins and leaves, of course checking if they’re an owner.

There should be a good amount of tutorials out there with code that you can learn about

1 Like

Alright, thank you for the help anyway!

1 Like