Creating compliant Announcements from “Admin Commands” (:m / :h) using TextChatService

Preramble on how we got here

Migrate to TextChatService: Removing Support for Legacy Chat and Custom Chat Systems

I think this announcement came as a really big shocker to most, however it was destined to happen sooner or later given the landscape of governments imposing restrictions on corporations. (For example in the USA see Kosa “Kids online safety act”) In order to simplify compliance with regulations all governments, having all peer to peer messages being sent through a single service actually makes a reasonable amount of sense.

I think a lot of people misinterpretation that Announcements from Admin Commands would be impossible since they are deemed to be a form of chat and custom chats will no longer be allowed.

This however is simply not the case:

Developers are able to create visual elements at such as admin command announcements as long as they do not create a custom chat and instead go through the TextChatService TextChannels API. In today’s tutorial we’ll be doing just that!


In order to make Compliant Announcements from Admin Commands, all command text must go through the TextChatService Apis. You cannot send Announcements through a remote event or function as that would constitute as creating a custom chat.


To start off, we’ll just make a simple script and text label inside of a ScreenGui. And also a server script anywhere it can run.

image

On the server, the main thing that we want to do is to authenticate the user who sent the admin command and if they are an admin, set the Metadata field of the TextMessage to indicate such. (This is actually the purpose of the metadata field, see TextChatMessage | Documentation - Roblox Creator Hub)

For this we’ll use ShouldDeliverCallback as OnIncomingMessage can only be run on the client.

local Players = game:GetService('Players')
local TextChatService = game:GetService('TextChatService')
local TextChannel: TextChannel = game:GetService('TextChatService'):WaitForChild('TextChannels'):WaitForChild('RBXGeneral')

-- Simple admins table
local Admins = {
	[82806501] = true,
	kingerman88 = true
}

TextChannel.ShouldDeliverCallback = function(message: TextChatMessage)
	-- Get the player
	local player = message.TextSource and Players:GetPlayerByUserId(message.TextSource.UserId)
	
	if player and (Admins[player.Name] or Admins[player.UserId]) then
		message.Metadata = "UserIsAnAdmin" -- Set a custom metatag!
	elseif message.Metadata == "UserIsAnAdmin" then -- check for goofy exploiters
		message.Metadata = "" -- no admin for you!
	end
	
	return true
end

Moving back to the client, we’ll now take the message and check the Metadata for the UserIsAnAdmin tag

local Players = game:GetService('Players')
local TextChatService = game:GetService('TextChatService')

TextChatService.MessageReceived:Connect(function(message: TextChatMessage)
	local sender: Player = nil
		
    -- Check if the message was sent by a user (not a system message)
	if message.TextSource and message.TextSource.UserId then
		sender = game:GetService('Players'):GetPlayerByUserId(message.TextSource.UserId)
	end
	
    -- If the message was validated by the server and it's the !m command then show it
	if message.Metadata == "UserIsAnAdmin" and message.Text:match("!m (.+)") then
		local text = `{sender.Name}: {message.Text:match("!m (.+)")}`
		script.Parent.TextLabel.Visible = true
		script.Parent.TextLabel.Text = text
		task.wait(5)
		if script.Parent.TextLabel.Text == text then
			script.Parent.TextLabel.Visible = false
			script.Parent.TextLabel.Text = ""
		end
	end
end)

Simple as that


Most admin commands can probably exist without this, however anything that constitutes chat will need to go through TextChatService to be compliant with newer regulations. Hope this helps you out and helps to explains a thing or two! (RIP users who are still using old Khols admin :pensive:)