舊版聊天系統

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

層級

舊版聊天系統使用 客戶端-伺服器模型。服務器側聊天模組組件 ChatChannelChatSpeaker 管理由服務器上的 ChatService 處理,而客戶端負責輸入和顯示消息。服務器與客戶端之間的通信會自動使用 RemoteEvents 來處理。

引擎服務本身是聊天系統的必要存儲單元:當 Roblox 位置載入(在客戶端或 Studio 運行或播放時)時,如果 是真實的,下列組件將自動加載到 服務。

  • 聊天模組 — 這個 Folder 是由 ChatServiceRunner 所需的模組集。這個文件夾的所有內容都被腳本需要,並用於在服務伺服器上創建自定義行為。
  • 客戶端聊天模組 — 此文件夾包含各種由 ModuleScripts 需要的 **** 。
    • 指令模組 — 包含用於實現客戶端聊天指令的模組。
    • 訊息創作者模組 — 包含用於處理和格式化訊息的模組。
    • 聊天常量 — 包含服務器和客戶端共享的常量。
    • 聊天設定 — 儲存各種設定以配置 聊天窗口 的不同方面。
  • 聊天本地化 — 儲存文字翻譯的資料結構。
  • 聊天服務執行器 — 這個 Script 執行聊天服務器的組件。一般來說,這不需要修改以創建自訂聊天行為和功能。
  • 對話泡泡 — 顯示使用者聊天訊息在他們的遊戲虛擬人偶上(如果啟用)。
  • 聊天腳本 — 這個 LocalScript 執行聊天客戶端組件。像 ChatServiceRunner 一樣,這不需要修改以自定義聊天。當遊戲運行時,會自動將其複製到 StarterPlayerScripts

修改聊天系統

若要修改或自訂舊版聊天系統,您必須先複製上面的階層。

  1. 導航器 窗口中,尋找 TextChatService 。然後,在 屬性 窗口中,將 聊天版本 屬性設為 LegacyChatService

  2. 使用 播放 按鈕運行體驗(F5)。

  3. 選擇並複製(Ctrl C C )添加到Chat 的對象。

  4. 使用 停止 按鈕停止體驗(ShiftF5)。

  5. 選擇 Chat粘貼到 ( Ctrl Shift V Shift V ) 複製的對象 (它們必須被父級到 Chat 因為體驗運行時)。

  6. 確保 Chat.LoadDefaultChat 已啟用。

聊天工作流程

在製作模組以自訂聊天之前,了解聊天訊息通過的工作流程很重要。除了傳送文字訊息外,聊天系統內建置了各種指令,因此每一則訊息都必須檢查是否需要解釋為指令或只是文字訊息。即使是文字訊息也可以在過程中修改和過濾。

使用者專注於聊天輸入並輸入角色之後,客戶端立即進行多個檢查。如果字元是 Esc,輸入框關閉,並沒有進行任何操作。如果字元是除了 Enter 以外的任何東西,文字將通過 進行中的指令處理器 傳送。這些用於評價文字,看看是否需要採取任何行動。例如,當使用者開始使用 /whisper 指令進行悄悄話時,指令後立即輸入使用者名稱時,輸入框會變更以表示使用者現在正在進入悄悄話通頻道。

在聊天的客戶端上,有兩種類型的處理器:進行中已完成。前者在每個字元輸入完畢後評估,而後者僅在使用者輸入完畢並點擊 Enter 時評估。

當使用者完成輸入並點擊 Enter 文字時,其輸入將通過多個指令處理器傳送。如果 進行中的指令 創建了自定义聊天狀態,聊天將檢查狀態以確定最終指令是否應該執行,並確定訊息是否應該繼續。如果訊息可以繼續傳送,則文字會通過另一組稱為 完成 的處理器傳送。如果這些處理器之一返回真值,訊息就停止傳送。否則,訊息將傳送到伺服器。

一旦訊息抵達伺服器,它將經過另一個指令處理器集合。和客戶端上的 完成 過程器一樣,如果這些過程器中的任何一個返回真值,則訊息執行將停止。否則訊息會通過一組過濾器(包括預設 Roblox 聊天過濾篩選器)傳送。一切完成後,訊息將傳送給所有通道和適當的發言者。

伺服器模組

放入 聊天模組 的模組可用於各種用途。這些模組可用於管理聊天頻道和發言者、添加過濾和指令功能、運行聊天機器人或任何需要在伺服器上處理的其他內容。要與聊天系統互動,每個模組都會傳送 ChatService 物件。

