传统聊天系统

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

层级

传统聊天系统使用 客户端-服务器模型 。 服务器端聊天模块组件 聊天채널聊天演讲者 管理由服务器负责处理,而客户端负责输入和显示消息。 客户端与服务器之间的通信由 1> Class.RemoteEvent|RemoteEvents1> 自动

Class.Chat 机器服务本身是聊天系统的必需存储单位:当 Roblox 位置加载(在客户端或 Studio 运行或玩游戏)时,以下组件将自动加载到 Chat 服务,如果 Chat.LoadDefaultChat 是真实的。

  • 聊天模块 — 此 Folder 是由 聊天服务运行器 所需的模块的收藏。 所有内容都需要脚本,并且用于在服务器上创建自定义行为。
  • ClientChatModule — 此文件夹包含 ChatScript 所需的各种 ModuleScripts
    • 命令模块 — 包含用于实现客户端聊天命令的模块。
    • 消息创建模块 — 包含用于处理和格式化消息的模块。
    • 聊天常量 — 包含服务器和客户端共享的常量。
    • 聊天设置 — 存储各种设置来配置不同的聊天窗口。
  • 聊天本地化 — 数据结构,存储文本翻译。
  • ChatServiceRunner — 此 Script 运行聊天室服务器部分。 一般来说,这不需要修改来创建自定义聊天行为和功能。
  • 泡泡聊天 — 显示用户聊天消息在他们的游戏虚拟形象上(如果启用)。
  • ChatScript — 此 LocalScript 运行客户端聊天组件。 与 ChatServiceRunner 一样,此操作不应该需要修改来自聊天的内容。 当游戏运行时,它会自动复制到 StarterPlayerScripts

修改聊天系统

要修改或自定义传统聊天系统,您必须首先复制上层的树结构。

  1. Explorer 窗口中,找到 TextChatService 。然后,在 属性 窗口中,将 1> ChatVersion1> 属性设置为 4> LegacyChatService4> .

  2. 使用 播放 按钮 ( F5 ) 运行体验。

  3. 选择并复制 ( CtrlCC ) 添加到 2> Class.Chat2> 的对象。

  4. 使用 停止 按钮(ShiftF5)停止体验。

  5. 选择 Chat贴入到 (Ctrl 0> Shift0> 2> V2> 或 5> ⌘5> 7> Shif聊天7> 9> V9> ) 复制的对象 (它们必须是父对于

  6. 确保 Chat.LoadDefaultChat 已启用。

聊天工作流程

在制作聊天模块自定义聊天时,重要的是要了解聊天消息通过工作流程。 与发送文本消息一起,聊天系统中构建了多个命令,因此每个消息都必须检查,以确保它们是否需要解释为命令或只是文本消信息。 即使是文本消息也可以在过程中修改和过滤。

当用户在聊天输入中集中,输入角色后,客户端上 immediately进行几个检查。如果角色是 Esc ,输入框会关闭,并且没有任何操作。如果角色是 频道入

聊天的客户端上,有两种处理器:进行中和已完成。前者在每个角色被打字后评估,而后者仅在用户完成输入并按<a href=\"#输入\">输入</a>后才会评估。

当用户完成输入并按“输入”时,其输入通过多个命令处理器发送。如果进行中命令发出了自定义聊天状态,聊天检查状态来确认是否要执行最终命令,并确认是否要继续发送消息。如果允许发送消息

一旦消息到达服务器,它通过另一系列命令处理器。 就像客户端上的完成处理器一样,如果这些处理器返回真,那么消息就停止执行。 否则,消息通过一系列过滤器(包括默认 Roblox 聊天过滤器)传递给所有频道和适当的发言人。 完成后,消息发送到所有频道和适当的发言人。

服务器模块

放入 聊天模块 的模块可以用于各种目的。 这些模块可以用于管理聊天频道和音频、添加过滤器和命令功能、运行聊天机器人或其他需要处理在服务器上的任何内容。 要与聊天系统交互,每个模块都通过一个 聊天服务 对象传递。

ChatServiceRunner 启动时,它需要在 ChatModule 内的每个模块。它期望每个模块都会返回一个函数,当它然后调用每个模块,通过它的 ChatService 对象传递给每个模块。无论模块的目的是什么(运行一个机器人、添加过滤器功能等),它都需要跟随此形式来工作。

示例模块框架

local function Run(ChatService)
-- 代码放在这里
end
return Run

添加频道

一个最简单的事情一个 聊天模块 可以做的是管理 频道 。 频道对象可以通过 AddChannel() 方法 来创建 1>聊天服务1> 中的会话成员(例如其属性和函数)。 当引


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 被静音或解除静音时。 例如,此模块将创建一个名为 2>MyChannel2> 的频道。 每


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

命令函数

另一个强大的事件,ChatModule 可以执行的是聊天 命令 。当发送消息到服务器时,聊天会通过

命令功能通常用于实现 管理员命令,这些是文本命令, которые某些用户可以使用来操作聊天中所述的特定文本说明的状态。

在此示例中, 聊天模块 用于创建一个Part,如果用户在聊天中输入了/part。注意,该函数将返回 true 如果部分已创建,这将阻止消息继续显示。如果未创建部分,该函数需要返回 false 以便系统能够继续运行。


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

ChatChannels 和 ChatService 自身都可以有聊天命令。 ChatService 命令处理器 将在发送到服务器的每个消息时运行,而 channel 命令处理器只会运行,如果消息发送到指定的频道。

过滤器功能

不受 命令函数 阻止的消息会通过所有注册在 ChatService 和相关频道的过滤功能。 每个过滤功能都会通过 通话服务 和相关频道注册的所有过滤器。 对过滤器对象的任何更改都不会持续。 每个过滤器功能都会显示更新的消信息。 请注意,过滤器功能不需要返回值。

在此示例中,注册了一个简单的过滤器函数,以便每个消息都以下大小写。


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

客户端模块

放入 ClientChatModule 中的模块可以用于为客户端提供自定义行为。这些模块分为两个不同的文件夹:命令模块消息创建器模块

命令模块

命令模块 工作很像注册在服务器上的命令函数的模块。 这些模块定义会在用户输入文本后发射的函信息。 文本可以被读取,命令可以让消息通过服务器发送或停止进度。 评论在

在两种类型的命令中,模块必须返回一个包含命令所使用类型的处理器和调用处理器时执行的函数的字典,例如一个 完成的消息处理器 应该采用以下形式:


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
}

