Unable to Chat Tag Not Working

Hello,

I am having issues with creating an unable to chat tag for players on the client.

First off, I have this function on the Server (PlayerManager), which should get all users that a player can chat with. I have it batches as Roblox seems to have a limit to how many players you can get at once, so I put it as a 25 player batch.

local function getUserIds()
	local userIds = {}
	for _, plr in srv.players:GetPlayers() do
		table.insert(userIds, plr.UserId)
	end
	return userIds
end

local MAX_BATCH : number = 25
local function getPlayersCanChatWith(getUserId : number)
	local userIds = getUserIds()
	if Shared.IsStudio then
		return userIds
	end
	
	local allowedUsers = {}
	for i = 1, #userIds, MAX_BATCH do
		local batch = {}
		for j = 1, math.min(i + MAX_BATCH - 1, #userIds) do
			table.insert(batch, userIds[j])
		end
		
		local succ, result = pcall(function()
			return srv.text:CanUsersDirectChatAsync(getUserId, batch)
		end)
		if succ and result then
			for _, userId in result do
				if table.find(allowedUsers, userId) then
					continue
				end
				table.insert(allowedUsers, userId)
			end
		end
		
		task.wait(0.05)
	end
	return allowedUsers
end

Now, when the player joins, I call an event to that player to the Client, letting them know who they can chat with

		for _, plr : Player in srv.players:GetPlayers() do
			local char : Model = plr.Character
			if not (plr ~= player and char) then
				-- If no character, skip
				continue
			end
			
			local head : BasePart = char:WaitForChild("Head", 5)
			local tag : BillboardGui = head and head:FindFirstChild("OverheadGui")
			local succ, err = pcall(function()
				self.Client.CharacterAdded:Fire(player, plr, char, tag, getPlayersCanChatWith(plr.UserId))
			end)
			if Shared.IsStudio and not succ then
				warn(err)
			end
		end

Then, also, when a new character is added, it sends an event to every player in the game letting them know if they can chat with that player or not

player.CharacterAdded:Connect(function(character : Model)
		local tag : BillboardGui = client:AssignTag()
		local succ, err = pcall(function()
			self.Client.CharacterAdded:FireAll(player, character, tag, getPlayersCanChatWith(player.UserId))
		end)
		if Shared.IsStudio and not succ then
			warn(err)
		end
end)

Then, on the Client, I am setting the tag to visible if their UserID is found inside of the table that getPlayersCanChatWith gives

	local function initChar(plr : Player, char : Model, tag : BillboardGui, canChat : NumberArray)
		if not (plr ~= player and char and tag) then
			return
		end
		canChat = canChat or {}
		
		local icon : ImageLabel = tag:WaitForChild("Icons"):WaitForChild("NoChat", 5)
		if not icon then
			return
		end
		icon.Visible = not table.find(canChat, player.UserId)
	end
	PlayerManager.CharacterAdded:Connect(initChar)

So, that is the entire setup process. For some reason, almost every user is set as they cannot talk with eachother, even though they can. Proof below:

So, what can be causing this? Am I calling it too much? Should I cache things? Does anyone else have any experience in this that they can give me.

Thanks.

4 Likes

Before the task.wait(0.05) line in the first sample, could you try to print out what allowedUsers is?

The issue is, is that this is almost impossible to test within Studio, as the multiple clients do not really have ids. If it works as intended, it should just be a table full of userids.

There are two bugs here:

Bug 1 (main cause) - You’re calling CanUsersDirectChatAsync in a loop for every existing player on join.
This fires multiple simultaneous async API calls at once. Most of them fail silently (pcall catches it but succ is false), so allowedUsers stays empty for those players → table.find returns nil → icon shows for everyone. Instead, call getPlayersCanChatWith ONCE for the joining player and send that single result to them for all existing characters:

local canChat = getPlayersCanChatWith(player.UserId)

for _, plr in srv.players:GetPlayers() do
    local char = plr.Character
    if not (plr ~= player and char) then continue end
    
    local head = char:WaitForChild("Head", 5)
    local tag = head and head:FindFirstChild("OverheadGui")
    self.Client.CharacterAdded:Fire(player, plr, char, tag, canChat)
end

Bug 2 — Your batch inner loop starts at j = 1 instead of j = i.
This means every batch re-starts from the beginning of the array, building batches that grow larger than MAX_BATCH on each iteration:

-- Wrong:
for j = 1, math.min(i + MAX_BATCH - 1, #userIds) do

-- Correct:
for j = i, math.min(i + MAX_BATCH - 1, #userIds) do

For small servers (under 25 players) Bug 2 won’t matter, but Bug 1 will still cause all the failed API calls.

1 Like

Thank you,

I will release this patch and see what happens. On bug #1, I completely forgot about the API’s failing due to it being called too fast, and especially for every player in the server (100 max), which could be bad.

I will mark this as the solution later if it seems to have been fixed.

The UserIds of the clients seem to descend from -1… for whatever reason.

(i suppose you’re using servers & clients)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.