ChatServiceRunner 開始運行時,它需要 ChatModules 內的每個模組。它期望每個模組返回一個函數,然後依序呼叫每個模組,將其 聊天服務 對象傳給每個函數。無論模組的目的是什麼(執行機器人、添加過濾功能等),它都需要遵循此形式才能運作。

樣板模組框架

local function Run(ChatService)
-- 代碼在這裡
end
return Run

新增通道

一個 聊天模組 最簡單的事情之一是管理 通道 。通道對象可以使用 AddChannel()方法 創建。請注意,通道對象只需要在呼叫該通道的成員(例如其屬性和功能)時使用。當從 ChatServiceChatSpeakers 的上下文中引用通道時,通頻道的名稱會被用來參考它。


local function Run(ChatService)
local myChannel = ChatService:AddChannel("MyChannel")
end
return Run

基本通道配置

通道有許多可以用來稍微修改它們的屬性。例如,此模組創建一個通道並設置歡迎訊息,並讓使用者在進入體驗時自動加入通道。


local function Run(ChatService)
local myChannel = ChatService:AddChannel("MyChannel")
-- 設置使用者加入通頻道時顯示的訊息
myChannel.WelcomeMessage = "Welcome to my channel!"
-- 讓玩家在進入遊戲時自動加入通道
myChannel.AutoJoin = true
end
return Run

通道事件

通道有許多可以訂閱的事件。當聊天頻道發布 聊天訊息 時,當 聊天講者 離開或加入,或當講者被靜音或解除靜音時,這些事件會發生。例如,此模組會創建名稱為 MyChannel 的通道。每當喇叭加入或離開通道時,系統訊息將被傳送給通道中的所有喇叭通知他們關於事件的信息。


local function Run(ChatService)
local myChannel = ChatService:AddChannel("MyChannel")
local function onSpeakerJoined(speakerName)
myChannel:SendSystemMessage(speakerName .. " has joined the channel.")
end
local function onSpeakerLeft(speakerName)
myChannel:SendSystemMessage(speakerName .. " has left the channel.")
end
myChannel.SpeakerJoined:Connect(onSpeakerJoined)
myChannel.SpeakerLeft:Connect(onSpeakerLeft)
end
return Run

指令功能

聊天模組可以做的另一件強大的事情是聊天指令。當訊息傳送到伺服器時,聊天會通過已註冊到 ChatService 和相關通頻道的每個指令功能發送訊息。這些功能會將訊息傳送給訊息被傳送到的揚聲器、訊息和通道。函數可以執行任何需要的操作,然後返回真或假。如果函數返回真值,則訊息將停止由聊天系統處理。它不會被傳送到任何指令功能,也不會顯示在聊天窗口中。如果函數返回 false,則訊息會繼續通過所有其他指令功能。如果指令功能之一沒有返回真值,則訊息將通過過濾器傳送,然後顯示。

指令功能經常用於實現 管理指令,這是一些用戶可以使用的文字指令,可以通過聊天中說的特定文字來操縱體驗狀態。

在這個例子中,一個 聊天模組 被用來創建一個 Part 如果使用者在聊天中輸入 /part 。請注意,此功能會返回真值,如果創建了一個部分,將停止訊息繼續進行,並且訊息將不會顯示。如果零件未創建,此功能需要返回 false,以便訊息能繼續通過系統工作。


local Workspace = game:GetService("Workspace")
local function Run(ChatService)
local function createPart(speakerName, message, channelName)
if string.sub(message, 1, 5) == "/part" then
local newPart = Instance.new("Part")
newPart.Parent = Workspace
return true
end
return false
end
ChatService:RegisterProcessCommandsFunction("createPart", createPart)
end
return Run

兩個聊天頻道聊天服務本身都可以有聊天指令。 聊天服務 指令處理器將在伺服器務器收到的每一個訊息上執行,而通道指令處理器只會在指令處理器註冊的通道上傳送訊息時執行。

過濾功能

指令功能 未阻止的訊息將通過所有已註冊給 聊天服務 和相關通道的過濾功能。每個過濾功能都會傳送發言者、訊息對物件和通道名稱。對訊息對象進行的任何變更將持續存在,每個後續過濾功能都會看到更新的訊息。請注意,過濾功能不需要返回值。

在這個例子中,簡單的過濾功能已註冊,使每個訊息都會以小寫出現。


local function Run(ChatService)
local function makeLowercase(sender, messageObject, channelName)
messageObject.Message = string.lower(messageObject.Message)
end
ChatService:RegisterFilterMessageFunction("makeLowercase", makeLowercase)
end
return Run

