Skip to content

Instantly share code, notes, and snippets.

@Aerodos12
Created January 22, 2018 20:39
Show Gist options
  • Save Aerodos12/27feee176ec8cae3ae52694677f2bbc7 to your computer and use it in GitHub Desktop.
Save Aerodos12/27feee176ec8cae3ae52694677f2bbc7 to your computer and use it in GitHub Desktop.
New Chat System
-- // FileName: ChannelsBar.lua
-- // Written by: Xsitsu
-- // Description: Manages creating, destroying, and displaying ChannelTabs.
local module = {}
local PlayerGui = game:GetService("Players").LocalPlayer:WaitForChild("PlayerGui")
--////////////////////////////// Include
--//////////////////////////////////////
local Chat = game:GetService("Chat")
local clientChatModules = Chat:WaitForChild("ClientChatModules")
local modulesFolder = script.Parent
local moduleChannelsTab = require(modulesFolder:WaitForChild("ChannelsTab"))
local MessageSender = require(modulesFolder:WaitForChild("MessageSender"))
local ChatSettings = require(clientChatModules:WaitForChild("ChatSettings"))
local CurveUtil = require(modulesFolder:WaitForChild("CurveUtil"))
--////////////////////////////// Methods
--//////////////////////////////////////
local methods = {}
methods.__index = methods
function methods:CreateGuiObjects(targetParent)
local BaseFrame = Instance.new("Frame")
BaseFrame.Selectable = false
BaseFrame.Size = UDim2.new(1, 0, 1, 0)
BaseFrame.BackgroundTransparency = 1
BaseFrame.Parent = targetParent
local ScrollingBase = Instance.new("Frame")
ScrollingBase.Selectable = false
ScrollingBase.Name = "ScrollingBase"
ScrollingBase.BackgroundTransparency = 1
ScrollingBase.ClipsDescendants = true
ScrollingBase.Size = UDim2.new(1, 0, 1, 0)
ScrollingBase.Position = UDim2.new(0, 0, 0, 0)
ScrollingBase.Parent = BaseFrame
local ScrollerSizer = Instance.new("Frame")
ScrollerSizer.Selectable = false
ScrollerSizer.Name = "ScrollerSizer"
ScrollerSizer.BackgroundTransparency = 1
ScrollerSizer.Size = UDim2.new(1, 0, 1, 0)
ScrollerSizer.Position = UDim2.new(0, 0, 0, 0)
ScrollerSizer.Parent = ScrollingBase
local ScrollerFrame = Instance.new("Frame")
ScrollerFrame.Selectable = false
ScrollerFrame.Name = "ScrollerFrame"
ScrollerFrame.BackgroundTransparency = 1
ScrollerFrame.Size = UDim2.new(1, 0, 1, 0)
ScrollerFrame.Position = UDim2.new(0, 0, 0, 0)
ScrollerFrame.Parent = ScrollerSizer
local LeaveConfirmationFrameBase = Instance.new("Frame")
LeaveConfirmationFrameBase.Selectable = false
LeaveConfirmationFrameBase.Size = UDim2.new(1, 0, 1, 0)
LeaveConfirmationFrameBase.Position = UDim2.new(0, 0, 0, 0)
LeaveConfirmationFrameBase.ClipsDescendants = true
LeaveConfirmationFrameBase.BackgroundTransparency = 1
LeaveConfirmationFrameBase.Parent = BaseFrame
local LeaveConfirmationFrame = Instance.new("Frame")
LeaveConfirmationFrame.Selectable = false
LeaveConfirmationFrame.Name = "LeaveConfirmationFrame"
LeaveConfirmationFrame.Size = UDim2.new(1, 0, 1, 0)
LeaveConfirmationFrame.Position = UDim2.new(0, 0, 1, 0)
LeaveConfirmationFrame.BackgroundTransparency = 0.6
LeaveConfirmationFrame.BorderSizePixel = 0
LeaveConfirmationFrame.BackgroundColor3 = Color3.new(0, 0, 0)
LeaveConfirmationFrame.Parent = LeaveConfirmationFrameBase
local InputBlocker = Instance.new("TextButton")
InputBlocker.Selectable = false
InputBlocker.Size = UDim2.new(1, 0, 1, 0)
InputBlocker.BackgroundTransparency = 1
InputBlocker.Text = ""
InputBlocker.Parent = LeaveConfirmationFrame
local LeaveConfirmationButtonYes = Instance.new("TextButton")
LeaveConfirmationButtonYes.Selectable = false
LeaveConfirmationButtonYes.Size = UDim2.new(0.25, 0, 1, 0)
LeaveConfirmationButtonYes.BackgroundTransparency = 1
LeaveConfirmationButtonYes.Font = ChatSettings.DefaultFont
LeaveConfirmationButtonYes.TextSize = 18
LeaveConfirmationButtonYes.TextStrokeTransparency = 0.75
LeaveConfirmationButtonYes.Position = UDim2.new(0, 0, 0, 0)
LeaveConfirmationButtonYes.TextColor3 = Color3.new(0, 1, 0)
LeaveConfirmationButtonYes.Text = "Confirm"
LeaveConfirmationButtonYes.Parent = LeaveConfirmationFrame
local LeaveConfirmationButtonNo = LeaveConfirmationButtonYes:Clone()
LeaveConfirmationButtonNo.Parent = LeaveConfirmationFrame
LeaveConfirmationButtonNo.Position = UDim2.new(0.75, 0, 0, 0)
LeaveConfirmationButtonNo.TextColor3 = Color3.new(1, 0, 0)
LeaveConfirmationButtonNo.Text = "Cancel"
local LeaveConfirmationNotice = Instance.new("TextLabel")
LeaveConfirmationNotice.Selectable = false
LeaveConfirmationNotice.Size = UDim2.new(0.5, 0, 1, 0)
LeaveConfirmationNotice.Position = UDim2.new(0.25, 0, 0, 0)
LeaveConfirmationNotice.BackgroundTransparency = 1
LeaveConfirmationNotice.TextColor3 = Color3.new(1, 1, 1)
LeaveConfirmationNotice.TextStrokeTransparency = 0.75
LeaveConfirmationNotice.Text = "Leave channel <XX>?"
LeaveConfirmationNotice.Font = ChatSettings.DefaultFont
LeaveConfirmationNotice.TextSize = 18
LeaveConfirmationNotice.Parent = LeaveConfirmationFrame
local LeaveTarget = Instance.new("StringValue")
LeaveTarget.Name = "LeaveTarget"
LeaveTarget.Parent = LeaveConfirmationFrame
local outPos = LeaveConfirmationFrame.Position
LeaveConfirmationButtonYes.MouseButton1Click:connect(function()
MessageSender:SendMessage(string.format("/leave %s", LeaveTarget.Value), nil)
LeaveConfirmationFrame:TweenPosition(outPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.2, true)
end)
LeaveConfirmationButtonNo.MouseButton1Click:connect(function()
LeaveConfirmationFrame:TweenPosition(outPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.2, true)
end)
local scale = 0.7
local scaleOther = (1 - scale) / 2
local pageButtonImage = "rbxasset://textures/ui/Chat/TabArrowBackground.png"
local pageButtonArrowImage = "rbxasset://textures/ui/Chat/TabArrow.png"
--// ToDo: Remove these lines when the assets are put into trunk.
--// These grab unchanging versions hosted on the site, and not from the content folder.
pageButtonImage = "rbxassetid://471630199"
pageButtonArrowImage = "rbxassetid://471630112"
local PageLeftButton = Instance.new("ImageButton", BaseFrame)
PageLeftButton.Selectable = ChatSettings.GamepadNavigationEnabled
PageLeftButton.Name = "PageLeftButton"
PageLeftButton.SizeConstraint = Enum.SizeConstraint.RelativeYY
PageLeftButton.Size = UDim2.new(scale, 0, scale, 0)
PageLeftButton.BackgroundTransparency = 1
PageLeftButton.Position = UDim2.new(0, 4, scaleOther, 0)
PageLeftButton.Visible = false
PageLeftButton.Image = pageButtonImage
local ArrowLabel = Instance.new("ImageLabel", PageLeftButton)
ArrowLabel.Name = "ArrowLabel"
ArrowLabel.BackgroundTransparency = 1
ArrowLabel.Size = UDim2.new(0.4, 0, 0.4, 0)
ArrowLabel.Image = pageButtonArrowImage
local PageRightButtonPositionalHelper = Instance.new("Frame", BaseFrame)
PageRightButtonPositionalHelper.Selectable = false
PageRightButtonPositionalHelper.BackgroundTransparency = 1
PageRightButtonPositionalHelper.Name = "PositionalHelper"
PageRightButtonPositionalHelper.Size = PageLeftButton.Size
PageRightButtonPositionalHelper.SizeConstraint = PageLeftButton.SizeConstraint
PageRightButtonPositionalHelper.Position = UDim2.new(1, 0, scaleOther, 0)
local PageRightButton = PageLeftButton:Clone()
PageRightButton.Parent = PageRightButtonPositionalHelper
PageRightButton.Name = "PageRightButton"
PageRightButton.Size = UDim2.new(1, 0, 1, 0)
PageRightButton.SizeConstraint = Enum.SizeConstraint.RelativeXY
PageRightButton.Position = UDim2.new(-1, -4, 0, 0)
local positionOffset = UDim2.new(0.05, 0, 0, 0)
PageRightButton.ArrowLabel.Position = UDim2.new(0.3, 0, 0.3, 0) + positionOffset
PageLeftButton.ArrowLabel.Position = UDim2.new(0.3, 0, 0.3, 0) - positionOffset
PageLeftButton.ArrowLabel.Rotation = 180
self.GuiObject = BaseFrame
self.GuiObjects.BaseFrame = BaseFrame
self.GuiObjects.ScrollerSizer = ScrollerSizer
self.GuiObjects.ScrollerFrame = ScrollerFrame
self.GuiObjects.PageLeftButton = PageLeftButton
self.GuiObjects.PageRightButton = PageRightButton
self.GuiObjects.LeaveConfirmationFrame = LeaveConfirmationFrame
self.GuiObjects.LeaveConfirmationNotice = LeaveConfirmationNotice
self.GuiObjects.PageLeftButtonArrow = PageLeftButton.ArrowLabel
self.GuiObjects.PageRightButtonArrow = PageRightButton.ArrowLabel
self:AnimGuiObjects()
PageLeftButton.MouseButton1Click:connect(function() self:ScrollChannelsFrame(-1) end)
PageRightButton.MouseButton1Click:connect(function() self:ScrollChannelsFrame(1) end)
self:ScrollChannelsFrame(0)
end
function methods:UpdateMessagePostedInChannel(channelName)
local tab = self:GetChannelTab(channelName)
if (tab) then
tab:UpdateMessagePostedInChannel()
else
warn("ChannelsTab '" .. channelName .. "' does not exist!")
end
end
function methods:AddChannelTab(channelName)
if (self:GetChannelTab(channelName)) then
error("Channel tab '" .. channelName .. "'already exists!")
end
local tab = moduleChannelsTab.new(channelName)
tab.GuiObject.Parent = self.GuiObjects.ScrollerFrame
self.ChannelTabs[channelName:lower()] = tab
self.NumTabs = self.NumTabs + 1
self:OrganizeChannelTabs()
if (ChatSettings.RightClickToLeaveChannelEnabled) then
tab.NameTag.MouseButton2Click:connect(function()
self.LeaveConfirmationNotice.Text = string.format("Leave channel %s?", tab.ChannelName)
self.LeaveConfirmationFrame.LeaveTarget.Value = tab.ChannelName
self.LeaveConfirmationFrame:TweenPosition(UDim2.new(0, 0, 0, 0), Enum.EasingDirection.In, Enum.EasingStyle.Quad, 0.2, true)
end)
end
return tab
end
function methods:RemoveChannelTab(channelName)
if (not self:GetChannelTab(channelName)) then
error("Channel tab '" .. channelName .. "'does not exist!")
end
local indexName = channelName:lower()
self.ChannelTabs[indexName]:Destroy()
self.ChannelTabs[indexName] = nil
self.NumTabs = self.NumTabs - 1
self:OrganizeChannelTabs()
end
function methods:GetChannelTab(channelName)
return self.ChannelTabs[channelName:lower()]
end
function methods:OrganizeChannelTabs()
local order = {}
table.insert(order, self:GetChannelTab(ChatSettings.GeneralChannelName))
table.insert(order, self:GetChannelTab("System"))
for tabIndexName, tab in pairs(self.ChannelTabs) do
if (tab.ChannelName ~= ChatSettings.GeneralChannelName and tab.ChannelName ~= "System") then
table.insert(order, tab)
end
end
for index, tab in pairs(order) do
tab.GuiObject.Position = UDim2.new(index - 1, 0, 0, 0)
end
--// Dynamic tab resizing
self.GuiObjects.ScrollerSizer.Size = UDim2.new(1 / math.max(1, math.min(ChatSettings.ChannelsBarFullTabSize, self.NumTabs)), 0, 1, 0)
self:ScrollChannelsFrame(0)
end
function methods:ResizeChannelTabText(textSize)
for i, tab in pairs(self.ChannelTabs) do
tab:SetTextSize(textSize)
end
end
function methods:ScrollChannelsFrame(dir)
if (self.ScrollChannelsFrameLock) then return end
self.ScrollChannelsFrameLock = true
local tabNumber = ChatSettings.ChannelsBarFullTabSize
local newPageNum = self.CurPageNum + dir
if (newPageNum < 0) then
newPageNum = 0
elseif (newPageNum > 0 and newPageNum + tabNumber > self.NumTabs) then
newPageNum = self.NumTabs - tabNumber
end
self.CurPageNum = newPageNum
local tweenTime = 0.15
local endPos = UDim2.new(-self.CurPageNum, 0, 0, 0)
self.GuiObjects.PageLeftButton.Visible = (self.CurPageNum > 0)
self.GuiObjects.PageRightButton.Visible = (self.CurPageNum + tabNumber < self.NumTabs)
if dir == 0 then
self.ScrollChannelsFrameLock = false
return
end
local function UnlockFunc()
self.ScrollChannelsFrameLock = false
end
self:WaitUntilParentedCorrectly()
self.GuiObjects.ScrollerFrame:TweenPosition(endPos, Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, tweenTime, true, UnlockFunc)
end
function methods:FadeOutBackground(duration)
for channelName, channelObj in pairs(self.ChannelTabs) do
channelObj:FadeOutBackground(duration)
end
self.AnimParams.Background_TargetTransparency = 1
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:FadeInBackground(duration)
for channelName, channelObj in pairs(self.ChannelTabs) do
channelObj:FadeInBackground(duration)
end
self.AnimParams.Background_TargetTransparency = 0.6
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:FadeOutText(duration)
for channelName, channelObj in pairs(self.ChannelTabs) do
channelObj:FadeOutText(duration)
end
end
function methods:FadeInText(duration)
for channelName, channelObj in pairs(self.ChannelTabs) do
channelObj:FadeInText(duration)
end
end
function methods:AnimGuiObjects()
self.GuiObjects.PageLeftButton.ImageTransparency = self.AnimParams.Background_CurrentTransparency
self.GuiObjects.PageRightButton.ImageTransparency = self.AnimParams.Background_CurrentTransparency
self.GuiObjects.PageLeftButtonArrow.ImageTransparency = self.AnimParams.Background_CurrentTransparency
self.GuiObjects.PageRightButtonArrow.ImageTransparency = self.AnimParams.Background_CurrentTransparency
end
function methods:InitializeAnimParams()
self.AnimParams.Background_TargetTransparency = 0.6
self.AnimParams.Background_CurrentTransparency = 0.6
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
end
function methods:Update(dtScale)
for channelName, channelObj in pairs(self.ChannelTabs) do
channelObj:Update(dtScale)
end
self.AnimParams.Background_CurrentTransparency = CurveUtil:Expt(
self.AnimParams.Background_CurrentTransparency,
self.AnimParams.Background_TargetTransparency,
self.AnimParams.Background_NormalizedExptValue,
dtScale
)
self:AnimGuiObjects()
end
--// ToDo: Move to common modules
function methods:WaitUntilParentedCorrectly()
while (not self.GuiObject:IsDescendantOf(game:GetService("Players").LocalPlayer)) do
self.GuiObject.AncestryChanged:wait()
end
end
--///////////////////////// Constructors
--//////////////////////////////////////
function module.new()
local obj = setmetatable({}, methods)
obj.GuiObject = nil
obj.GuiObjects = {}
obj.ChannelTabs = {}
obj.NumTabs = 0
obj.CurPageNum = 0
obj.ScrollChannelsFrameLock = false
obj.AnimParams = {}
obj:InitializeAnimParams()
ChatSettings.SettingsChanged:connect(function(setting, value)
if (setting == "ChatChannelsTabTextSize") then
obj:ResizeChannelTabText(value)
end
end)
return obj
end
return module
-- // FileName: ChannelsTab.lua
-- // Written by: Xsitsu
-- // Description: Channel tab button for selecting current channel and also displaying if currently selected.
local module = {}
--////////////////////////////// Include
--//////////////////////////////////////
local Chat = game:GetService("Chat")
local clientChatModules = Chat:WaitForChild("ClientChatModules")
local modulesFolder = script.Parent
local ChatSettings = require(clientChatModules:WaitForChild("ChatSettings"))
local CurveUtil = require(modulesFolder:WaitForChild("CurveUtil"))
--////////////////////////////// Methods
--//////////////////////////////////////
local methods = {}
methods.__index = methods
local function CreateGuiObjects()
local BaseFrame = Instance.new("Frame")
BaseFrame.Selectable = false
BaseFrame.Size = UDim2.new(1, 0, 1, 0)
BaseFrame.BackgroundTransparency = 1
local gapOffsetX = 1
local gapOffsetY = 1
local BackgroundFrame = Instance.new("Frame")
BackgroundFrame.Selectable = false
BackgroundFrame.Name = "BackgroundFrame"
BackgroundFrame.Size = UDim2.new(1, -gapOffsetX * 2, 1, -gapOffsetY * 2)
BackgroundFrame.Position = UDim2.new(0, gapOffsetX, 0, gapOffsetY)
BackgroundFrame.BackgroundTransparency = 1
BackgroundFrame.Parent = BaseFrame
local UnselectedFrame = Instance.new("Frame")
UnselectedFrame.Selectable = false
UnselectedFrame.Name = "UnselectedFrame"
UnselectedFrame.Size = UDim2.new(1, 0, 1, 0)
UnselectedFrame.Position = UDim2.new(0, 0, 0, 0)
UnselectedFrame.BorderSizePixel = 0
UnselectedFrame.BackgroundColor3 = ChatSettings.ChannelsTabUnselectedColor
UnselectedFrame.BackgroundTransparency = 0.6
UnselectedFrame.Parent = BackgroundFrame
local SelectedFrame = Instance.new("Frame")
SelectedFrame.Selectable = false
SelectedFrame.Name = "SelectedFrame"
SelectedFrame.Size = UDim2.new(1, 0, 1, 0)
SelectedFrame.Position = UDim2.new(0, 0, 0, 0)
SelectedFrame.BorderSizePixel = 0
SelectedFrame.BackgroundColor3 = ChatSettings.ChannelsTabSelectedColor
SelectedFrame.BackgroundTransparency = 1
SelectedFrame.Parent = BackgroundFrame
local SelectedFrameBackgroundImage = Instance.new("ImageLabel")
SelectedFrameBackgroundImage.Selectable = false
SelectedFrameBackgroundImage.Name = "BackgroundImage"
SelectedFrameBackgroundImage.BackgroundTransparency = 1
SelectedFrameBackgroundImage.BorderSizePixel = 0
SelectedFrameBackgroundImage.Size = UDim2.new(1, 0, 1, 0)
SelectedFrameBackgroundImage.Position = UDim2.new(0, 0, 0, 0)
SelectedFrameBackgroundImage.ScaleType = Enum.ScaleType.Slice
SelectedFrameBackgroundImage.Parent = SelectedFrame
SelectedFrameBackgroundImage.BackgroundTransparency = 0.6 - 1
local rate = 1.2 * 1
SelectedFrameBackgroundImage.BackgroundColor3 = Color3.fromRGB(78 * rate, 84 * rate, 96 * rate)
local borderXOffset = 2
local blueBarYSize = 4
local BlueBarLeft = Instance.new("ImageLabel")
BlueBarLeft.Selectable = false
BlueBarLeft.Size = UDim2.new(0.5, -borderXOffset, 0, blueBarYSize)
BlueBarLeft.BackgroundTransparency = 1
BlueBarLeft.ScaleType = Enum.ScaleType.Slice
BlueBarLeft.SliceCenter = Rect.new(3,3,32,21)
BlueBarLeft.Parent = SelectedFrame
local BlueBarRight = BlueBarLeft:Clone()
BlueBarRight.Parent = SelectedFrame
BlueBarLeft.Position = UDim2.new(0, borderXOffset, 1, -blueBarYSize)
BlueBarRight.Position = UDim2.new(0.5, 0, 1, -blueBarYSize)
BlueBarLeft.Image = "rbxasset://textures/ui/Settings/Slider/SelectedBarLeft.png"
BlueBarRight.Image = "rbxasset://textures/ui/Settings/Slider/SelectedBarRight.png"
BlueBarLeft.Name = "BlueBarLeft"
BlueBarRight.Name = "BlueBarRight"
local NameTag = Instance.new("TextButton")
NameTag.Selectable = ChatSettings.GamepadNavigationEnabled
NameTag.Size = UDim2.new(1, 0, 1, 0)
NameTag.Position = UDim2.new(0, 0, 0, 0)
NameTag.BackgroundTransparency = 1
NameTag.Font = ChatSettings.DefaultFont
NameTag.TextSize = ChatSettings.ChatChannelsTabTextSize
NameTag.TextColor3 = Color3.new(1, 1, 1)
NameTag.TextStrokeTransparency = 0.75
NameTag.Parent = BackgroundFrame
local NameTagNonSelect = NameTag:Clone()
local NameTagSelect = NameTag:Clone()
NameTagNonSelect.Parent = UnselectedFrame
NameTagSelect.Parent = SelectedFrame
NameTagNonSelect.Font = Enum.Font.SourceSans
NameTagNonSelect.Active = false
NameTagSelect.Active = false
local NewMessageIconFrame = Instance.new("Frame")
NewMessageIconFrame.Selectable = false
NewMessageIconFrame.Size = UDim2.new(0, 18, 0, 18)
NewMessageIconFrame.Position = UDim2.new(0.8, -9, 0.5, -9)
NewMessageIconFrame.BackgroundTransparency = 1
NewMessageIconFrame.Parent = BackgroundFrame
local NewMessageIcon = Instance.new("ImageLabel")
NewMessageIcon.Selectable = false
NewMessageIcon.Size = UDim2.new(1, 0, 1, 0)
NewMessageIcon.BackgroundTransparency = 1
NewMessageIcon.Image = "rbxasset://textures/ui/Chat/MessageCounter.png"
NewMessageIcon.Visible = false
NewMessageIcon.Parent = NewMessageIconFrame
local NewMessageIconText = Instance.new("TextLabel")
NewMessageIconText.Selectable = false
NewMessageIconText.BackgroundTransparency = 1
NewMessageIconText.Size = UDim2.new(0, 13, 0, 9)
NewMessageIconText.Position = UDim2.new(0.5, -7, 0.5, -7)
NewMessageIconText.Font = ChatSettings.DefaultFont
NewMessageIconText.TextSize = 14
NewMessageIconText.TextColor3 = Color3.new(1, 1, 1)
NewMessageIconText.Text = ""
NewMessageIconText.Parent = NewMessageIcon
return BaseFrame, NameTag, NameTagNonSelect, NameTagSelect, NewMessageIcon, UnselectedFrame, SelectedFrame
end
function methods:Destroy()
self.GuiObject:Destroy()
end
function methods:UpdateMessagePostedInChannel(ignoreActive)
if (self.Active and (ignoreActive ~= true)) then return end
local count = self.UnreadMessageCount + 1
self.UnreadMessageCount = count
local label = self.NewMessageIcon
label.Visible = true
label.TextLabel.Text = (count < 100) and tostring(count) or "!"
local tweenTime = 0.15
local tweenPosOffset = UDim2.new(0, 0, -0.1, 0)
local curPos = label.Position
local outPos = curPos + tweenPosOffset
local easingDirection = Enum.EasingDirection.Out
local easingStyle = Enum.EasingStyle.Quad
label.Position = UDim2.new(0, 0, -0.15, 0)
label:TweenPosition(UDim2.new(0, 0, 0, 0), easingDirection, easingStyle, tweenTime, true)
end
function methods:SetActive(active)
self.Active = active
self.UnselectedFrame.Visible = not active
self.SelectedFrame.Visible = active
if (active) then
self.UnreadMessageCount = 0
self.NewMessageIcon.Visible = false
self.NameTag.Font = Enum.Font.SourceSansBold
else
self.NameTag.Font = Enum.Font.SourceSans
end
end
function methods:SetTextSize(textSize)
self.NameTag.TextSize = textSize
end
function methods:FadeOutBackground(duration)
self.AnimParams.Background_TargetTransparency = 1
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:FadeInBackground(duration)
self.AnimParams.Background_TargetTransparency = 0.6
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:FadeOutText(duration)
self.AnimParams.Text_TargetTransparency = 1
self.AnimParams.Text_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
self.AnimParams.TextStroke_TargetTransparency = 1
self.AnimParams.TextStroke_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:FadeInText(duration)
self.AnimParams.Text_TargetTransparency = 0
self.AnimParams.Text_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
self.AnimParams.TextStroke_TargetTransparency = 0.75
self.AnimParams.TextStroke_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end
function methods:AnimGuiObjects()
self.UnselectedFrame.BackgroundTransparency = self.AnimParams.Background_CurrentTransparency
self.SelectedFrame.BackgroundImage.BackgroundTransparency = self.AnimParams.Background_CurrentTransparency
self.SelectedFrame.BlueBarLeft.ImageTransparency = self.AnimParams.Background_CurrentTransparency
self.SelectedFrame.BlueBarRight.ImageTransparency = self.AnimParams.Background_CurrentTransparency
self.NameTagNonSelect.TextTransparency = self.AnimParams.Background_CurrentTransparency
self.NameTagNonSelect.TextStrokeTransparency = self.AnimParams.Background_CurrentTransparency
self.NameTag.TextTransparency = self.AnimParams.Text_CurrentTransparency
self.NewMessageIcon.ImageTransparency = self.AnimParams.Text_CurrentTransparency
self.WhiteTextNewMessageNotification.TextTransparency = self.AnimParams.Text_CurrentTransparency
self.NameTagSelect.TextTransparency = self.AnimParams.Text_CurrentTransparency
self.NameTag.TextStrokeTransparency = self.AnimParams.TextStroke_CurrentTransparency
self.WhiteTextNewMessageNotification.TextStrokeTransparency = self.AnimParams.TextStroke_CurrentTransparency
self.NameTagSelect.TextStrokeTransparency = self.AnimParams.TextStroke_CurrentTransparency
end
function methods:InitializeAnimParams()
self.AnimParams.Text_TargetTransparency = 0
self.AnimParams.Text_CurrentTransparency = 0
self.AnimParams.Text_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
self.AnimParams.TextStroke_TargetTransparency = 0.75
self.AnimParams.TextStroke_CurrentTransparency = 0.75
self.AnimParams.TextStroke_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
self.AnimParams.Background_TargetTransparency = 0.6
self.AnimParams.Background_CurrentTransparency = 0.6
self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
end
function methods:Update(dtScale)
self.AnimParams.Background_CurrentTransparency = CurveUtil:Expt(
self.AnimParams.Background_CurrentTransparency,
self.AnimParams.Background_TargetTransparency,
self.AnimParams.Background_NormalizedExptValue,
dtScale
)
self.AnimParams.Text_CurrentTransparency = CurveUtil:Expt(
self.AnimParams.Text_CurrentTransparency,
self.AnimParams.Text_TargetTransparency,
self.AnimParams.Text_NormalizedExptValue,
dtScale
)
self.AnimParams.TextStroke_CurrentTransparency = CurveUtil:Expt(
self.AnimParams.TextStroke_CurrentTransparency,
self.AnimParams.TextStroke_TargetTransparency,
self.AnimParams.TextStroke_NormalizedExptValue,
dtScale
)
self:AnimGuiObjects()
end
--///////////////////////// Constructors
--//////////////////////////////////////
function module.new(channelName)
local obj = setmetatable({}, methods)
local BaseFrame, NameTag, NameTagNonSelect, NameTagSelect, NewMessageIcon, UnselectedFrame, SelectedFrame = CreateGuiObjects()
obj.GuiObject = BaseFrame
obj.NameTag = NameTag
obj.NameTagNonSelect = NameTagNonSelect
obj.NameTagSelect = NameTagSelect
obj.NewMessageIcon = NewMessageIcon
obj.UnselectedFrame = UnselectedFrame
obj.SelectedFrame = SelectedFrame
obj.BlueBarLeft = SelectedFrame.BlueBarLeft
obj.BlueBarRight = SelectedFrame.BlueBarRight
obj.BackgroundImage = SelectedFrame.BackgroundImage
obj.WhiteTextNewMessageNotification = obj.NewMessageIcon.TextLabel
obj.ChannelName = channelName
obj.UnreadMessageCount = 0
obj.Active = false
obj.GuiObject.Name = "Frame_" .. obj.ChannelName
if (string.len(channelName) > ChatSettings.MaxChannelNameLength) then
channelName = string.sub(channelName, 1, ChatSettings.MaxChannelNameLength - 3) .. "..."
end
--obj.NameTag.Text = channelName
obj.NameTag.Text = ""
obj.NameTagNonSelect.Text = channelName
obj.NameTagSelect.Text = channelName
obj.AnimParams = {}
obj:InitializeAnimParams()
obj:AnimGuiObjects()
obj:SetActive(false)
return obj
end
return module
-- // FileName: ChatMain.lua
-- // Written by: Xsitsu
-- // Description: Main module to handle initializing chat window UI and hooking up events to individual UI pieces.
local moduleApiTable = {}
--// This section of code waits until all of the necessary RemoteEvents are found in EventFolder.
--// I have to do some weird stuff since people could potentially already have pre-existing
--// things in a folder with the same name, and they may have different class types.
--// I do the useEvents thing and set EventFolder to useEvents so I can have a pseudo folder that
--// the rest of the code can interface with and have the guarantee that the RemoteEvents they want
--// exist with their desired names.
local FILTER_MESSAGE_TIMEOUT = 60
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Chat = game:GetService("Chat")
local StarterGui = game:GetService("StarterGui")
local DefaultChatSystemChatEvents = ReplicatedStorage:WaitForChild("DefaultChatSystemChatEvents")
local EventFolder = ReplicatedStorage:WaitForChild("DefaultChatSystemChatEvents")
local clientChatModules = Chat:WaitForChild("ClientChatModules")
local ChatConstants = require(clientChatModules:WaitForChild("ChatConstants"))
local ChatSettings = require(clientChatModules:WaitForChild("ChatSettings"))
local messageCreatorModules = clientChatModules:WaitForChild("MessageCreatorModules")
local MessageCreatorUtil = require(messageCreatorModules:WaitForChild("Util"))
local numChildrenRemaining = 10 -- #waitChildren returns 0 because it's a dictionary
local waitChildren =
{
OnNewMessage = "RemoteEvent",
OnMessageDoneFiltering = "RemoteEvent",
OnNewSystemMessage = "RemoteEvent",
OnChannelJoined = "RemoteEvent",
OnChannelLeft = "RemoteEvent",
OnMuted = "RemoteEvent",
OnUnmuted = "RemoteEvent",
OnMainChannelSet = "RemoteEvent",
SayMessageRequest = "RemoteEvent",
GetInitDataRequest = "RemoteFunction",
}
-- waitChildren/EventFolder does not contain all the remote events, because the server version could be older than the client version.
-- In that case it would not create the new events.
-- These events are accessed directly from DefaultChatSystemChatEvents
local useEvents = {}
local FoundAllEventsEvent = Instance.new("BindableEvent")
function TryRemoveChildWithVerifyingIsCorrectType(child)
if (waitChildren[child.Name] and child:IsA(waitChildren[child.Name])) then
waitChildren[child.Name] = nil
useEvents[child.Name] = child
numChildrenRemaining = numChildrenRemaining - 1
end
end
for i, child in pairs(EventFolder:GetChildren()) do
TryRemoveChildWithVerifyingIsCorrectType(child)
end
if (numChildrenRemaining > 0) then
local con = EventFolder.ChildAdded:connect(function(child)
TryRemoveChildWithVerifyingIsCorrectType(child)
if (numChildrenRemaining < 1) then
FoundAllEventsEvent:Fire()
end
end)
FoundAllEventsEvent.Event:wait()
con:disconnect()
FoundAllEventsEvent:Destroy()
end
EventFolder = useEvents
--// Rest of code after waiting for correct events.
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
while not LocalPlayer do
Players.ChildAdded:wait()
LocalPlayer = Players.LocalPlayer
end
local canChat = true
local ChatDisplayOrder = 6
if ChatSettings.ScreenGuiDisplayOrder ~= nil then
ChatDisplayOrder = ChatSettings.ScreenGuiDisplayOrder
end
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
local GuiParent = Instance.new("ScreenGui")
GuiParent.Name = "Chat"
GuiParent.ResetOnSpawn = false
GuiParent.DisplayOrder = ChatDisplayOrder
GuiParent.Parent = PlayerGui
local DidFirstChannelsLoads = false
local modulesFolder = script
local moduleChatWindow = require(modulesFolder:WaitForChild("ChatWindow"))
local moduleChatBar = require(modulesFolder:WaitForChild("ChatBar"))
local moduleChannelsBar = require(modulesFolder:WaitForChild("ChannelsBar"))
local moduleMessageLabelCreator = require(modulesFolder:WaitForChild("MessageLabelCreator"))
local moduleMessageLogDisplay = require(modulesFolder:WaitForChild("MessageLogDisplay"))
local moduleChatChannel = require(modulesFolder:WaitForChild("ChatChannel"))
local moduleCommandProcessor = require(modulesFolder:WaitForChild("CommandProcessor"))
local ChatWindow = moduleChatWindow.new()
local ChannelsBar = moduleChannelsBar.new()
local MessageLogDisplay = moduleMessageLogDisplay.new()
local CommandProcessor = moduleCommandProcessor.new()
local ChatBar = moduleChatBar.new(CommandProcessor, ChatWindow)
ChatWindow:CreateGuiObjects(GuiParent)
ChatWindow:RegisterChatBar(ChatBar)
ChatWindow:RegisterChannelsBar(ChannelsBar)
ChatWindow:RegisterMessageLogDisplay(MessageLogDisplay)
MessageCreatorUtil:RegisterChatWindow(ChatWindow)
local MessageSender = require(modulesFolder:WaitForChild("MessageSender"))
MessageSender:RegisterSayMessageFunction(EventFolder.SayMessageRequest)
if (UserInputService.TouchEnabled) then
ChatBar:SetTextLabelText('Tap here to chat')
else
ChatBar:SetTextLabelText('To chat click here or press "/" key')
end
spawn(function()
local CurveUtil = require(modulesFolder:WaitForChild("CurveUtil"))
local animationFps = ChatSettings.ChatAnimationFPS or 20.0
local updateWaitTime = 1.0 / animationFps
local lastTick = tick()
while true do
local currentTick = tick()
local tickDelta = currentTick - lastTick
local dtScale = CurveUtil:DeltaTimeToTimescale(tickDelta)
if dtScale ~= 0 then
ChatWindow:Update(dtScale)
end
lastTick = currentTick
wait(updateWaitTime)
end
end)
--////////////////////////////////////////////////////////////////////////////////////////////
--////////////////////////////////////////////////////////////// Code to do chat window fading
--////////////////////////////////////////////////////////////////////////////////////////////
function CheckIfPointIsInSquare(checkPos, topLeft, bottomRight)
return (topLeft.X <= checkPos.X and checkPos.X <= bottomRight.X and
topLeft.Y <= checkPos.Y and checkPos.Y <= bottomRight.Y)
end
local backgroundIsFaded = false
local textIsFaded = false
local lastTextFadeTime = 0
local lastBackgroundFadeTime = 0
local fadedChanged = Instance.new("BindableEvent")
local mouseStateChanged = Instance.new("BindableEvent")
local chatBarFocusChanged = Instance.new("BindableEvent")
function DoBackgroundFadeIn(setFadingTime)
lastBackgroundFadeTime = tick()
backgroundIsFaded = false
fadedChanged:Fire()
ChatWindow:FadeInBackground((setFadingTime or ChatSettings.ChatDefaultFadeDuration))
local currentChannelObject = ChatWindow:GetCurrentChannel()
if (currentChannelObject) then
local Scroller = MessageLogDisplay.Scroller
Scroller.ScrollingEnabled = true
Scroller.ScrollBarThickness = moduleMessageLogDisplay.ScrollBarThickness
end
end
function DoBackgroundFadeOut(setFadingTime)
lastBackgroundFadeTime = tick()
backgroundIsFaded = true
fadedChanged:Fire()
ChatWindow:FadeOutBackground((setFadingTime or ChatSettings.ChatDefaultFadeDuration))
local currentChannelObject = ChatWindow:GetCurrentChannel()
if (currentChannelObject) then
local Scroller = MessageLogDisplay.Scroller
Scroller.ScrollingEnabled = false
Scroller.ScrollBarThickness = 0
end
end
function DoTextFadeIn(setFadingTime)
lastTextFadeTime = tick()
textIsFaded = false
fadedChanged:Fire()
ChatWindow:FadeInText((setFadingTime or ChatSettings.ChatDefaultFadeDuration) * 0)
end
function DoTextFadeOut(setFadingTime)
lastTextFadeTime = tick()
textIsFaded = true
fadedChanged:Fire()
ChatWindow:FadeOutText((setFadingTime or ChatSettings.ChatDefaultFadeDuration))
end
function DoFadeInFromNewInformation()
DoTextFadeIn()
if ChatSettings.ChatShouldFadeInFromNewInformation then
DoBackgroundFadeIn()
end
end
function InstantFadeIn()
DoBackgroundFadeIn(0)
DoTextFadeIn(0)
end
function InstantFadeOut()
DoBackgroundFadeOut(0)
DoTextFadeOut(0)
end
local mouseIsInWindow = nil
function UpdateFadingForMouseState(mouseState)
mouseIsInWindow = mouseState
mouseStateChanged:Fire()
if (ChatBar:IsFocused()) then return end
if (mouseState) then
DoBackgroundFadeIn()
DoTextFadeIn()
else
DoBackgroundFadeIn()
end
end
spawn(function()
while true do
RunService.RenderStepped:wait()
while (mouseIsInWindow or ChatBar:IsFocused()) do
if (mouseIsInWindow) then
mouseStateChanged.Event:wait()
end
if (ChatBar:IsFocused()) then
chatBarFocusChanged.Event:wait()
end
end
if (not backgroundIsFaded) then
local timeDiff = tick() - lastBackgroundFadeTime
if (timeDiff > ChatSettings.ChatWindowBackgroundFadeOutTime) then
DoBackgroundFadeOut()
end
elseif (not textIsFaded) then
local timeDiff = tick() - lastTextFadeTime
if (timeDiff > ChatSettings.ChatWindowTextFadeOutTime) then
DoTextFadeOut()
end
else
fadedChanged.Event:wait()
end
end
end)
function getClassicChatEnabled()
if ChatSettings.ClassicChatEnabled ~= nil then
return ChatSettings.ClassicChatEnabled
end
return Players.ClassicChat
end
function getBubbleChatEnabled()
if ChatSettings.BubbleChatEnabled ~= nil then
return ChatSettings.BubbleChatEnabled
end
return Players.BubbleChat
end
function bubbleChatOnly()
return not getClassicChatEnabled() and getBubbleChatEnabled()
end
function UpdateMousePosition(mousePos)
if not (moduleApiTable.Visible and moduleApiTable.IsCoreGuiEnabled and (moduleApiTable.TopbarEnabled or ChatSettings.ChatOnWithTopBarOff)) then return end
if bubbleChatOnly() then
return
end
local windowPos = ChatWindow.GuiObject.AbsolutePosition
local windowSize = ChatWindow.GuiObject.AbsoluteSize
local newMouseState = CheckIfPointIsInSquare(mousePos, windowPos, windowPos + windowSize)
if (newMouseState ~= mouseIsInWindow) then
UpdateFadingForMouseState(newMouseState)
end
end
UserInputService.InputChanged:connect(function(inputObject)
if (inputObject.UserInputType == Enum.UserInputType.MouseMovement) then
local mousePos = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
UpdateMousePosition(mousePos)
end
end)
UserInputService.TouchTap:connect(function(tapPos, gameProcessedEvent)
UpdateMousePosition(tapPos[1])
end)
UserInputService.TouchMoved:connect(function(inputObject, gameProcessedEvent)
local tapPos = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
UpdateMousePosition(tapPos)
end)
UserInputService.Changed:connect(function(prop)
if prop == "MouseBehavior" then
if UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter then
local windowPos = ChatWindow.GuiObject.AbsolutePosition
local windowSize = ChatWindow.GuiObject.AbsoluteSize
local screenSize = GuiParent.AbsoluteSize
local centerScreenIsInWindow = CheckIfPointIsInSquare(screenSize/2, windowPos, windowPos + windowSize)
if centerScreenIsInWindow then
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
end
end
end)
--// Start and stop fading sequences / timers
UpdateFadingForMouseState(true)
UpdateFadingForMouseState(false)
--////////////////////////////////////////////////////////////////////////////////////////////
--///////////// Code to talk to topbar and maintain set/get core backwards compatibility stuff
--////////////////////////////////////////////////////////////////////////////////////////////
local Util = {}
do
function Util.Signal()
local sig = {}
local mSignaler = Instance.new('BindableEvent')
local mArgData = nil
local mArgDataCount = nil
function sig:fire(...)
mArgData = {...}
mArgDataCount = select('#', ...)
mSignaler:Fire()
end
function sig:connect(f)
if not f then error("connect(nil)", 2) end
return mSignaler.Event:connect(function()
f(unpack(mArgData, 1, mArgDataCount))
end)
end
function sig:wait()
mSignaler.Event:wait()
assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.")
return unpack(mArgData, 1, mArgDataCount)
end
return sig
end
end
function SetVisibility(val)
ChatWindow:SetVisible(val)
moduleApiTable.VisibilityStateChanged:fire(val)
moduleApiTable.Visible = val
if (moduleApiTable.IsCoreGuiEnabled) then
if (val) then
InstantFadeIn()
else
InstantFadeOut()
end
end
end
do
moduleApiTable.TopbarEnabled = true
moduleApiTable.MessageCount = 0
moduleApiTable.Visible = true
moduleApiTable.IsCoreGuiEnabled = true
function moduleApiTable:ToggleVisibility()
SetVisibility(not ChatWindow:GetVisible())
end
function moduleApiTable:SetVisible(visible)
if (ChatWindow:GetVisible() ~= visible) then
SetVisibility(visible)
end
end
function moduleApiTable:FocusChatBar()
ChatBar:CaptureFocus()
end
function moduleApiTable:GetVisibility()
return ChatWindow:GetVisible()
end
function moduleApiTable:GetMessageCount()
return self.MessageCount
end
function moduleApiTable:TopbarEnabledChanged(enabled)
self.TopbarEnabled = enabled
self.CoreGuiEnabled:fire(game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Chat))
end
function moduleApiTable:IsFocused(useWasFocused)
return ChatBar:IsFocused()
end
moduleApiTable.ChatBarFocusChanged = Util.Signal()
moduleApiTable.VisibilityStateChanged = Util.Signal()
moduleApiTable.MessagesChanged = Util.Signal()
moduleApiTable.MessagePosted = Util.Signal()
moduleApiTable.CoreGuiEnabled = Util.Signal()
moduleApiTable.ChatMakeSystemMessageEvent = Util.Signal()
moduleApiTable.ChatWindowPositionEvent = Util.Signal()
moduleApiTable.ChatWindowSizeEvent = Util.Signal()
moduleApiTable.ChatBarDisabledEvent = Util.Signal()
function moduleApiTable:fChatWindowPosition()
return ChatWindow.GuiObject.Position
end
function moduleApiTable:fChatWindowSize()
return ChatWindow.GuiObject.Size
end
function moduleApiTable:fChatBarDisabled()
return not ChatBar:GetEnabled()
end
function moduleApiTable:SpecialKeyPressed(key, modifiers)
if (key == Enum.SpecialKey.ChatHotkey) then
if canChat then
DoChatBarFocus()
end
end
end
end
moduleApiTable.CoreGuiEnabled:connect(function(enabled)
moduleApiTable.IsCoreGuiEnabled = enabled
enabled = enabled and (moduleApiTable.TopbarEnabled or ChatSettings.ChatOnWithTopBarOff)
ChatWindow:SetCoreGuiEnabled(enabled)
if (not enabled) then
ChatBar:ReleaseFocus()
InstantFadeOut()
else
InstantFadeIn()
end
end)
function trimTrailingSpaces(str)
local lastSpace = #str
while lastSpace > 0 do
--- The pattern ^%s matches whitespace at the start of the string. (Starting from lastSpace)
if str:find("^%s", lastSpace) then
lastSpace = lastSpace - 1
else
break
end
end
return str:sub(1, lastSpace)
end
moduleApiTable.ChatMakeSystemMessageEvent:connect(function(valueTable)
if (valueTable["Text"] and type(valueTable["Text"]) == "string") then
while (not DidFirstChannelsLoads) do wait() end
local channel = ChatSettings.GeneralChannelName
local channelObj = ChatWindow:GetChannel(channel)
if (channelObj) then
local messageObject = {
ID = -1,
FromSpeaker = nil,
SpeakerUserId = 0,
OriginalChannel = channel,
IsFiltered = true,
MessageLength = string.len(valueTable.Text),
Message = trimTrailingSpaces(valueTable.Text),
MessageType = ChatConstants.MessageTypeSetCore,
Time = os.time(),
ExtraData = valueTable,
}
channelObj:AddMessageToChannel(messageObject)
ChannelsBar:UpdateMessagePostedInChannel(channel)
moduleApiTable.MessageCount = moduleApiTable.MessageCount + 1
moduleApiTable.MessagesChanged:fire(moduleApiTable.MessageCount)
end
end
end)
moduleApiTable.ChatBarDisabledEvent:connect(function(disabled)
if canChat then
ChatBar:SetEnabled(not disabled)
if (disabled) then
ChatBar:ReleaseFocus()
end
end
end)
moduleApiTable.ChatWindowSizeEvent:connect(function(size)
ChatWindow.GuiObject.Size = size
end)
moduleApiTable.ChatWindowPositionEvent:connect(function(position)
ChatWindow.GuiObject.Position = position
end)
--////////////////////////////////////////////////////////////////////////////////////////////
--///////////////////////////////////////////////// Code to hook client UI up to server events
--////////////////////////////////////////////////////////////////////////////////////////////
function DoChatBarFocus()
if (not ChatWindow:GetCoreGuiEnabled()) then return end
if (not ChatBar:GetEnabled()) then return end
if (not ChatBar:IsFocused() and ChatBar:GetVisible()) then
moduleApiTable:SetVisible(true)
InstantFadeIn()
ChatBar:CaptureFocus()
moduleApiTable.ChatBarFocusChanged:fire(true)
end
end
chatBarFocusChanged.Event:connect(function(focused)
moduleApiTable.ChatBarFocusChanged:fire(focused)
end)
function DoSwitchCurrentChannel(targetChannel)
if (ChatWindow:GetChannel(targetChannel)) then
ChatWindow:SwitchCurrentChannel(targetChannel)
end
end
function SendMessageToSelfInTargetChannel(message, channelName, extraData)
local channelObj = ChatWindow:GetChannel(channelName)
if (channelObj) then
local messageData =
{
ID = -1,
FromSpeaker = nil,
SpeakerUserId = 0,
OriginalChannel = channelName,
IsFiltered = true,
MessageLength = string.len(message),
Message = trimTrailingSpaces(message),
MessageType = ChatConstants.MessageTypeSystem,
Time = os.time(),
ExtraData = extraData,
}
channelObj:AddMessageToChannel(messageData)
end
end
function chatBarFocused()
if (not mouseIsInWindow) then
DoBackgroundFadeIn()
if (textIsFaded) then
DoTextFadeIn()
end
end
chatBarFocusChanged:Fire(true)
end
--// Event for making player say chat message.
function chatBarFocusLost(enterPressed, inputObject)
DoBackgroundFadeIn()
chatBarFocusChanged:Fire(false)
if (enterPressed) then
local message = ChatBar:GetTextBox().Text
if ChatBar:IsInCustomState() then
local customMessage = ChatBar:GetCustomMessage()
if customMessage then
message = customMessage
end
local messageSunk = ChatBar:CustomStateProcessCompletedMessage(message)
ChatBar:ResetCustomState()
if messageSunk then
return
end
end
message = string.sub(message, 1, ChatSettings.MaximumMessageLength)
ChatBar:GetTextBox().Text = ""
if message ~= "" then
--// Sends signal to eventually call Player:Chat() to handle C++ side legacy stuff.
moduleApiTable.MessagePosted:fire(message)
if not CommandProcessor:ProcessCompletedChatMessage(message, ChatWindow) then
if ChatSettings.DisallowedWhiteSpace then
for i = 1, #ChatSettings.DisallowedWhiteSpace do
if ChatSettings.DisallowedWhiteSpace[i] == "\t" then
message = string.gsub(message, ChatSettings.DisallowedWhiteSpace[i], " ")
else
message = string.gsub(message, ChatSettings.DisallowedWhiteSpace[i], "")
end
end
end
message = string.gsub(message, "\n", "")
message = string.gsub(message, "[ ]+", " ")
local targetChannel = ChatWindow:GetTargetMessageChannel()
if targetChannel then
MessageSender:SendMessage(message, targetChannel)
else
MessageSender:SendMessage(message, nil)
end
end
end
end
end
local ChatBarConnections = {}
function setupChatBarConnections()
for i = 1, #ChatBarConnections do
ChatBarConnections[i]:Disconnect()
end
ChatBarConnections = {}
local focusLostConnection = ChatBar:GetTextBox().FocusLost:connect(chatBarFocusLost)
table.insert(ChatBarConnections, focusLostConnection)
local focusGainedConnection = ChatBar:GetTextBox().Focused:connect(chatBarFocused)
table.insert(ChatBarConnections, focusGainedConnection)
end
setupChatBarConnections()
ChatBar.GuiObjectsChanged:connect(setupChatBarConnections)
function getEchoMessagesInGeneral()
if ChatSettings.EchoMessagesInGeneralChannel == nil then
return true
end
return ChatSettings.EchoMessagesInGeneralChannel
end
EventFolder.OnMessageDoneFiltering.OnClientEvent:connect(function(messageData)
if not ChatSettings.ShowUserOwnFilteredMessage then
if messageData.FromSpeaker == LocalPlayer.Name then
return
end
end
local channelName = messageData.OriginalChannel
local channelObj = ChatWindow:GetChannel(channelName)
if channelObj then
channelObj:UpdateMessageFiltered(messageData)
end
if getEchoMessagesInGeneral() and ChatSettings.GeneralChannelName and channelName ~= ChatSettings.GeneralChannelName then
local generalChannel = ChatWindow:GetChannel(ChatSettings.GeneralChannelName)
if generalChannel then
generalChannel:UpdateMessageFiltered(messageData)
end
end
end)
EventFolder.OnNewMessage.OnClientEvent:connect(function(messageData, channelName)
local channelObj = ChatWindow:GetChannel(channelName)
if (channelObj) then
channelObj:AddMessageToChannel(messageData)
if (messageData.FromSpeaker ~= LocalPlayer.Name) then
ChannelsBar:UpdateMessagePostedInChannel(channelName)
end
if getEchoMessagesInGeneral() and ChatSettings.GeneralChannelName and channelName ~= ChatSettings.GeneralChannelName then
local generalChannel = ChatWindow:GetChannel(ChatSettings.GeneralChannelName)
if generalChannel then
generalChannel:AddMessageToChannel(messageData)
end
end
moduleApiTable.MessageCount = moduleApiTable.MessageCount + 1
moduleApiTable.MessagesChanged:fire(moduleApiTable.MessageCount)
DoFadeInFromNewInformation()
end
end)
EventFolder.OnNewSystemMessage.OnClientEvent:connect(function(messageData, channelName)
channelName = channelName or "System"
local channelObj = ChatWindow:GetChannel(channelName)
if (channelObj) then
channelObj:AddMessageToChannel(messageData)
ChannelsBar:UpdateMessagePostedInChannel(channelName)
moduleApiTable.MessageCount = moduleApiTable.MessageCount + 1
moduleApiTable.MessagesChanged:fire(moduleApiTable.MessageCount)
DoFadeInFromNewInformation()
if getEchoMessagesInGeneral() and ChatSettings.GeneralChannelName and channelName ~= ChatSettings.GeneralChannelName then
local generalChannel = ChatWindow:GetChannel(ChatSettings.GeneralChannelName)
if generalChannel then
generalChannel:AddMessageToChannel(messageData)
end
end
else
warn(string.format("Just received system message for channel I'm not in [%s]", channelName))
end
end)
function HandleChannelJoined(channel, welcomeMessage, messageLog, channelNameColor, addHistoryToGeneralChannel,
addWelcomeMessageToGeneralChannel)
if ChatWindow:GetChannel(channel) then
--- If the channel has already been added, remove it first.
ChatWindow:RemoveChannel(channel)
end
if (channel == ChatSettings.GeneralChannelName) then
DidFirstChannelsLoads = true
end
if channelNameColor then
ChatBar:SetChannelNameColor(channel, channelNameColor)
end
local channelObj = ChatWindow:AddChannel(channel)
if (channelObj) then
if (channel == ChatSettings.GeneralChannelName) then
DoSwitchCurrentChannel(channel)
end
if (messageLog) then
local startIndex = 1
if #messageLog > ChatSettings.MessageHistoryLengthPerChannel then
startIndex = #messageLog - ChatSettings.MessageHistoryLengthPerChannel
end
for i = startIndex, #messageLog do
channelObj:AddMessageToChannel(messageLog[i])
end
if getEchoMessagesInGeneral() and addHistoryToGeneralChannel then
if ChatSettings.GeneralChannelName and channel ~= ChatSettings.GeneralChannelName then
local generalChannel = ChatWindow:GetChannel(ChatSettings.GeneralChannelName)
if generalChannel then
generalChannel:AddMessagesToChannelByTimeStamp(messageLog, startIndex)
end
end
end
end
if (welcomeMessage ~= "") then
local welcomeMessageObject = {
ID = -1,
FromSpeaker = nil,
SpeakerUserId = 0,
OriginalChannel = channel,
IsFiltered = true,
MessageLength = string.len(welcomeMessage),
Message = trimTrailingSpaces(welcomeMessage),
MessageType = ChatConstants.MessageTypeWelcome,
Time = os.time(),
ExtraData = nil,
}
channelObj:AddMessageToChannel(welcomeMessageObject)
if getEchoMessagesInGeneral() and addWelcomeMessageToGeneralChannel and not ChatSettings.ShowChannelsBar then
if channel ~= ChatSettings.GeneralChannelName then
local generalChannel = ChatWindow:GetChannel(ChatSettings.GeneralChannelName)
if generalChannel then
generalChannel:AddMessageToChannel(welcomeMessageObject)
end
end
end
end
DoFadeInFromNewInformation()
end
end
EventFolder.OnChannelJoined.OnClientEvent:connect(function(channel, welcomeMessage, messageLog, channelNameColor)
HandleChannelJoined(channel, welcomeMessage, messageLog, channelNameColor, false, true)
end)
EventFolder.OnChannelLeft.OnClientEvent:connect(function(channel)
ChatWindow:RemoveChannel(channel)
DoFadeInFromNewInformation()
end)
EventFolder.OnMuted.OnClientEvent:connect(function(channel)
--// Do something eventually maybe?
--// This used to take away the chat bar in channels the player was muted in.
--// We found out this behavior was inconvenient for doing chat commands though.
end)
EventFolder.OnUnmuted.OnClientEvent:connect(function(channel)
--// Same as above.
end)
EventFolder.OnMainChannelSet.OnClientEvent:connect(function(channel)
DoSwitchCurrentChannel(channel)
end)
coroutine.wrap(function()
-- ChannelNameColorUpdated may not exist if the client version is older than the server version.
local ChannelNameColorUpdated = DefaultChatSystemChatEvents:WaitForChild("ChannelNameColorUpdated", 5)
if ChannelNameColorUpdated then
ChannelNameColorUpdated.OnClientEvent:connect(function(channelName, channelNameColor)
ChatBar:SetChannelNameColor(channelName, channelNameColor)
end)
end
end)()
--- Interaction with SetCore Player events.
local PlayerBlockedEvent = nil
local PlayerMutedEvent = nil
local PlayerUnBlockedEvent = nil
local PlayerUnMutedEvent = nil
-- This is pcalled because the SetCore methods may not be released yet.
pcall(function()
PlayerBlockedEvent = StarterGui:GetCore("PlayerBlockedEvent")
PlayerMutedEvent = StarterGui:GetCore("PlayerMutedEvent")
PlayerUnBlockedEvent = StarterGui:GetCore("PlayerUnblockedEvent")
PlayerUnMutedEvent = StarterGui:GetCore("PlayerUnmutedEvent")
end)
function SendSystemMessageToSelf(message)
local currentChannel = ChatWindow:GetCurrentChannel()
if currentChannel then
local messageData =
{
ID = -1,
FromSpeaker = nil,
SpeakerUserId = 0,
OriginalChannel = currentChannel.Name,
IsFiltered = true,
MessageLength = string.len(message),
Message = trimTrailingSpaces(message),
MessageType = ChatConstants.MessageTypeSystem,
Time = os.time(),
ExtraData = nil,
}
currentChannel:AddMessageToChannel(messageData)
end
end
function MutePlayer(player)
local mutePlayerRequest = DefaultChatSystemChatEvents:FindFirstChild("MutePlayerRequest")
if mutePlayerRequest then
return mutePlayerRequest:InvokeServer(player.Name)
end
return false
end
if PlayerBlockedEvent then
PlayerBlockedEvent.Event:connect(function(player)
if MutePlayer(player) then
SendSystemMessageToSelf(string.format("Speaker '%s' has been blocked.", player.Name))
end
end)
end
if PlayerMutedEvent then
PlayerMutedEvent.Event:connect(function(player)
if MutePlayer(player) then
SendSystemMessageToSelf(string.format("Speaker '%s' has been muted.", player.Name))
end
end)
end
function UnmutePlayer(player)
local unmutePlayerRequest = DefaultChatSystemChatEvents:FindFirstChild("UnMutePlayerRequest")
if unmutePlayerRequest then
return unmutePlayerRequest:InvokeServer(player.Name)
end
return false
end
if PlayerUnBlockedEvent then
PlayerUnBlockedEvent.Event:connect(function(player)
if UnmutePlayer(player) then
SendSystemMessageToSelf(string.format("Speaker '%s' has been unblocked.", player.Name))
end
end)
end
if PlayerUnMutedEvent then
PlayerUnMutedEvent.Event:connect(function(player)
if UnmutePlayer(player) then
SendSystemMessageToSelf(string.format("Speaker '%s' has been unmuted.", player.Name))
end
end)
end
-- Get a list of blocked users from the corescripts.
-- Spawned because this method can yeild.
spawn(function()
-- Pcalled because this method is not released on all platforms yet.
if LocalPlayer.UserId > 0 then
pcall(function()
local blockedUserIds = StarterGui:GetCore("GetBlockedUserIds")
if #blockedUserIds > 0 then
local setInitalBlockedUserIds = DefaultChatSystemChatEvents:FindFirstChild("SetBlockedUserIdsRequest")
if setInitalBlockedUserIds then
setInitalBlockedUserIds:FireServer(blockedUserIds)
end
end
end)
end
end)
spawn(function()
local success, canLocalUserChat = pcall(function()
return Chat:CanUserChatAsync(LocalPlayer.UserId)
end)
if success then
canChat = RunService:IsStudio() or canLocalUserChat
end
end)
local initData = EventFolder.GetInitDataRequest:InvokeServer()
-- Handle joining general channel first.
for i, channelData in pairs(initData.Channels) do
if channelData[1] == ChatSettings.GeneralChannelName then
HandleChannelJoined(channelData[1], channelData[2], channelData[3], channelData[4], true, false)
end
end
for i, channelData in pairs(initData.Channels) do
if channelData[1] ~= ChatSettings.GeneralChannelName then
HandleChannelJoined(channelData[1], channelData[2], channelData[3], channelData[4], true, false)
end
end
return moduleApiTable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment