Roblox commands V2

Hey developers! I am going to share some information and controls/commands of the roblox chat.
Commands we are talking today are:
/whisper, /mute, /unmute, /whisper, /version, /me and friend join notifier

You may view version I of this article which talks about commands such as /cls, /team, /console and how roblox chat automatically detects spam and vulgar language here:
Roblox chat commands version I

Commands:

/version
local util = require(script.Parent:WaitForChild("Util"))
local ChatConstants = require(script.Parent.Parent:WaitForChild("ChatConstants"))

local function ProcessMessage(message, ChatWindow, _)
	if string.sub(message, 1,  8):lower() == "/version" or string.sub(message, 1, 9):lower() == "/version " then
		util:SendSystemMessageToSelf(
			string.format("This game is running chat version [%d.%d.%s].",
				ChatConstants.MajorVersion,
				ChatConstants.MinorVersion,
				ChatConstants.BuildVersion),
			ChatWindow:GetCurrentChannel(),
			{})
		return true
	end
	return false
end

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

local PlayersService = game:GetService("Players")

local ChatLocalization = nil
pcall(function() ChatLocalization = require(game:GetService("Chat").ClientChatModules.ChatLocalization) end)

local LocalPlayer = PlayersService.LocalPlayer
while LocalPlayer == nil do
	PlayersService.ChildAdded:wait()
	LocalPlayer = PlayersService.LocalPlayer
end

local whisperStateMethods = {}
whisperStateMethods.__index = whisperStateMethods

local WhisperCustomState = {}

function whisperStateMethods:TrimWhisperCommand(text)
	if string.sub(text, 1, 3):lower() == "/w " then
		return string.sub(text, 4)
	elseif string.sub(text, 1, 9):lower() == "/whisper " then
		return string.sub(text, 10)
 	end
	return nil
end