客戶模組

放入 客戶端聊天模組 的模組可用於為客戶端創建自訂行為。這些模組被分為兩個不同的文件夾:指令模組訊息創作者模組

指令模組

指令模組 與服務器上註冊指令功能的模組相似工作。這些模組定義會在使用者輸入文字後發射的功能。該文字可以閱讀,指令可以將訊息傳送到服務器或停止訊息的進度。在訊息結尾評價的指令以 COMPLETED_MESSAGE_PROCESSOR 標示,而在每個字符後評價的指令以 IN_PROGRESS_MESSAGE_PROCESSOR 標示。

在兩種指令類型中,模組必須返回一個字典,說明指令應該使用哪種類型的處理器,以及當處理器被呼叫時執行哪個功能。例如,一個 完成的訊息處理器 應該採取以下形式:


local util = require(script.Parent:WaitForChild("Util"))
function ProcessMessage(message, ChatWindow, ChatSettings)
end
return {
[util.KEY_COMMAND_PROCESSOR_TYPE] = util.COMPLETED_MESSAGE_PROCESSOR,
[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage
}

請注意,枚舉 列表在 命令模組 文件夾內的 Util 內定義。

已完成的訊息指令

完成訊息指令 會在使用者輸入完畢且按下Enter時評估。處理器的功能是傳送 聊天訊息 對物件、客戶的 聊天窗口聊天設定 表。如果函數返回真值,則訊息將停止處理並不會傳送到伺服器。否則它將被傳送給所有其他處理器,最終傳送到伺服器,如果沒有其他處理器停止它。

例如,以下處理器會在使用者輸入指令 /last 時移除當前通道中最舊的訊息。


local util = require(script.Parent:WaitForChild("Util"))
function ProcessMessage(message, ChatWindow, ChatSettings)
if string.sub(message, 1, 5) == "/last" then
local currentChannel = ChatWindow:GetCurrentChannel()
if currentChannel then
currentChannel:RemoveLastMessageFromChannel()
end
return true
end
return false
end
return {
[util.KEY_COMMAND_PROCESSOR_TYPE] = util.COMPLETED_MESSAGE_PROCESSOR,
[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage
}

進行中的指令

進行中的指令 每次用戶輸入聊天輸入時都會評估。例如,以下代碼在每次按下鍵後播放一次敲響,讓它聽起來像是使用打字機輸入:


local util = require(script.Parent:WaitForChild("Util"))
local keyEffect = Instance.new("Sound")
keyEffect.SoundId = "rbxassetid://12221976"
keyEffect.Parent = script
function ProcessMessage(message, ChatWindow, ChatBar, ChatSettings)
keyEffect:Play()
end
return {
[util.KEY_COMMAND_PROCESSOR_TYPE] = util.IN_PROGRESS_MESSAGE_PROCESSOR,
[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage
}

進行中的指令經常用於製作 自訂狀態 以便聊天向特定用戶發送消息,而不是只向現有通頻道發送。例如,寂靜和團隊聊天系統檢查用戶是否輸入了 /whisper/team 各自,然後將完成的訊息傳送給適當的使用者。

期望一個自訂狀態是表,具有以下功能:

  • TextUpdated() — 當輸入框中的文字變更時呼叫。
  • GetMessage() — 在使用者完成輸入訊息並點擊 Enter 之後呼叫。此功能應返回一個字串。
  • ProcessCompletedMessage() — 在訊息正在處理時呼叫。自訂狀態處理器總是會在完成的訊息處理器之前發射。像其他處理器一樣,此功能應在訊息停止傳送時返回真值,否則應返回假值。
  • Destroy() — 在訊息已傳送後呼叫。應該用於清理由自訂狀態設置的任何東西。

為了使用自訂狀態,指令模組的 ProcessMessage() 功能必須返回狀態。基本的自訂狀態將採取以下形式:


local util = require(script.Parent:WaitForChild("Util"))
local oneLineState = {}
oneLineState.__index = oneLineState
function oneLineState:TextUpdated()
local text = self.TextBox.Text
local length = string.len(text)
if length > 20 then
local chopLength = length - 20
local addToPrefix = string.sub(text, 1, chopLength)
self.Prefix = self.Prefix .. addToPrefix
self.TextBox.Text = string.sub(text, chopLength + 1)
end
end
function oneLineState:GetMessage()
local fullString = self.Prefix .. self.TextBox.Text
return fullString
end
function oneLineState:ProcessCompletedMessage()
return false
end
function oneLineState:Destroy()
self.Destroyed = true
end
function oneLineState.new(ChatWindow, ChatBar, ChatSettings)
local obj = {}
setmetatable(obj, oneLineState)
obj.Destroyed = false
obj.ChatWindow = ChatWindow
obj.ChatBar = ChatBar
obj.ChatSettings = ChatSettings
obj.TextBox = ChatBar:GetTextBox()
obj.MessageModeLabel = ChatBar:GetMessageModeTextLabel()
obj.Prefix = ""
return obj
end
local function ProcessMessage(message, ChatWindow, ChatBar, ChatSettings)
return oneLineState.new(ChatWindow, ChatBar, ChatSettings)
end
return {
[util.KEY_COMMAND_PROCESSOR_TYPE] = util.IN_PROGRESS_MESSAGE_PROCESSOR,
[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage
}

使用自訂狀態的主要優點之一是模組可以編輯聊天欄和其包含的文字,而使用者在輸入功能和外觀方面都輸入時,然後輕鬆重置它(一旦傳送消息後,自訂狀態將自動移除並將所有內容重置為正常)。例如,這段代碼設定了一個只允許一次顯示 20 個字符的自訂狀態,以便在文字框中顯示。如果使用者繼續輸入,字串的開頭字元暫時移除。當使用者傳送訊息時,所有被移除的字元都會被添加回訊息。


local util = require(script.Parent:WaitForChild("Util"))
local oneLineState = {}
oneLineState.__index = oneLineState
function oneLineState:TextUpdated()
local text = self.TextBox.Text
local length = string.len(text)
if length > 20 then
local chopLength = length - 20
local addToPrefix = string.sub(text, 1, chopLength)
self.Prefix = self.Prefix .. addToPrefix
self.TextBox.Text = string.sub(text, chopLength + 1)
end
end
function oneLineState:GetMessage()
local fullString = self.Prefix .. self.TextBox.Text
return fullString
end
function oneLineState:ProcessCompletedMessage()
return false
end
function oneLineState:Destroy()
self.Destroyed = true
end
function oneLineState.new(ChatWindow, ChatBar, ChatSettings)
local obj = {}
setmetatable(obj, oneLineState)
obj.Destroyed = false
obj.ChatWindow = ChatWindow
obj.ChatBar = ChatBar
obj.ChatSettings = ChatSettings
obj.TextBox = ChatBar:GetTextBox()
obj.MessageModeLabel = ChatBar:GetMessageModeTextLabel()
obj.Prefix = ""
return obj
end
local function ProcessMessage(message, ChatWindow, ChatBar, ChatSettings)
return oneLineState.new(ChatWindow, ChatBar, ChatSettings)
end
return {
[util.KEY_COMMAND_PROCESSOR_TYPE] = util.IN_PROGRESS_MESSAGE_PROCESSOR,
[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage
}

如前所述,一旦傳送了訊息,任何自訂狀態都將被移除,聊天將恢復正常。如果需要在傳送消息前重設特定狀態,狀態可以用 ChatBar:ResetCustomState() 重設。請注意,這將從聊天欄的文字框中移除焦點。

訊息創作者模組

客戶端組件中可以使用的另一種模組類型是 訊息創作者模組 。這種類型的模組用於在聊天窗口中創建顯示訊息的 GUI 元素。每種類型的訊息創作者定義了新的訊息輸入,因此不同類型的訊息可以使用不同的格式來創建。此外,使用者介面元素可以這樣添加到訊息顯示,這讓圖像、按鈕和其他內容可以加入。

這些模組需要在多個不同位置進行設置。對於每種訊息輸入,必須在 MessageCreatorModules 內有一個 ModuleScript。此外, 聊天標籤 ModuleScript 需要編輯以包含新的訊息輸入。最後,模組只會在聊天伺服器的一個組件創建新訊息時使用指定的訊息輸入時使用。

下面的例子將通過製作每 5 秒說出時間的機器人,傳送的訊息會獲得紅色背景。

首啟動, 聊天標籤 ModuleScript 添加一個新類型的訊息欄位。


-- 聊天常態
local module = {}
---[[ 訊息類型 ]]
module.MessageTypeDefault = "Message"
module.MessageTypeSystem = "System"
module.MessageTypeMeCommand = "MeCommand"
module.MessageTypeWelcome = "Welcome"
module.MessageTypeSetCore = "SetCore"
module.MessageTypeWhisper = "Whisper"
module.MessageTypeTime = "Time"
module.MajorVersion = 0
module.MinorVersion = 2
return module

機器人本身在服務伺服器上創建了新的 聊天模組 。請注意,過濾功能用於將新訊息類型添加到機器人所傳送的訊息。


-- 新模組腳本將放置在聊天模組中
local Chat = game:GetService("Chat")
local ReplicatedModules = Chat:WaitForChild("ClientChatModules")
local ChatConstants = require(ReplicatedModules:WaitForChild("ChatConstants"))
local function Run(ChatService)
local timeBot = ChatService:AddSpeaker("TimeBot")
timeBot:JoinChannel("All")
local function addMessageType(speaker, messageObject, channelName)
if speaker == "TimeBot" then
messageObject.MessageType = ChatConstants.MessageTypeTime
end
end
ChatService:RegisterFilterMessageFunction("TimeBotFilter", addMessageType)
task.spawn(function()
while task.wait(5) do
timeBot:SayMessage("The current time is: " .. os.time(), "All", {})
end
end)
end
return Run

最後,必須建立一個訊息創作者模組。此模組必須返回兩個元素的辭典:訊息類型,使用 KEY_MESSAGE_TYPE 索引,以及在創建訊息GUI元素時呼叫的功能,使用 KEY_CREATOR_FUNCTION 索引。

KEY_CREATOR_FUNCTION 儲存的功能需要返回包含多個組件的字典。首先,它需要包含 FrameTextLabel ,這些將在聊天窗口中顯示。這些可以使用 util:CreateBaseMessage() 函數創建。辭典也需要包含一個函數來運行,如果訊息文字更新。當訊息第一次出現在客戶端時,訊息正在處理和過濾時,它們會有空白的暫時文字,因此這類訊息對象需要處理當它們收到更新呼叫時發生的事情。接下來,辭典需要包含一個函數來確定框架的高度。此功能經常呼叫 util:GetMessageHeight() 功能。最後,辭典需要包含幾個功能來定義元素在窗口消失時應該消失的方式(此功能的實用函數是 util:CreateFadeFunctions())。


-- 新模組腳本將包含在訊息創作者模組中
local messageCreatorModules = script.Parent
local util = require(messageCreatorModules:WaitForChild("Util"))
local clientChatModules = messageCreatorModules.Parent
local ChatSettings = require(clientChatModules:WaitForChild("ChatSettings"))
local ChatConstants = require(clientChatModules:WaitForChild("ChatConstants"))
local function CreateMessageLabel(messageData, channelName)
-- 創建框架和文字標籤的 GUI 對象來保存訊息
local BaseFrame, BaseMessage = util:CreateBaseMessage("", ChatSettings.DefaultFont, ChatSettings.ChatWindowTextSize, ChatSettings.DefaultMessageColor)
-- 將框架的背景變更為紅色
BaseFrame.BackgroundColor3 = Color3.new(1,0,0)
BaseFrame.BackgroundTransparency = 0
-- 處理更新暫時填充訊息文字
local function UpdateTextFunction(messageObject)
if messageObject.IsFiltered then
BaseMessage.Text = messageObject.Message
end
end
UpdateTextFunction(messageData)
-- 使用 util 函數來確定框架的高度
local function GetHeightFunction(xSize)
return util:GetMessageHeight(BaseMessage, BaseFrame, xSize)
end
-- 創建在聊天窗口消失時呼叫的淡化功能
local FadeParameters = {}
FadeParameters[BaseMessage] = {
TextTransparency = {FadedIn = 0, FadedOut = 1},
TextStrokeTransparency = {FadedIn = 0.75, FadedOut = 1}
}
local FadeInFunction, FadeOutFunction, UpdateAnimFunction = util:CreateFadeFunctions(FadeParameters)
-- 返回定義訊息標籤的辭典
return {
[util.KEY_BASE_FRAME] = BaseFrame,
[util.KEY_BASE_MESSAGE] = BaseMessage,
[util.KEY_UPDATE_TEXT_FUNC] = UpdateTextFunction,
[util.KEY_GET_HEIGHT] = GetHeightFunction,
[util.KEY_FADE_IN] = FadeInFunction,
[util.KEY_FADE_OUT] = FadeOutFunction,
[util.KEY_UPDATE_ANIMATION] = UpdateAnimFunction
}
end
return {
[util.KEY_MESSAGE_TYPE] = ChatConstants.MessageTypeTime,
[util.KEY_CREATOR_FUNCTION] = CreateMessageLabel
}