Hierarquia
O sistema de chat de legado usa o modelo cliente-servidor. Os módulos de chat do lado do servidor são compostos por ChatChannel e ChatSpeaker. A gestão do módulo de chat do lado do cliente é feita pelo 1> ChatService1> no servidor, enquanto a interface do cliente é responsável pela entrada e pela exibição de mensagens. A comunica
O próprio serviço de motor Chat é a unidade de armazenamento essencial para o sistema de chat: quando um local Roblox é carregado (seja no cliente ou no Studio ao executar ou jogar), os seguintes componentes são carregados automaticamente no serviço Chat se Chat.LoadDefaultChat for verdadeiro.
- ChatModuleScripts — Este Folder é uma coleção de módulos que são requisitados pelo ChatServiceRunner . Todos os conteúdos deste pasta são requisitados pelo script e são usados para criar comportamento personalizado no servidor.
- ClientChatModules — Este pasta contém vários ModuleScripts necessários pelo ChatScript .
- Modulos de Comando — Contém módulos usados para implementar comandos de chat do lado do cliente.
- MessageCreatorModules — Contém módulos usados para lidar e formatar mensagens.
- ChatCommands — Contém constantes compartilhadas pelo servidor e pelo cliente.
- ChatSettings — Armazena várias configurações para configurar diferentes aspectos da Janela de Bate-papo.
- Localização de Chat — Estrutura de dados que armazena traduções de texto.
- ChatServiceRunner — Este Script executa o componente do servidor do chat. Em geral, isso não precisa ser modificado para criar comportamento e funcionalidade de chat personalizados.
- BubbleChat — Exibe mensagens de chat do usuário acima de seu avatar (se habilitado).
- ChatScript — Este LocalScript executa o cliente do componente do chat. Como o ChatServiceRunner, isso não deve ser modificado para personalizar o chat. Quando o jogo executa isso, ele é clonado automaticamente para o StarterPlayerScripts.
Modificando o Sistema de Chat
Para modificar ou personalizar o sistema de chat de legado, você deve primeiro fazer uma cópia da hierarquia acima.
Na janela Explorer, localize TextChatService. Em seguida, na janela Propriedades, configure a propriedade 2>ChatVersion2> para 5>LegacyChatService5>.
Execute a experiência usando o botão Jogar ( F5 ).
Selecione e copie ( CtrlC ou ⌘C ) os objetos que são adicionados ao 2> Class.chat/conversa2> .
Pare a experiência usando o botão Parar ( ShiftF5 ).
Certifique-se de que Chat.LoadDefaultChat está Ativado.
Fluxo de Chat
Antes de fazer módulos para personalizar o chat, é importante entender o fluxo de trabalho que uma mensagem de chat passa. Junto com enviar mensagens de texto, há vários comandos construídos no sistema de chat, então cada mensagem precisa ser verificada para ver se ela precisa ser interpretada como um comando ou apenas uma mensagem de texto. Mesmo as mensagens de texto podem ser modificadas e filtradas no processo.
Depois que um usuário tem foco na entrada de chat e insere um personagem, vários testes são feitos imediatamente no cliente. Se o personagem for Esc, a caixa de entrada fecha e nenhuma ação será tomada. Se o
No lado do cliente do chat, existem dois tipos de processadores: em andamento e concluído. O primeiro avalia após cada personagem ter sido digito, enquanto o último avalia apenas quando o usuário terminar de digitar e pressionar Enter.
Quando o usuário terminar de digitar e pressionar Enter o texto, sua entrada é enviada através de vários processadores de comando. Se uma ordem In-Progress for feita, o chat verifica o estado para ver se um comando final deve ser executado e se a mensagem deve continuar. Se a mensagem for permitida, ent
Uma vez que a mensagem chega ao servidor, ela passa por outro conjunto de processadores de comando. Como os concluídos processadores no cliente, se algum desses processadores retornar verdadeiro, então a mensagem para ser executada. Caso contrário, a mensagem é enviada para todos os canais e os oradores apropriados.
Módulos do Servidor
Módulos colocados em ChatModuleScripts podem ser usados para uma variedade de propósitos. Esses módulos podem ser usados para gerenciar canais de chat e oradores, adicionar filtros e funções de comando, executar bots de chat ou qualquer outra coisa que precisa ser tratada no servidor. Para interagir com o sistema de chat, cada módulo é passado um ObjetoChatService.
Quando o ChatServiceRunner é iniciado, ele requer que cada módulo dentro de ChatModule seja chamado. Ele espera que cada módulo retorne uma função como então chama cada um dos módulos em vez, passando seu objeto ChatService para cada função. Independentemente do que o módulo seja intencionado ( Executar um bot, adicionar uma função de filtro, etc), ele precisa seguir essa
Estrutura de Módulo de Exemplo
local function Run(ChatService)
-- Código vai aqui
end
return Run
Adicionando Canais
Uma das coisas mais simples que um ChatModule pode fazer é gerenciar canais. Objetos de canal podem ser criados com o método AddChannel() do 2>ChatService2>. Observe que o objeto de canal só precisa ser usado quando se refere a membros desse canal (como su
local function Run(ChatService)
local myChannel = ChatService:AddChannel("MyChannel")
end
return Run
Configuração de Canal Básica
Os canais têm várias propriedades que podem ser usadas para alterá-los levemente. Por exemplo, este módulo cria um canal e configura a Mensagem de Bem-Vindo e faz com que os usuários entrem automaticamente no canal quando eles entrarem na experiência.
local function Run(ChatService)
local myChannel = ChatService:AddChannel("MyChannel")
-- Defina a mensagem que é mostrada quando um usuário se junta ao canal
myChannel.WelcomeMessage = "Welcome to my channel!"
-- Causa os jogadores a entrar automaticamente no canal quando eles entram no jogo
myChannel.AutoJoin = true
end
return Run
Eventos de Canal
Canais têm vários eventos que podem ser subscritos. Esses eventos são disparados quando um ChatMessage é postado no canal, quando um ChatSpeaker sai ou entra, ou quando um MyChannel é silenciado ou não silenciado. Por exemplo, este módulo criará um canal com o nome 2> MyChannel2>. Sempre que um
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
Funções de Comando
Outra coisa poderosa que ChatModule pode fazer são chamadas de comandos . Quando uma mensagem é enviada para o servidor, a chat env
As funções de comando geralmente são usadas para implementar Comandos de Administração, que são comandos de texto que certos usuários podem usar para manipular o estado da experiência através de texto específico dito no chat.
Neste exemplo, um Modulo de Bate-papo é usado para criar um Part se um usuário digitar /part no chat. Observe que esta função retorna verdadeiro se uma parte for criada, o que impedirá que a mensagem progrida e nenhuma mensagem será exibida. Se uma parte não for criada, esta função precisa retornar falso para que a mensagem possa continuar
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
Tanto Canais de Chat e Serviço de Chat podem ter comandos de chat. O processador de comando ChatService será executado em cada mensagem enviada ao servidor, enquanto os comandos de canal só serão executados se a mensagem for enviada ao canal ao qual o comando está registrado.
Funções de Filtro
Mensagens que não são interrompidas por uma Função de Comando irão passar por todas as funções de filtro que estão registradas no ChatService e canais relevantes. Cada função de filtro é passada ao altofalante, Objetode mensagem e nome do canal. Qualquer alteração feita ao objeto de mensagem persistirá e cada função de filtro seguinte verá a mensagem atualizada. Nota que funções de filtro não precisam retornar um valor.
Neste exemplo, uma função simples de filtro está registrada para fazer qualquer mensagem aparecer em minúsculas.
local function Run(ChatService)
local function makeLowercase(sender, messageObject, channelName)
messageObject.Message = string.lower(messageObject.Message)
end
ChatService:RegisterFilterMessageFunction("makeLowercase", makeLowercase)
end
return Run
Módulos de Cliente
Módulos colocados em ClientChatModule podem ser usados para fazer comportamento personalizado para clientes. Esses módulos são divididos em duas pastas diferentes: Módulos de Comando e Módulos de Criador de Mensagens.
Módulos de Comando
Módulos de Comando trabalham muito semelhantes a módulos no servidor que registram Funções de Comando. Esses módulos definem funções que serão executadas depois que o usuário inserir no texto. Esse texto pode ser lido e a função pode ser ou
Em ambos os tipos de comandos, o módulo deve retornar um dicionário que diz qual tipo de processador o comando deve usar e qual função para executar quando o processador for chamado. Por exemplo, um processador de mensagem concluído deve tomar a forma:
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
}
Nota que o índice KEY_COMMAND_PROCESSOR_TYPE é definido no Util ModuleScript dentro da pasta 1>CommandModuleScript1>.
Comandos de Mensagem Concluídos
Comandos de Mensagem Concluídos são avaliados quando o usuário terminar de digitar e pressionar Enter. A função do processador é passada para o ObjetoChatMessage do cliente e a tabela 0> ChatSettings0>. Se a função retornar verdadeiro, então a mens
Por exemplo, o seguinte processador removerá a mensagem mais antiga no canal atual se o usuário entrar na ordem /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
}
Comandos de Progresso
Comandos em andamento são avaliados sempre que um usuário digita um personagem na entrada de chat. Por exemplo, o seguinte código toca um clique depois de cada pressione de tecla para fazer com que pareça que o usuário está digitando em um tipo de papel:
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
}
Comandos em andamento são frequentemente usados para fazer um estado personalizado para o chat enviar mensagens para usuários específicos em vez do canal atual. Por exemplo, os sistemas Whisper e Team Chat verificam se o usuário digitou /whisper ou /team respectivamente e envia a mensagem terminada para apenas os usuários apropriados.
Um estado personalizado é esperado para ser uma tabela com as seguintes funções:
- TextUpdated() — Chamado quando o texto na caixa de entrada muda.
- GetMessage() — Chamado depois que o usuário terminar de inserir a mensagem e pressionar Enter. Essa função é esperada para retornar uma string / cadeia / texto.
- ProcessCompletedMessage() — Chamado à medida que a mensagem está sendo processada. Um processador de estado personalizado sempre será chamado antes que os processadores de mensagem concluídos. Como outros processadores, essa função deve retornar verdadeiro se a mensagem não for mais enviada, caso contrário, deve retornar falso.
- Destroy() — Chamado depois que a mensagem for enviada. Deve ser usado para limpar qualquer coisa configurada pelo estado personalizado.
Para usar um estado personalizado, a função ProcessMessage() do módulo de comando deve retornar o estado. Um estado personalizado básico levaria a seguinte forma:
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
}
Uma das principais vantagens de usar um estado personalizado é que um módulo pode editar a barra de chat e seu conteúdo enquanto o usuário está digando tanto em termos de função quanto aparência, e depois pode facilmente redefinir depois (uma vez que uma mensagem é enviada, um estado personalizado é automaticamente removido e tudo é redefinido de
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
}
Como mencionado antes, uma vez que uma mensagem é enviada, qualquer estado personalizado é removido e o chat é restaurado ao normal. Se for necessário para redefinir um estado personalizado antes de enviar a mensagem, o estado pode ser redefinido com ChatBar:ResetCustomState() . Observe que isso removerá o foco da caixa de texto da barra de chat também.
Módulos de Criador de Mensagens
Outro tipo de módulo que pode ser usado no cliente é um módulo Criador de Mensagens . Este tipo de módulo é usado para criar os elementos da GUI na janela de chat para exibir a mensagem. Cada tipo de criador de mensagens define um novo digitarde mensagem, para que diferentes tipos de mensagens possam ser criados com diferentes formatações. Além disso, os elementos da GUI podem ser adicionados à janela de exibição para exibir as mens
Esses módulos requerem configuração em vários locais diferentes. Para cada digitarde mensagem, deve haver um ModuleScript dentro de MessageCreatorModuleScript . Além disso, o ChatCommands 1> Class.ModuleScript1> precisa ser editado para incluir o novo digitarde mensagem. Por fim, os módulos são usados apenas se um componente de chat do serv
O seguinte exemplo vai passar por fazer um bot que diz o tempo a cada 5 segundos, e a mensagem que é enviada tem um fundo vermelho.
Para iniciar, o ChatConstraints ModuleScript precisa adicionar um campo para o novo tipo de mensagem.
-- Constantes de Bate-papolocal module = {}--<-[[ Tipos de Mensagem ]]module.MessageTypeDefault = "Message"module.MessageTypeSystem = "System"module.MessageTypeMeCommand = "MeCommand"module.MessageTypeWelcome = "Welcome"module.MessageTypeSetCore = "SetCore"module.MessageTypeWhisper = "Whisper"module.MessageTypeTime = "Time"module.MajorVersion = 0module.MinorVersion = 2return module
O próprio bot é criado em um novo ChatModule no servidor. Observe que uma função de filtro é usada para adicionar o novo tipo de mensagem aos mensagens que o bot envia.
-- Novo Script de Módulo para ser colocado em ChatModule
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
Por último, um módulo de criação de mensagens deve ser feito. Este módulo deve retornar um dicionário com dois elementos: o tipo da mensagem, indexado com KEY_MESSAGE_TYPE e a função para chamar quando criar os elementos da GUI de mensagens, indexados com KEY_CREATOR_FUNCTION.
A função armazenada por KEY_CREATOR_FUNCTION precisa retornar um dicionário com vários componentes. Primeiro, ele precisa incluir um Frame e TextLabel que serão exibidos
-- novo ModuleScript para ser incluído em MessageCreatorModules
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)
-- Crie os objetos GUI para a Frame e TextLabel para armazenar a mensagem
local BaseFrame, BaseMessage = util:CreateBaseMessage("", ChatSettings.DefaultFont, ChatSettings.ChatWindowTextSize, ChatSettings.DefaultMessageColor)
-- Altere o fundo da Frame para vermelho
BaseFrame.BackgroundColor3 = Color3.new(1,0,0)
BaseFrame.BackgroundTransparency = 0
-- Manipular texto de mensagem de espaço reservado
local function UpdateTextFunction(messageObject)
if messageObject.IsFiltered then
BaseMessage.Text = messageObject.Message
end
end
UpdateTextFunction(messageData)
-- Use a função util para determinar a altura da janela
local function GetHeightFunction(xSize)
return util:GetMessageHeight(BaseMessage, BaseFrame, xSize)
end
-- Crie funções de desvanecimento que são chamadas quando a janela de chat desaparece
local FadeParameters = {}
FadeParameters[BaseMessage] = {
TextTransparency = {FadedIn = 0, FadedOut = 1},
TextStrokeTransparency = {FadedIn = 0.75, FadedOut = 1}
}
local FadeInFunction, FadeOutFunction, UpdateAnimFunction = util:CreateFadeFunctions(FadeParameters)
-- Retornar dicionário que define a etiqueta de etiqueta / rótulo
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
}