update rules

This commit is contained in:
Joe 2026-02-02 14:05:11 -06:00
parent 4c390fdd37
commit d5522b2fef
8549 changed files with 11783 additions and 1888 deletions

View file

@ -0,0 +1,55 @@
---
title: Custom text chat commands
description: Learn how to create custom chat commands.
---
`Class.TextChatService` has built-in chat commands for common purposes, such as muting other players and using avatar emotes. You can enable them by setting `Class.TextChatService.CreateDefaultCommands|CreateDefaultCommands` to `true` in Studio's **Properties** window.
You can also add custom commands using `Class.TextChatCommand`. Users sending a defined command in the chat input bar trigger a callback defined by `Class.TextChatCommand.Triggered` to perform your customized actions.
The following example shows how to create a chat command that allows players to increase or decrease their character's size when they input `/super` or `/mini`.
1. Add a `Class.TextChatCommand` instance inside `Class.TextChatService`.
2. Rename it to **SizeCommand**.
<img src="../../assets/studio/explorer/TextChatService-TextChatCommand.png" width="320" />
3. Set its `Class.TextChatCommand.PrimaryAlias|PrimaryAlias` property to `/super` and its `Class.TextChatCommand.SecondaryAlias|SecondaryAlias` to `/mini`.
<img src="../../assets/players/in-experience-text-chat/TextChatCommand-Aliases.png" width="320" />
4. Insert the following `Class.Script` inside `Class.ServerScriptService` to define a callback for the chat command that scales the character's size:
```lua title="Script" highlight="4,6"
local TextChatService = game:GetService("TextChatService")
local Players = game:GetService("Players")
local sizeCommand: TextChatCommand = TextChatService:WaitForChild("SizeCommand")
sizeCommand.Triggered:Connect(function(textSource, message)
local scaleMult = 1
local messageWords = string.split(message, " ")
if messageWords[1] == "/super" then
scaleMult = 2
elseif messageWords[1] == "/mini" then
scaleMult = 0.5
end
local player = Players:GetPlayerByUserId(textSource.UserId)
if player then
local character = player.Character
if character then
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
for _, child in humanoid:GetChildren() do
if child:IsA("NumberValue") then
child.Value *= scaleMult
end
end
end
end
end
end)
```
<video controls src="../../assets/players/in-experience-text-chat/Text-Custom-Command.mp4" width="90%"></video>

View file

