mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-24 06:34:09 +00:00
update rules
This commit is contained in:
parent
4c390fdd37
commit
d5522b2fef
8549 changed files with 11783 additions and 1888 deletions
|
|
@ -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>
|
||||
56
.cursor/rules/roblox/en-us/chat/examples/group-chat-tags.md
Normal file
56
.cursor/rules/roblox/en-us/chat/examples/group-chat-tags.md
Normal 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
|
||||
```
|
||||
44
.cursor/rules/roblox/en-us/chat/examples/proximity-chat.md
Normal file
44
.cursor/rules/roblox/en-us/chat/examples/proximity-chat.md
Normal 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
|
||||
```
|
||||
|
|
@ -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)
|
||||
```
|
||||
|
|
@ -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).
|
||||
Loading…
Add table
Add a link
Reference in a new issue