注意,KEY_COMMAND_PROCESSOR_TYPE 枚举是在 命令模块 内的 ModuleScript 中定义的。

已完成的消息命令

完成的消息命令 在用户完成输入并按输入 时评论。处理器的函数通过 聊天消息 对象传递,客户服务器的 0>聊天窗口0> 和 3>聊天设置 3> 表。如果

例如,以下处理器将在用户输入命令 /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 Chat系统检查用户是否输入了 /whisper 或 /whisper ,并将完成的消息发送给仅适当用户。

自定义状态应该包含以下功能:

  • TextUpdated() — 调用输入框中的文本更改时。
  • GetMessage() — 在用户完成输入信息后调用 — 按 输入 。 此函数期望返回一个字符串。
  • ProcessCompletedMessage() — 调用作为处理消息的处理器。一个自定义状态处理器总是会在完成处理器的消息后发射。 像其他处理器一样,此函数总是返回 true 如果消息不再发送,否则返回 false。
  • 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() 来重置。 请注意,这将从聊天栏的文本框中移除焦点。

消息创建模块

客户端组件中使用的另一个类型的模块是一个 消息创建器 模块。这种模块是用于在聊天窗口中显示消信息的图形用户界面元素的创建器。每种模块都定义一个新的消息输入,因此不同类型的消息创建器可以用不同的格式创建图像、按钮和更多。此外,图形用户界面元素可以添加到显示消息的方式,从

这些模块需要在多个不同的位置设置。 对于每个消息输入,必须在 ModuleScript 内有一个 Class.ModuleScript 。 还需要, 聊天创建器模块 内的 2>ChatConstructModule2> 必须被编辑才能包含新的消息输入输入。 最后,模块仅在服务器组件的聊天创

下面的例子将通过使用每 5 秒发送一次时间的机器人,以及使用红色背景发送的消息。

首开始, ChatCommands 需要为新类型的信息添加一个字段。


-- 聊天常量
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 的函数需要返回一个字典,其中包含零件。首先,它需要包含一个 Frame 和一个 TextLabel ,这将在聊天窗


-- 新ModuleScript 将包含在MessageCreatorModule 中
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)
-- 创建框架和 TextLabel 的 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
}