I’ve worked quite a bit with the Lua Chat System. Although I haven’t ever made a shadow ban feature myself, I know it is possible to accomplish a feature like this.
Command functions will be your friend here. ChatModules will be run by the server to configure or extend the chat system. In the case of command functions, each of them are ran to process chats. We also have the ability to stop a chat from being processed through a command function by returning true.
Ever wonder why you can use /mute or /e without it showing up in the chat window? These are command functions. They run their respective functions, but also tell the ChatService not to continue processing the message. You can find more information on the documentation page I linked.
Since shadow banning is a server-side action, we also want to keep this system contained with the server. The idea is to swallow the chat but still send it to the client anyway. So with that in mind, we can get started on working to build this system.
You will need to create some of the directories that the Lua Chat System relies on, but you won’t need to fork anything. Start by creating the ChatModules folder in Chat. Add a BoolValue called InsertDefaultModules and make sure the value is checked off. This tells the Lua Chat System to fill the folder with the missing components at runtime. You’ll also want your module that tackles shadow bans, so you can go ahead and insert that as well.
When finished with the above setup, you should have a Chat service looking like this:
It’s all about editing the module from here. We’ll need at the very least the boilerplate for ChatModules (which should ideally be consistent). ChatModules typically return a function that will be called by the ChatService internally, passing itself to said function. Boilerplate code:
local function Run(ChatService)
local function ProcessMessage(speakerName, message, channelName)
end
ChatService:RegisterProcessCommandsFunction("swallow_shadow_ban_chat", ProcessMessage)
end
return Run
Everything happens within the ProcessMessage function. Since I assume your shadow ban command will act directly on ChatSpeakers (which I can cover a bit later), we’re just going to perform a few simple checks on the ChatSpeaker regarding whether or not they have a shadow ban tag. If they do, then we’ll swallow the chat but continue to show it to them.
To skip some time on unnecessary explanations and all, I’ve supplied the complete code with comments throughout so you can understand what’s going into this ChatModule and what each step will contribute towards making this system work.
--- Swallow chats for shadow banned users.
-- @module SwallowShadowBanChats
-- @author colbert2677
local function Run(ChatService)
local function ProcessMessage(speakerName, message, channelName)
-- Get the speaker and the channel they sent a message in
local speaker = ChatService:GetSpeaker(speakerName)
local channel = ChatService:GetChannel(channelName)
-- If neither exists, we're safe to continue processing via other methods
if not speaker then return false end
if not channel then return false end
-- Check if they are shadow banned
if speaker.ShadowBanned then
-- Send the message to themselves
speaker:SendMessage(message, channelName, speakerName, message.ExtraData)
-- Speaker was shadow banned, stop processing message
return true
end
-- Speaker is fine, continue processing message
return false
end
ChatService:RegisterProcessCommandsFunction("swallow_shadow_ban_chat", ProcessMessage)
end
return Run
That’s pretty much all there is to it. Done. The rest of the effort will now come from you to determine how to insert and toggle the shadow ban tag in the ChatSpeaker object.
I have some test code that can also serve as a guiding line if you need that, though I trust that you already have your own way of doing this and you just needed to know how to stop messages from being sent to anyone except themselves.
Do not run this from the command bar. The command bar runs on a different VM, so it won’t be able to accurately execute this code because ChatSpeakers don’t exist for it. Create a new script in ServerScriptService with Disabled on and put this in. Execution steps will be included below.
local ServerScriptService = game.ServerScriptService
-- Need to access ChatService to work with its API
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)
-- Add the ShadowBanned tag to a ChatSpeaker for testing
local VictimSpeaker = ChatService:GetSpeaker("Player1")
VictimSpeaker.ShadowBanned = true
Player1 is now shadow banned as per the Chat system, but Player2 is not. To test if this holds true, start a local session of 2 players or more as you like. Go to the server view and enable the script by making Disabled false, then switch back to your clients. Send a message from Player1 and one from Player2. If this worked, Player1 should see both chats, but Player2 will only see their own.
And just like that. Shadow banned.
You could probably also write the shadow ban command via the ChatService if you follow the conventions of the mute speaker command. You’d just need to think in terms of using this shadow ban system rather than making it so that only the clients that muted a speaker don’t get the message.
Let me know if you have any questions or anything, always happy to help developers when it comes to working with the Lua Chat System.
I’ve supplied the system worked out above as a file in case you want to use a reference, want to use it directly how I set it up or want hands-on work with it:
Shadow Ban System.rbxl (137.0 KB)