@ -0,0 +1,56 @@
---
title: Assign chat tags
description: Example of how to assign chat tags to players based on their membership in a group.
---
This example demonstrates how to assign **chat tags** to players based on their membership in a [group](../../projects/groups.md). Chat tags are a way to visually identify a player in the chat window and useful for indicating a player's role or status.
<img src="../../assets/players/in-experience-text-chat/Chat-Tag-VIP.png" width="780" alt="VIP chat tag appended to user name in the chat window." />
Because [text chat callbacks](../in-experience-text-chat.md#text-chat-hooks-and-callbacks) expect a non-yielding callback, attempting to query the group membership status of a player in the `Class.TextChatService.OnIncomingMessage` callback is not recommended, as it may cause the chat system to hang or become unresponsive.
Instead, set a player [attribute](../../studio/properties.md#instance-attributes) when they join the server. Setting an attribute lets you reuse the player's status in other parts of your experience such as allowing access to particular areas or providing bonus experience.
1. Create a `Class.Script` in `Class.ServerScriptService` and add the following code to it:
```lua title="Server"
local Players = game:GetService("Players")
-- Replace 123456 with the group ID you want to check for
local groupID = 123456
Players.PlayerAdded:Connect(function(player)
local success, isInGroup = pcall(function()
return player:IsInGroup(groupID)
end)
if success and isInGroup then
player:SetAttribute("IsVIP", true)
else
player:SetAttribute("IsVIP", false)
end
end)
```
2. Create a `Class.LocalScript` in `Class.StarterPlayer` ⟩ `Class.StarterCharacterScripts` and add the following code to display a **\[VIP\]** tag in the chat window:
```lua title="Client"
local Players = game:GetService("Players")
local TextChatService = game:GetService("TextChatService")
TextChatService.OnIncomingMessage = function(message: TextChatMessage)
local textSource = message.TextSource
if textSource then
local player = Players:GetPlayerByUserId(textSource.UserId)
if player then
if player:GetAttribute("IsVIP") == true then
local overrideProperties = Instance.new("TextChatMessageProperties")
overrideProperties.PrefixText = "[VIP] " .. message.PrefixText
return overrideProperties
end
end
end
return nil
end
```

View file

@ -0,0 +1,44 @@
---
title: Proximity-based chat
description: Learn how to implement exclusive chat for users who are close to each other in locations using the TextChatService.
---
This example shows how to implement an exclusive chat for users who are near each other in the 3D world. It extends the callback with a function using `Class.TextSource` to identify the locations of a user who might be a potential message receiver. If this function returns `false`, it means that the user locates further than the preset valid range from the message sender, so the system doesn't deliver the message to that user.
Add the following to a `Class.Script` in `Class.ServerScriptService`:
```lua title="Server"
local TextChatService = game:GetService("TextChatService")
local Players = game:GetService("Players")
-- Get the chat channel for proximity-based chat
-- You can replace this general channel with a dedicated channel
local generalChannel: TextChannel = TextChatService:WaitForChild("TextChannels").RBXGeneral
-- Function to get the position of a user's character
local function getPositionFromUserId(userId: number)
-- Get the player associated with the given user ID
local targetPlayer = Players:GetPlayerByUserId(userId)
-- If the player exists, get their character's position
if targetPlayer then
local targetCharacter = targetPlayer.Character
if targetCharacter then
return targetCharacter:GetPivot().Position
end
end
-- Return a default position if the player or character cannot be found
return Vector3.zero
end
-- Set the callback for the general channel to control message delivery
generalChannel.ShouldDeliverCallback = function(textChatMessage: TextChatMessage, targetTextSource: TextSource)
-- Get the positions of the message sender and target
local sourcePos = getPositionFromUserId(textChatMessage.TextSource.UserId)
local targetPos = getPositionFromUserId(targetTextSource.UserId)
-- Deliver message if distance between sender and target is less than 50 units
return (targetPos - sourcePos).Magnitude < 50
end
```

View file

@ -0,0 +1,75 @@
---
title: Rate-limited text inputs
description: Learn how to implement a rate limit for any text field that might be used by players to conduct a conversation.
---
This example shows how to implement a rate limit of 1 minute on a text input field that allows players to post notes to a community bulletin board.
Add the following to a `Class.Script` in `Class.ServerScriptService`:
```lua title="Server"
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Create RemoteEvent for communication
local postNoteEvent = Instance.new("RemoteEvent")
postNoteEvent.Name = "PostNoteEvent"
postNoteEvent.Parent = ReplicatedStorage
-- Rate limit of one note per minute per player
local COOLDOWN_TIME = 60 -- Time in seconds
local lastPostTime = {}
local function canPlayerPost(player)
local userId = player.UserId
local currentTime = tick()
if lastPostTime[userId] then
local timeSinceLastPost = currentTime - lastPostTime[userId]
if timeSinceLastPost < COOLDOWN_TIME then
return false, COOLDOWN_TIME - timeSinceLastPost
end
end
return true, 0
end
-- Handle post requests with rate limit and text filtering
postNoteEvent.OnServerEvent:Connect(function(player, noteData)
local canPost, cooldown = canPlayerPost(player)
if not canPost then
postNoteEvent:FireClient(player, "cooldown", math.ceil(cooldown))
return
end
-- All text shared publicly must go through a text filter
local filterResult = getFilterResult(noteData.text, player.UserId)
if filterResult then
local success, filteredText = pcall(function()
return filterResult:GetNonChatStringForBroadcastAsync()
end)
if success then
-- Create the note
local note = {
text = filteredText
}
-- Update last post time
lastPostTime[player.UserId] = tick()
-- Send success response
postNoteEvent:FireClient(player, "success", note)
-- Broadcast new note to all players
postNoteEvent:FireAllClients("newNote", note)
else
warn("Error filtering text!")
end
end)
-- Clean up when player leaves
Players.PlayerRemoving:Connect(function(player)
lastPostTime[player.UserId] = nil
end)
```

View file

@ -0,0 +1,84 @@
---
title: Custom text chat UI
description: Example of how to create a simple frontend UI powered with TextChatService.
---
This example shows how to use the `Class.TextChatService` class to design your own frontend. It reuses the default text channels from `Class.TextChatService.CreateDefaultTextChannels|CreateDefaultTextChannels` and is very simple compared to the default UI.
1. Disable the default UI that comes with the `Class.TextChatService` by setting the `Class.ChatWindowConfiguration.Enabled` and `Class.ChatInputBarConfiguration.Enabled` properties to `false` in Studio's **Properties** window.
2. Create a replacement for the chat input bar. This is the text box that emits messages when the user presses <kbd>Enter</kbd>.
1. Create a `Class.ScreenGui` and parent it to `Class.StarterGui`.
2. Create a `Class.TextBox` and parent it to the new `Class.ScreenGui`, then [reposition](../../ui/position-and-size.md#position) and [resize](../../ui/position-and-size.md#size) it as desired.
3. Create a `Class.LocalScript` and parent it to the new `Class.TextBox`.
4. Add the following code to the `Class.LocalScript`:
```lua title="Client"
local TextChatService = game:GetService("TextChatService")
-- RBXGeneral is the default public channel
local RBXGeneral = TextChatService:FindFirstChild("TextChannels"):WaitForChild("RBXGeneral")
local textBox = script.Parent
textBox.FocusLost:Connect(function(enterPressed)
local text = textBox.Text
if enterPressed and #text > 0 then
local success, response = pcall(function()
return RBXGeneral:SendAsync(textBox.Text)
end)
if not success then
RBXGeneral:DisplaySystemMessage("Failed to send message")
end
-- Users expect the input box to be cleared after sending a message
textBox.Text = ""
end
end)
```
3. Create a replacement for the chat window. This is the `Class.ScrollingFrame` that displays messages as they are received from `Class.TextChatService.MessageReceived`. This step also creates a `Class.UIListLayout` to automatically layout the messages.
1. Create another new `Class.ScreenGui` and parent it to `Class.StarterGui`.
2. Create a `Class.ScrollingFrame` and parent it to the `ScreenGui`, then [reposition](../../ui/position-and-size.md#position) and [resize](../../ui/position-and-size.md#size) it as desired.
3. Create a `Class.UIListLayout` and parent it to the `Class.ScrollingFrame`.
4. Create a `Class.LocalScript` and parent it to the `Class.ScrollingFrame`.
5. Add the following code to the `Class.LocalScript`:
```lua title="Client"
local TextChatService = game:GetService("TextChatService")
-- Function to create a new text label for each message received
local function addMessageGui(textChatMessage: TextChatMessage)
local isOutgoingMessage = textChatMessage.Status == Enum.TextChatMessageStatus.Sending
local parent = script.Parent
local originalLabel = parent:FindFirstChild(textChatMessage.MessageId)
if originalLabel then
originalLabel.Text = textChatMessage.Text
originalLabel.BackgroundTransparency = if isOutgoingMessage then 0.5 else 0
else
local textLabel = Instance.new("TextLabel")
textLabel.BorderSizePixel = 0
textLabel.Font = Enum.Font.BuilderSans
textLabel.TextSize = 18
textLabel.TextXAlignment = Enum.TextXAlignment.Left
textLabel.BackgroundTransparency = if isOutgoingMessage then 0.5 else 0
textLabel.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
textLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
textLabel.Name = textChatMessage.MessageId
textLabel.AutomaticSize = Enum.AutomaticSize.XY
textLabel.Text = textChatMessage.Text
textLabel.Parent = parent
end
end
-- Start listening for incoming messages
TextChatService.MessageReceived:Connect(addMessageGui)
```
<Alert severity="warning">
When using the `Class.TextChatService.MessageReceived` event, it's important to check if the message already exists in the chat window. This event is called once when sending and once when the message is received from the server.
</Alert>
4. Test your experience by sending messages in the chat input bar. You should see the messages appear in the chat window. You can then expand on this example by adding features such as focusing the `Class.TextBox` when a key is pressed or adding [chat tags](./group-chat-tags.md).