function whisperStateMethods:TrimWhiteSpace(text)
	local newText = string.gsub(text, "%s+", "")
	local wasWhitespaceTrimmed = text[#text] == " "
	return newText, wasWhitespaceTrimmed
end

function whisperStateMethods:ShouldAutoCompleteNames()
	if ChatSettings.WhisperCommandAutoCompletePlayerNames ~= nil then
		return ChatSettings.WhisperCommandAutoCompletePlayerNames
	end
	return true
end

function whisperStateMethods:GetWhisperingPlayer(enteredText)
	enteredText = enteredText:lower()
	local trimmedText = self:TrimWhisperCommand(enteredText)
	if trimmedText then
		local possiblePlayerName, whitespaceTrimmed = self:TrimWhiteSpace(trimmedText)
		local possibleUserNameMatches = {}
		local possibleDisplayNameMatches = {}
		local players = PlayersService:GetPlayers()
		for i = 1, #players do
			if players[i] ~= LocalPlayer then
				local lowerPlayerName = players[i].Name:lower()
				if string.sub(lowerPlayerName, 1, string.len(possiblePlayerName)) == possiblePlayerName then
					possibleUserNameMatches[players[i]] = players[i].Name:lower()
				end

				if ChatSettings.WhisperByDisplayName then
					local lowerDisplayName = players[i].DisplayName:lower()
					if string.sub(lowerDisplayName, 1, string.len(possiblePlayerName)) == possiblePlayerName then
						possibleDisplayNameMatches[players[i]] = lowerDisplayName
					end
				end
			end
		end

		local matchCount = 0
		local lastMatch = nil
		local lastMatchName = nil
		for player, playerName in pairs(possibleUserNameMatches) do
			matchCount = matchCount + 1
			lastMatch = player
			lastMatchName = playerName
			if playerName == possiblePlayerName and whitespaceTrimmed then
				return player
			end
		end

		if ChatSettings.WhisperByDisplayName then
			for player, playerName in pairs(possibleDisplayNameMatches) do
				matchCount = matchCount + 1
				lastMatch = player
				lastMatchName = playerName
			end
		end

		if matchCount == 1 then
			if self:ShouldAutoCompleteNames() then
				return lastMatch
			elseif lastMatchName == possiblePlayerName then
				return lastMatch
			end
		end
	end
	return nil
end

function whisperStateMethods:GetWhisperChanneNameColor()
	if self.ChatSettings.WhisperChannelNameColor then
		return self.ChatSettings.WhisperChannelNameColor
	end
	return Color3.fromRGB(102, 14, 102)
end

function whisperStateMethods:EnterWhisperState(player)
	self.PlayerNameEntered = true
	self.PlayerName = player.Name
	self.PlayerDisplayName = player.DisplayName

	self.MessageModeButton.Size = UDim2.new(0, 1000, 1, 0)

	local messageModeString

	if ChatSettings.PlayerDisplayNamesEnabled and ChatSettings.WhisperByDisplayName then
		messageModeString = string.format("[To %s]", player.DisplayName)
	else
		messageModeString = string.format("[To %s]", player.Name)
	end

	if ChatLocalization.tryLocalize then
		messageModeString = ChatLocalization:tryLocalize(messageModeString)
	end
	self.MessageModeButton.Text = messageModeString

	self.MessageModeButton.TextColor3 = self:GetWhisperChanneNameColor()

	local xSize = math.ceil(self.MessageModeButton.TextBounds.X)
	self.MessageModeButton.Size = UDim2.new(0, xSize, 1, 0)
	self.TextBox.Size = UDim2.new(1, -xSize, 1, 0)
	self.TextBox.Position = UDim2.new(0, xSize, 0, 0)
	self.TextBox.Text = " "
end

function whisperStateMethods:TextUpdated()
	local newText = self.TextBox.Text
	if not self.PlayerNameEntered then
		local player = self:GetWhisperingPlayer(newText)
		if player then
			self:EnterWhisperState(player)
		end
	else
		if newText == "" then
			self.MessageModeButton.Text = ""
			self.MessageModeButton.Size = UDim2.new(0, 0, 0, 0)
			self.TextBox.Size = UDim2.new(1, 0, 1, 0)
			self.TextBox.Position = UDim2.new(0, 0, 0, 0)
			self.TextBox.Text = ""
			---Implement this when setting cursor positon is a thing.
			---self.TextBox.Text = self.OriginalText .. " " .. self.PlayerName
			self.PlayerNameEntered = false
			---Temporary until setting cursor position...
			self.ChatBar:ResetCustomState()
			self.ChatBar:CaptureFocus()
		end
	end
end

function whisperStateMethods:GetMessage()
	if self.PlayerNameEntered then
		return "/w " ..self.PlayerName.. " " ..self.TextBox.Text
	end
	return self.TextBox.Text
end

function whisperStateMethods:ProcessCompletedMessage()
	return false
end

function whisperStateMethods:Destroy()
	self.MessageModeConnection:disconnect()
	self.Destroyed = true
end

function WhisperCustomState.new(ChatWindow, ChatBar, ChatSettings, player)
	local obj = setmetatable({}, whisperStateMethods)
	obj.Destroyed = false
	obj.ChatWindow = ChatWindow
	obj.ChatBar = ChatBar
	obj.ChatSettings = ChatSettings
	obj.TextBox = ChatBar:GetTextBox()
	obj.MessageModeButton = ChatBar:GetMessageModeTextButton()
	obj.OriginalWhisperText = ""
	obj.PlayerNameEntered = false

	obj.MessageModeConnection = obj.MessageModeButton.MouseButton1Click:connect(function()
		local chatBarText = obj.TextBox.Text
		if string.sub(chatBarText, 1, 1) == " " then
			chatBarText = string.sub(chatBarText, 2)
		end
		obj.ChatBar:ResetCustomState()
		obj.ChatBar:SetTextBoxText(chatBarText)
		obj.ChatBar:CaptureFocus()
	end)

	if player then
		obj:EnterWhisperState(player)
	else
		obj:TextUpdated()
	end

	return obj
end

function ProcessMessage(message, ChatWindow, ChatBar, ChatSettings)
	if string.sub(message, 1, 3):lower() == "/w " or	string.sub(message, 1, 9):lower() == "/whisper " then
		return WhisperCustomState.new(ChatWindow, ChatBar, ChatSettings)
	end
	return nil
end

function CreateCustomState(player, ChatWindow, ChatBar, ChatSettings)
	return WhisperCustomState.new(ChatWindow, ChatBar, ChatSettings, player)
end

return {
	[util.KEY_COMMAND_PROCESSOR_TYPE] = util.IN_PROGRESS_MESSAGE_PROCESSOR,
	[util.KEY_PROCESSOR_FUNCTION] = ProcessMessage,
	CustomStateCreator = CreateCustomState,
}
/mute & /unmute

Command: /mute


local Chat = game:GetService("Chat")
local ReplicatedModules = Chat:WaitForChild("ClientChatModules")
local ChatModules = Chat:WaitForChild("ChatModules")
local ChatConstants = require(ReplicatedModules:WaitForChild("ChatConstants"))
local ChatSettings = require(ReplicatedModules:WaitForChild("ChatSettings"))
local DisplayNameHelpers = require(ChatModules.Utility.DisplayNameHelpers)

local ChatLocalization = nil
pcall(function() ChatLocalization = require(game:GetService("Chat").ClientChatModules.ChatLocalization) end)
if ChatLocalization == nil then ChatLocalization = {} end
if not ChatLocalization.FormatMessageToSend or not ChatLocalization.LocalizeFormattedMessage then
	function ChatLocalization:FormatMessageToSend(key,default) return default end
end

local errorTextColor = ChatSettings.ErrorMessageTextColor or Color3.fromRGB(245, 50, 50)
local errorExtraData = {ChatColor = errorTextColor}

local function Run(ChatService)

	local function GetSpeakerNameFromMessage(message)
		local speakerName = message
		if string.sub(message, 1, 1) == "\"" then
			local pos = string.find(message, "\"", 2)
			if pos then
				speakerName = string.sub(message, 2, pos - 1)
			end
		else
			local first = string.match(message, "^[^%s]+")
			if first then
				speakerName = first
			end
		end
		return speakerName
	end

	local function DoMuteCommand(speakerName, message, channel)
		local muteSpeakerInputName = GetSpeakerNameFromMessage(message)
		local speaker = ChatService:GetSpeaker(speakerName)

		if speaker then
			local muteSpeakerName, muteSpeakerError

			--Get the target user's UserName from the input (which could be userName or displayName)
			if ChatSettings.PlayerDisplayNamesEnabled then
				muteSpeakerName, muteSpeakerError = DisplayNameHelpers.getUserNameFromChattedName(muteSpeakerInputName, speakerName, speaker:GetNameForDisplay())
			else
				muteSpeakerName, muteSpeakerError = DisplayNameHelpers.getUserNameFromChattedName(muteSpeakerInputName, speakerName, nil)
			end

			local muteSpeaker = ChatService:GetSpeaker(muteSpeakerName)

			if muteSpeakerError == DisplayNameHelpers.CommandErrorCodes.ChattingToSelf then
				speaker:SendSystemMessage(ChatLocalization:FormatMessageToSend("GameChat_DoMuteCommand_CannotMuteSelf", "You cannot mute yourself."), channel, errorExtraData)

			elseif muteSpeakerError == DisplayNameHelpers.CommandErrorCodes.NoMatches then
				local msg = ChatLocalization:FormatMessageToSend(
					"GameChat_MuteSpeaker_SpeakerDoesNotExist",
					string.format("Speaker '%s' does not exist.", tostring(muteSpeakerInputName)),
					"RBX_NAME",
					tostring(muteSpeakerName))
				speaker:SendSystemMessage(msg, channel, errorExtraData)

			elseif muteSpeakerError == DisplayNameHelpers.CommandErrorCodes.MultipleMatches then
				local matchingUsersText = DisplayNameHelpers.getUsersWithDisplayNameString(muteSpeakerInputName, speakerName)
				speaker:SendSystemMessage(ChatLocalization:FormatMessageToSend("InGame.Chat.Response.DisplayNameMultipleMatches", "Warning: The following users have this display name: "),  channel, errorExtraData)

				--Send a second message with a list of names so that the localization formatter doesn't prune it
				speaker:SendSystemMessage(matchingUsersText,  channel, errorExtraData)

			elseif muteSpeaker then
				speaker:AddMutedSpeaker(muteSpeaker.Name)

				local muteSpeakerDisplayName = muteSpeakerName

				if ChatSettings.PlayerDisplayNamesEnabled then
					muteSpeakerDisplayName = muteSpeaker:GetNameForDisplay()
				end

				local msg = ChatLocalization:FormatMessageToSend("GameChat_ChatMain_SpeakerHasBeenMuted",
					string.format("Speaker '%s' has been muted.", muteSpeakerDisplayName),
					"RBX_NAME",
					muteSpeakerDisplayName)
				speaker:SendSystemMessage(msg, channel)
			end
		end
	end

	local function DoUnmuteCommand(speakerName, message, channel)
		local unmuteSpeakerInputName = GetSpeakerNameFromMessage(message)
		local speaker = ChatService:GetSpeaker(speakerName)

		if speaker then
			local unmuteSpeakerName, unmuteSpeakerError

			--Get the target user's UserName from the input (which could be userName or displayName)
			if ChatSettings.PlayerDisplayNamesEnabled then
				unmuteSpeakerName, unmuteSpeakerError = DisplayNameHelpers.getUserNameFromChattedName(unmuteSpeakerInputName, speakerName, speaker:GetNameForDisplay())
			else
				unmuteSpeakerName, unmuteSpeakerError = DisplayNameHelpers.getUserNameFromChattedName(unmuteSpeakerInputName, speakerName, nil)
			end

			local unmuteSpeaker = ChatService:GetSpeaker(unmuteSpeakerName)

			if unmuteSpeakerError == DisplayNameHelpers.CommandErrorCodes.ChattingToSelf then
				speaker:SendSystemMessage(ChatLocalization:FormatMessageToSend("GameChat_DoMuteCommand_CannotMuteSelf","You cannot mute yourself."), channel, errorExtraData)
				return

			elseif unmuteSpeakerError == DisplayNameHelpers.CommandErrorCodes.NoMatches then
				local msg = ChatLocalization:FormatMessageToSend("GameChat_MuteSpeaker_SpeakerDoesNotExist",
					string.format("Speaker '%s' does not exist.", tostring(unmuteSpeakerName)),
					"RBX_NAME",
					tostring(unmuteSpeakerName))
				speaker:SendSystemMessage(msg, channel, errorExtraData)
				return

			elseif unmuteSpeakerError == DisplayNameHelpers.CommandErrorCodes.MultipleMatches then --More than one DisplayName match
				local matchingUsersText = DisplayNameHelpers.getUsersWithDisplayNameString(unmuteSpeakerInputName, speakerName)
				speaker:SendSystemMessage(ChatLocalization:FormatMessageToSend("InGame.Chat.Response.DisplayNameMultipleMatches", "Warning: The following users have this display name: "),  channel, errorExtraData)

				--Send a second message with a list of names so that the localization formatter doesn't prune it
				speaker:SendSystemMessage(matchingUsersText,  channel, errorExtraData)
				return

			elseif unmuteSpeaker then
				speaker:RemoveMutedSpeaker(unmuteSpeaker.Name)
				local playerName = unmuteSpeakerName

				if ChatSettings.PlayerDisplayNamesEnabled then
					playerName = unmuteSpeaker:GetNameForDisplay()
				end

				local msg = ChatLocalization:FormatMessageToSend("GameChat_ChatMain_SpeakerHasBeenUnMuted",
					string.format("Speaker '%s' has been unmuted.", playerName),
					"RBX_NAME",
					playerName)
				speaker:SendSystemMessage(msg, channel)
				return

			end
		end
	end

	local function MuteCommandsFunction(fromSpeaker, message, channel)
		local processedCommand = false

		if string.sub(message, 1, 6):lower() == "/mute " then
			DoMuteCommand(fromSpeaker, string.sub(message, 7), channel)
			processedCommand = true
		elseif string.sub(message, 1, 8):lower() == "/unmute " then
			DoUnmuteCommand(fromSpeaker, string.sub(message, 9), channel)
			processedCommand = true
		end
		return processedCommand

	end

	ChatService:RegisterProcessCommandsFunction("mute_commands", MuteCommandsFunction, ChatConstants.StandardPriority)
end

return Run
Friend Join notifier

Friend Join notifier:

local Chat = game:GetService("Chat")
local Players = game:GetService("Players")
local FriendService = game:GetService("FriendService")

local ReplicatedModules = Chat:WaitForChild("ClientChatModules")
local ChatSettings = require(ReplicatedModules:WaitForChild("ChatSettings"))
local ChatConstants = require(ReplicatedModules:WaitForChild("ChatConstants"))

local ChatLocalization = nil
pcall(function() ChatLocalization = require(game:GetService("Chat").ClientChatModules.ChatLocalization) end)
if ChatLocalization == nil then ChatLocalization = {} end
if not ChatLocalization.FormatMessageToSend or not ChatLocalization.LocalizeFormattedMessage then
	function ChatLocalization:FormatMessageToSend(key,default) return default end
end

local FriendMessageTextColor = Color3.fromRGB(255, 255, 255)
local FriendMessageExtraData = {ChatColor = FriendMessageTextColor}

local function Run(ChatService)

	local function ShowFriendJoinNotification()
		if ChatSettings.ShowFriendJoinNotification ~= nil then
			return ChatSettings.ShowFriendJoinNotification
		end
		return false
	end

	local function SendFriendJoinNotification(player, joinedFriend)
		local speakerObj = ChatService:GetSpeaker(player.Name)
		if speakerObj then
			local joinedFriendName = joinedFriend.Name
			if ChatSettings.PlayerDisplayNamesEnabled then
				joinedFriendName = joinedFriend.DisplayName
			end

			local msg = ChatLocalization:FormatMessageToSend("GameChat_FriendChatNotifier_JoinMessage",
				string.format("Your friend %s has joined the game.", joinedFriendName),
				"RBX_NAME",
				joinedFriendName)
			speakerObj:SendSystemMessage(msg, "System", FriendMessageExtraData)
		end
	end

	local function TrySendFriendNotification(player, joinedPlayer)
		if player ~= joinedPlayer then
			coroutine.wrap(function()
				if player:IsFriendsWith(joinedPlayer.UserId) then
					SendFriendJoinNotification(player, joinedPlayer)
				end
			end)()
		end
	end

	if ShowFriendJoinNotification() then
		Players.PlayerAdded:connect(function(player)
			local possibleFriends = Players:GetPlayers()
			for i = 1, #possibleFriends do
				TrySendFriendNotification(possibleFriends[i], player)
			end
		end)
	end
end

return Run