Advertisement
Guest User

BubbleChat Roblox

a guest
Oct 22nd, 2017
3,611
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 22.26 KB | None | 0 0
  1. --[[
  2.     // FileName: BubbleChat.lua
  3.     // Written by: jeditkacheff, TheGamer101
  4.     // Description: Code for rendering bubble chat
  5. ]]
  6.  
  7. --[[ SERVICES ]]
  8. local PlayersService = game:GetService('Players')
  9. local ReplicatedStorage = game:GetService("ReplicatedStorage")
  10. local ChatService = game:GetService("Chat")
  11. local TextService = game:GetService("TextService")
  12. --[[ END OF SERVICES ]]
  13.  
  14. local LocalPlayer = PlayersService.LocalPlayer
  15. while LocalPlayer == nil do
  16.     PlayersService.ChildAdded:wait()
  17.     LocalPlayer = PlayersService.LocalPlayer
  18. end
  19.  
  20. local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
  21.  
  22. --[[ SCRIPT VARIABLES ]]
  23. local CHAT_BUBBLE_FONT = Enum.Font.SourceSans
  24. local CHAT_BUBBLE_FONT_SIZE = Enum.FontSize.Size24 -- if you change CHAT_BUBBLE_FONT_SIZE_INT please change this to match
  25. local CHAT_BUBBLE_FONT_SIZE_INT = 24 -- if you change CHAT_BUBBLE_FONT_SIZE please change this to match
  26. local CHAT_BUBBLE_LINE_HEIGHT = CHAT_BUBBLE_FONT_SIZE_INT + 10
  27. local CHAT_BUBBLE_TAIL_HEIGHT = 14
  28. local CHAT_BUBBLE_WIDTH_PADDING = 30
  29. local CHAT_BUBBLE_FADE_SPEED = 1.5
  30.  
  31. local BILLBOARD_MAX_WIDTH = 400
  32. local BILLBOARD_MAX_HEIGHT = 250    --This limits the number of bubble chats that you see above characters
  33.  
  34. local ELIPSES = "..."
  35. local MaxChatMessageLength = 128 -- max chat message length, including null terminator and elipses.
  36. local MaxChatMessageLengthExclusive = MaxChatMessageLength - string.len(ELIPSES) - 1
  37.  
  38. local NEAR_BUBBLE_DISTANCE = 65 --previously 45
  39. local MAX_BUBBLE_DISTANCE = 100 --previously 80
  40.  
  41. --[[ END OF SCRIPT VARIABLES ]]
  42.  
  43.  
  44. -- [[ SCRIPT ENUMS ]]
  45. local BubbleColor = {   WHITE = "dub",
  46.                     BLUE = "blu",
  47.                     GREEN = "gre",
  48.                     RED = "red" }
  49.  
  50. --[[ END OF SCRIPT ENUMS ]]
  51.  
  52. -- This screenGui exists so that the billboardGui is not deleted when the PlayerGui is reset.
  53. local BubbleChatScreenGui = Instance.new("ScreenGui")
  54. BubbleChatScreenGui.Name = "BubbleChat"
  55. BubbleChatScreenGui.ResetOnSpawn = false
  56. BubbleChatScreenGui.Parent = PlayerGui
  57.  
  58. --[[ FUNCTIONS ]]
  59.  
  60. local function lerpLength(msg, min, max)
  61.     return min + (max-min) * math.min(string.len(msg)/75.0, 1.0)
  62. end
  63.  
  64. local function createFifo()
  65.     local this = {}
  66.     this.data = {}
  67.  
  68.     local emptyEvent = Instance.new("BindableEvent")
  69.     this.Emptied = emptyEvent.Event
  70.  
  71.     function this:Size()
  72.         return #this.data
  73.     end
  74.  
  75.     function this:Empty()
  76.         return this:Size() <= 0
  77.     end
  78.  
  79.     function this:PopFront()
  80.         table.remove(this.data, 1)
  81.         if this:Empty() then emptyEvent:Fire() end
  82.     end
  83.  
  84.     function this:Front()
  85.         return this.data[1]
  86.     end
  87.  
  88.     function this:Get(index)
  89.         return this.data[index]
  90.     end
  91.  
  92.     function this:PushBack(value)
  93.         table.insert(this.data, value)
  94.     end
  95.  
  96.     function this:GetData()
  97.         return this.data
  98.     end
  99.  
  100.     return this
  101. end
  102.  
  103. local function createCharacterChats()
  104.     local this = {}
  105.  
  106.     this.Fifo = createFifo()
  107.     this.BillboardGui = nil
  108.  
  109.     return this
  110. end
  111.  
  112. local function createMap()
  113.     local this = {}
  114.     this.data = {}
  115.     local count = 0
  116.  
  117.     function this:Size()
  118.         return count
  119.     end
  120.  
  121.     function this:Erase(key)
  122.         if this.data[key] then count = count - 1 end
  123.         this.data[key] = nil
  124.     end
  125.  
  126.     function this:Set(key, value)
  127.         this.data[key] = value
  128.         if value then count = count + 1 end
  129.     end
  130.  
  131.     function this:Get(key)
  132.         if not key then return end
  133.         if not this.data[key] then
  134.             this.data[key] = createCharacterChats()
  135.             local emptiedCon = nil
  136.             emptiedCon = this.data[key].Fifo.Emptied:connect(function()
  137.                 emptiedCon:disconnect()
  138.                 this:Erase(key)
  139.             end)
  140.         end
  141.         return this.data[key]
  142.     end
  143.  
  144.     function this:GetData()
  145.         return this.data
  146.     end
  147.  
  148.     return this
  149. end
  150.  
  151. local function createChatLine(message, bubbleColor, isLocalPlayer)
  152.     local this = {}
  153.  
  154.     function this:ComputeBubbleLifetime(msg, isSelf)
  155.         if isSelf then
  156.             return lerpLength(msg,8,15)
  157.         else
  158.             return lerpLength(msg,12,20)
  159.         end
  160.     end
  161.  
  162.     this.Origin = nil
  163.     this.RenderBubble = nil
  164.     this.Message = message
  165.     this.BubbleDieDelay = this:ComputeBubbleLifetime(message, isLocalPlayer)
  166.     this.BubbleColor = bubbleColor
  167.     this.IsLocalPlayer = isLocalPlayer
  168.  
  169.     return this
  170. end
  171.  
  172. local function createPlayerChatLine(player, message, isLocalPlayer)
  173.     local this = createChatLine(message, BubbleColor.WHITE, isLocalPlayer)
  174.  
  175.     if player then
  176.         this.User = player.Name
  177.         this.Origin = player.Character
  178.     end
  179.  
  180.     return this
  181. end
  182.  
  183. local function createGameChatLine(origin, message, isLocalPlayer, bubbleColor)
  184.     local this = createChatLine(message, bubbleColor, isLocalPlayer)
  185.     this.Origin = origin
  186.  
  187.     return this
  188. end
  189.  
  190. function createChatBubbleMain(filePrefix, sliceRect)
  191.     local chatBubbleMain = Instance.new("ImageLabel")
  192.     chatBubbleMain.Name = "ChatBubble"
  193.     chatBubbleMain.ScaleType = Enum.ScaleType.Slice
  194.     chatBubbleMain.SliceCenter = sliceRect
  195.     chatBubbleMain.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
  196.     chatBubbleMain.BackgroundTransparency = 1
  197.     chatBubbleMain.BorderSizePixel = 0
  198.     chatBubbleMain.Size = UDim2.new(1.0, 0, 1.0, 0)
  199.     chatBubbleMain.Position = UDim2.new(0,0,0,0)
  200.  
  201.     return chatBubbleMain
  202. end
  203.  
  204. function createChatBubbleTail(position, size)
  205.     local chatBubbleTail = Instance.new("ImageLabel")
  206.     chatBubbleTail.Name = "ChatBubbleTail"
  207.     chatBubbleTail.Image = "rbxasset://textures/ui/dialog_tail.png"
  208.     chatBubbleTail.BackgroundTransparency = 1
  209.     chatBubbleTail.BorderSizePixel = 0
  210.     chatBubbleTail.Position = position
  211.     chatBubbleTail.Size = size
  212.  
  213.     return chatBubbleTail
  214. end
  215.  
  216. function createChatBubbleWithTail(filePrefix, position, size, sliceRect)
  217.     local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)
  218.  
  219.     local chatBubbleTail = createChatBubbleTail(position, size)
  220.     chatBubbleTail.Parent = chatBubbleMain
  221.  
  222.     return chatBubbleMain
  223. end
  224.  
  225. function createScaledChatBubbleWithTail(filePrefix, frameScaleSize, position, sliceRect)
  226.     local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)
  227.  
  228.     local frame = Instance.new("Frame")
  229.     frame.Name = "ChatBubbleTailFrame"
  230.     frame.BackgroundTransparency = 1
  231.     frame.SizeConstraint = Enum.SizeConstraint.RelativeXX
  232.     frame.Position = UDim2.new(0.5, 0, 1, 0)
  233.     frame.Size = UDim2.new(frameScaleSize, 0, frameScaleSize, 0)
  234.     frame.Parent = chatBubbleMain
  235.  
  236.     local chatBubbleTail = createChatBubbleTail(position, UDim2.new(1,0,0.5,0))
  237.     chatBubbleTail.Parent = frame
  238.  
  239.     return chatBubbleMain
  240. end
  241.  
  242. function createChatImposter(filePrefix, dotDotDot, yOffset)
  243.     local result = Instance.new("ImageLabel")
  244.     result.Name = "DialogPlaceholder"
  245.     result.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
  246.     result.BackgroundTransparency = 1
  247.     result.BorderSizePixel = 0
  248.     result.Position = UDim2.new(0, 0, -1.25, 0)
  249.     result.Size = UDim2.new(1, 0, 1, 0)
  250.  
  251.     local image = Instance.new("ImageLabel")
  252.     image.Name = "DotDotDot"
  253.     image.Image = "rbxasset://textures/" .. tostring(dotDotDot) .. ".png"
  254.     image.BackgroundTransparency = 1
  255.     image.BorderSizePixel = 0
  256.     image.Position = UDim2.new(0.001, 0, yOffset, 0)
  257.     image.Size = UDim2.new(1, 0, 0.7, 0)
  258.     image.Parent = result
  259.  
  260.     return result
  261. end
  262.  
  263.  
  264. local this = {}
  265. this.ChatBubble = {}
  266. this.ChatBubbleWithTail = {}
  267. this.ScalingChatBubbleWithTail = {}
  268. this.CharacterSortedMsg = createMap()
  269.  
  270. -- init chat bubble tables
  271. local function initChatBubbleType(chatBubbleType, fileName, imposterFileName, isInset, sliceRect)
  272.     this.ChatBubble[chatBubbleType] = createChatBubbleMain(fileName, sliceRect)
  273.     this.ChatBubbleWithTail[chatBubbleType] = createChatBubbleWithTail(fileName, UDim2.new(0.5, -CHAT_BUBBLE_TAIL_HEIGHT, 1, isInset and -1 or 0), UDim2.new(0, 30, 0, CHAT_BUBBLE_TAIL_HEIGHT), sliceRect)
  274.     this.ScalingChatBubbleWithTail[chatBubbleType] = createScaledChatBubbleWithTail(fileName, 0.5, UDim2.new(-0.5, 0, 0, isInset and -1 or 0), sliceRect)
  275. end
  276.  
  277. initChatBubbleType(BubbleColor.WHITE,   "ui/dialog_white",  "ui/chatBubble_white_notify_bkg",   false,  Rect.new(5,5,15,15))
  278. initChatBubbleType(BubbleColor.BLUE,    "ui/dialog_blue",   "ui/chatBubble_blue_notify_bkg",    true,   Rect.new(7,7,33,33))
  279. initChatBubbleType(BubbleColor.RED,     "ui/dialog_red",    "ui/chatBubble_red_notify_bkg",     true,   Rect.new(7,7,33,33))
  280. initChatBubbleType(BubbleColor.GREEN,   "ui/dialog_green",  "ui/chatBubble_green_notify_bkg",   true,   Rect.new(7,7,33,33))
  281.  
  282. function this:SanitizeChatLine(msg)
  283.     if string.len(msg) > MaxChatMessageLengthExclusive then
  284.         return string.sub(msg, 1, MaxChatMessageLengthExclusive + string.len(ELIPSES))
  285.     else
  286.         return msg
  287.     end
  288. end
  289.  
  290. local function createBillboardInstance(adornee)
  291.     local billboardGui = Instance.new("BillboardGui")
  292.     billboardGui.Adornee = adornee
  293.     billboardGui.Size = UDim2.new(0,BILLBOARD_MAX_WIDTH,0,BILLBOARD_MAX_HEIGHT)
  294.     billboardGui.StudsOffset = Vector3.new(0, 1.5, 2)
  295.     billboardGui.Parent = BubbleChatScreenGui
  296.  
  297.     local billboardFrame = Instance.new("Frame")
  298.     billboardFrame.Name = "BillboardFrame"
  299.     billboardFrame.Size = UDim2.new(1,0,1,0)
  300.     billboardFrame.Position = UDim2.new(0,0,-0.5,0)
  301.     billboardFrame.BackgroundTransparency = 1
  302.     billboardFrame.Parent = billboardGui
  303.  
  304.     local billboardChildRemovedCon = nil
  305.     billboardChildRemovedCon = billboardFrame.ChildRemoved:connect(function()
  306.         if #billboardFrame:GetChildren() <= 1 then
  307.             billboardChildRemovedCon:disconnect()
  308.             billboardGui:Destroy()
  309.         end
  310.     end)
  311.  
  312.     this:CreateSmallTalkBubble(BubbleColor.WHITE).Parent = billboardFrame
  313.  
  314.     return billboardGui
  315. end
  316.  
  317. function this:CreateBillboardGuiHelper(instance, onlyCharacter)
  318.     if instance and not this.CharacterSortedMsg:Get(instance)["BillboardGui"] then
  319.         if not onlyCharacter then
  320.             if instance:IsA("BasePart") then
  321.                 -- Create a new billboardGui object attached to this player
  322.                 local billboardGui = createBillboardInstance(instance)
  323.                 this.CharacterSortedMsg:Get(instance)["BillboardGui"] = billboardGui
  324.                 return
  325.             end
  326.         end
  327.  
  328.         if instance:IsA("Model") then
  329.             local head = instance:FindFirstChild("Head")
  330.             if head and head:IsA("BasePart") then
  331.                 -- Create a new billboardGui object attached to this player
  332.                 local billboardGui = createBillboardInstance(head)
  333.                 this.CharacterSortedMsg:Get(instance)["BillboardGui"] = billboardGui
  334.             end
  335.         end
  336.     end
  337. end
  338.  
  339. local function distanceToBubbleOrigin(origin)
  340.     if not origin then return 100000 end
  341.  
  342.     return (origin.Position - game.Workspace.CurrentCamera.CoordinateFrame.p).magnitude
  343. end
  344.  
  345. local function isPartOfLocalPlayer(adornee)
  346.     if adornee and PlayersService.LocalPlayer.Character then
  347.         return adornee:IsDescendantOf(PlayersService.LocalPlayer.Character)
  348.     end
  349. end
  350.  
  351. function this:SetBillboardLODNear(billboardGui)
  352.     local isLocalPlayer = isPartOfLocalPlayer(billboardGui.Adornee)
  353.     billboardGui.Size = UDim2.new(0, BILLBOARD_MAX_WIDTH, 0, BILLBOARD_MAX_HEIGHT)
  354.     billboardGui.StudsOffset = Vector3.new(0, isLocalPlayer and 1.5 or 2.5, isLocalPlayer and 2 or 0.1)
  355.     billboardGui.Enabled = true
  356.     local billChildren = billboardGui.BillboardFrame:GetChildren()
  357.     for i = 1, #billChildren do
  358.         billChildren[i].Visible = true
  359.     end
  360.     billboardGui.BillboardFrame.SmallTalkBubble.Visible = false
  361. end
  362.  
  363. function this:SetBillboardLODDistant(billboardGui)
  364.     local isLocalPlayer = isPartOfLocalPlayer(billboardGui.Adornee)
  365.     billboardGui.Size = UDim2.new(4,0,3,0)
  366.     billboardGui.StudsOffset = Vector3.new(0, 3, isLocalPlayer and 2 or 0.1)
  367.     billboardGui.Enabled = true
  368.     local billChildren = billboardGui.BillboardFrame:GetChildren()
  369.     for i = 1, #billChildren do
  370.         billChildren[i].Visible = false
  371.     end
  372.     billboardGui.BillboardFrame.SmallTalkBubble.Visible = true
  373. end
  374.  
  375. function this:SetBillboardLODVeryFar(billboardGui)
  376.     billboardGui.Enabled = false
  377. end
  378.  
  379. function this:SetBillboardGuiLOD(billboardGui, origin)
  380.     if not origin then return end
  381.  
  382.     if origin:IsA("Model") then
  383.         local head = origin:FindFirstChild("Head")
  384.         if not head then origin = origin.PrimaryPart
  385.         else origin = head end
  386.     end
  387.  
  388.     local bubbleDistance = distanceToBubbleOrigin(origin)
  389.  
  390.     if bubbleDistance < NEAR_BUBBLE_DISTANCE then
  391.         this:SetBillboardLODNear(billboardGui)
  392.     elseif bubbleDistance >= NEAR_BUBBLE_DISTANCE and bubbleDistance < MAX_BUBBLE_DISTANCE then
  393.         this:SetBillboardLODDistant(billboardGui)
  394.     else
  395.         this:SetBillboardLODVeryFar(billboardGui)
  396.     end
  397. end
  398.  
  399. function this:CameraCFrameChanged()
  400.     for index, value in pairs(this.CharacterSortedMsg:GetData()) do
  401.         local playerBillboardGui = value["BillboardGui"]
  402.         if playerBillboardGui then this:SetBillboardGuiLOD(playerBillboardGui, index) end
  403.     end
  404. end
  405.  
  406. function this:CreateBubbleText(message)
  407.     local bubbleText = Instance.new("TextLabel")
  408.     bubbleText.Name = "BubbleText"
  409.     bubbleText.BackgroundTransparency = 1
  410.     bubbleText.Position = UDim2.new(0,CHAT_BUBBLE_WIDTH_PADDING/2,0,0)
  411.     bubbleText.Size = UDim2.new(1,-CHAT_BUBBLE_WIDTH_PADDING,1,0)
  412.     bubbleText.Font = CHAT_BUBBLE_FONT
  413.     bubbleText.TextWrapped = true
  414.     bubbleText.FontSize = CHAT_BUBBLE_FONT_SIZE
  415.     bubbleText.Text = message
  416.     bubbleText.Visible = false
  417.  
  418.     return bubbleText
  419. end
  420.  
  421. function this:CreateSmallTalkBubble(chatBubbleType)
  422.     local smallTalkBubble = this.ScalingChatBubbleWithTail[chatBubbleType]:Clone()
  423.     smallTalkBubble.Name = "SmallTalkBubble"
  424.     smallTalkBubble.AnchorPoint = Vector2.new(0, 0.5)
  425.     smallTalkBubble.Position = UDim2.new(0,0,0.5,0)
  426.     smallTalkBubble.Visible = false
  427.     local text = this:CreateBubbleText("...")
  428.     text.TextScaled = true
  429.     text.TextWrapped = false
  430.     text.Visible = true
  431.     text.Parent = smallTalkBubble
  432.  
  433.     return smallTalkBubble
  434. end
  435.  
  436. function this:UpdateChatLinesForOrigin(origin, currentBubbleYPos)
  437.     local bubbleQueue = this.CharacterSortedMsg:Get(origin).Fifo
  438.     local bubbleQueueSize = bubbleQueue:Size()
  439.     local bubbleQueueData = bubbleQueue:GetData()
  440.     if #bubbleQueueData <= 1 then return end
  441.  
  442.     for index = (#bubbleQueueData - 1), 1, -1 do
  443.         local value = bubbleQueueData[index]
  444.         local bubble = value.RenderBubble
  445.         if not bubble then return end
  446.         local bubblePos = bubbleQueueSize - index + 1
  447.  
  448.         if bubblePos > 1 then
  449.             local tail = bubble:FindFirstChild("ChatBubbleTail")
  450.             if tail then tail:Destroy() end
  451.             local bubbleText = bubble:FindFirstChild("BubbleText")
  452.             if bubbleText then bubbleText.TextTransparency = 0.5 end
  453.         end
  454.  
  455.         local udimValue = UDim2.new( bubble.Position.X.Scale, bubble.Position.X.Offset,
  456.                                     1, currentBubbleYPos - bubble.Size.Y.Offset - CHAT_BUBBLE_TAIL_HEIGHT )
  457.         bubble:TweenPosition(udimValue, Enum.EasingDirection.Out, Enum.EasingStyle.Bounce, 0.1, true)
  458.         currentBubbleYPos = currentBubbleYPos - bubble.Size.Y.Offset - CHAT_BUBBLE_TAIL_HEIGHT
  459.     end
  460. end
  461.  
  462. function this:DestroyBubble(bubbleQueue, bubbleToDestroy)
  463.     if not bubbleQueue then return end
  464.     if bubbleQueue:Empty() then return end
  465.  
  466.     local bubble = bubbleQueue:Front().RenderBubble
  467.     if not bubble then
  468.         bubbleQueue:PopFront()
  469.         return
  470.     end
  471.  
  472.     spawn(function()
  473.         while bubbleQueue:Front().RenderBubble ~= bubbleToDestroy do
  474.             wait()
  475.         end
  476.  
  477.         bubble = bubbleQueue:Front().RenderBubble
  478.  
  479.         local timeBetween = 0
  480.         local bubbleText = bubble:FindFirstChild("BubbleText")
  481.         local bubbleTail = bubble:FindFirstChild("ChatBubbleTail")
  482.  
  483.         while bubble and bubble.ImageTransparency < 1 do
  484.             timeBetween = wait()
  485.             if bubble then
  486.                 local fadeAmount = timeBetween * CHAT_BUBBLE_FADE_SPEED
  487.                 bubble.ImageTransparency = bubble.ImageTransparency + fadeAmount
  488.                 if bubbleText then bubbleText.TextTransparency = bubbleText.TextTransparency + fadeAmount end
  489.                 if bubbleTail then bubbleTail.ImageTransparency = bubbleTail.ImageTransparency + fadeAmount end
  490.             end
  491.         end
  492.  
  493.         if bubble then
  494.             bubble:Destroy()
  495.             bubbleQueue:PopFront()
  496.         end
  497.     end)
  498. end
  499.  
  500. function this:CreateChatLineRender(instance, line, onlyCharacter, fifo)
  501.     if not instance then return end
  502.  
  503.     if not this.CharacterSortedMsg:Get(instance)["BillboardGui"] then
  504.         this:CreateBillboardGuiHelper(instance, onlyCharacter)
  505.     end
  506.  
  507.     local billboardGui = this.CharacterSortedMsg:Get(instance)["BillboardGui"]
  508.     if billboardGui then
  509.         local chatBubbleRender = this.ChatBubbleWithTail[line.BubbleColor]:Clone()
  510.         chatBubbleRender.Visible = false
  511.         local bubbleText = this:CreateBubbleText(line.Message)
  512.  
  513.         bubbleText.Parent = chatBubbleRender
  514.         chatBubbleRender.Parent = billboardGui.BillboardFrame
  515.  
  516.         line.RenderBubble = chatBubbleRender
  517.  
  518.         local currentTextBounds = TextService:GetTextSize(
  519.                 bubbleText.Text, CHAT_BUBBLE_FONT_SIZE_INT, CHAT_BUBBLE_FONT,
  520.                 Vector2.new(BILLBOARD_MAX_WIDTH, BILLBOARD_MAX_HEIGHT))
  521.         local bubbleWidthScale = math.max((currentTextBounds.X + CHAT_BUBBLE_WIDTH_PADDING)/BILLBOARD_MAX_WIDTH, 0.1)
  522.         local numOflines = (currentTextBounds.Y/CHAT_BUBBLE_FONT_SIZE_INT)
  523.  
  524.         -- prep chat bubble for tween
  525.         chatBubbleRender.Size = UDim2.new(0,0,0,0)
  526.         chatBubbleRender.Position = UDim2.new(0.5,0,1,0)
  527.  
  528.         local newChatBubbleOffsetSizeY = numOflines * CHAT_BUBBLE_LINE_HEIGHT
  529.  
  530.         chatBubbleRender:TweenSizeAndPosition(UDim2.new(bubbleWidthScale, 0, 0, newChatBubbleOffsetSizeY),
  531.                                                 UDim2.new( (1-bubbleWidthScale)/2, 0, 1, -newChatBubbleOffsetSizeY),
  532.                                                 Enum.EasingDirection.Out, Enum.EasingStyle.Elastic, 0.1, true,
  533.                                                 function() bubbleText.Visible = true end)
  534.  
  535.         -- todo: remove when over max bubbles
  536.         this:SetBillboardGuiLOD(billboardGui, line.Origin)
  537.         this:UpdateChatLinesForOrigin(line.Origin, -newChatBubbleOffsetSizeY)
  538.  
  539.         delay(line.BubbleDieDelay, function()
  540.             this:DestroyBubble(fifo, chatBubbleRender)
  541.         end)
  542.     end
  543. end
  544.  
  545. function this:OnPlayerChatMessage(sourcePlayer, message, targetPlayer)
  546.     if not this:BubbleChatEnabled() then return end
  547.  
  548.     local localPlayer = PlayersService.LocalPlayer
  549.     local fromOthers = localPlayer ~= nil and sourcePlayer ~= localPlayer
  550.  
  551.     local safeMessage = this:SanitizeChatLine(message)
  552.  
  553.     local line = createPlayerChatLine(sourcePlayer, safeMessage, not fromOthers)
  554.  
  555.     if sourcePlayer and line.Origin then
  556.         local fifo = this.CharacterSortedMsg:Get(line.Origin).Fifo
  557.         fifo:PushBack(line)
  558.         --Game chat (badges) won't show up here
  559.         this:CreateChatLineRender(sourcePlayer.Character, line, true, fifo)
  560.     end
  561. end
  562.  
  563. function this:OnGameChatMessage(origin, message, color)
  564.     local localPlayer = PlayersService.LocalPlayer
  565.     local fromOthers = localPlayer ~= nil and (localPlayer.Character ~= origin)
  566.  
  567.     local bubbleColor = BubbleColor.WHITE
  568.  
  569.     if color == Enum.ChatColor.Blue then bubbleColor = BubbleColor.BLUE
  570.     elseif color == Enum.ChatColor.Green then bubbleColor = BubbleColor.GREEN
  571.     elseif color == Enum.ChatColor.Red then bubbleColor = BubbleColor.RED end
  572.  
  573.     local safeMessage = this:SanitizeChatLine(message)
  574.     local line = createGameChatLine(origin, safeMessage, not fromOthers, bubbleColor)
  575.  
  576.     this.CharacterSortedMsg:Get(line.Origin).Fifo:PushBack(line)
  577.     this:CreateChatLineRender(origin, line, false, this.CharacterSortedMsg:Get(line.Origin).Fifo)
  578. end
  579.  
  580. function this:BubbleChatEnabled()
  581.     local clientChatModules = ChatService:FindFirstChild("ClientChatModules")
  582.     if clientChatModules then
  583.         local chatSettings = clientChatModules:FindFirstChild("ChatSettings")
  584.         if chatSettings then
  585.             local chatSettings = require(chatSettings)
  586.             if chatSettings.BubbleChatEnabled ~= nil then
  587.                 return chatSettings.BubbleChatEnabled
  588.             end
  589.         end
  590.     end
  591.     return PlayersService.BubbleChat
  592. end
  593.  
  594. function this:ShowOwnFilteredMessage()
  595.     local clientChatModules = ChatService:FindFirstChild("ClientChatModules")
  596.     if clientChatModules then
  597.         local chatSettings = clientChatModules:FindFirstChild("ChatSettings")
  598.         if chatSettings then
  599.             chatSettings = require(chatSettings)
  600.             return chatSettings.ShowUserOwnFilteredMessage
  601.         end
  602.     end
  603.     return false
  604. end
  605.  
  606. function findPlayer(playerName)
  607.     for i,v in pairs(PlayersService:GetPlayers()) do
  608.         if v.Name == playerName then
  609.             return v
  610.         end
  611.     end
  612. end
  613.  
  614. ChatService.Chatted:connect(function(origin, message, color) this:OnGameChatMessage(origin, message, color) end)
  615.  
  616. local cameraChangedCon = nil
  617. if game.Workspace.CurrentCamera then
  618.     cameraChangedCon = game.Workspace.CurrentCamera:GetPropertyChangedSignal("CFrame"):connect(function(prop) this:CameraCFrameChanged() end)
  619. end
  620.  
  621. game.Workspace.Changed:connect(function(prop)
  622.     if prop == "CurrentCamera" then
  623.         if cameraChangedCon then cameraChangedCon:disconnect() end
  624.         if game.Workspace.CurrentCamera then
  625.             cameraChangedCon = game.Workspace.CurrentCamera:GetPropertyChangedSignal("CFrame"):connect(function(prop) this:CameraCFrameChanged() end)
  626.         end
  627.     end
  628. end)
  629.  
  630.  
  631. local AllowedMessageTypes = nil
  632.  
  633. function getAllowedMessageTypes()
  634.     if AllowedMessageTypes then
  635.         return AllowedMessageTypes
  636.     end
  637.     local clientChatModules = ChatService:FindFirstChild("ClientChatModules")
  638.     if clientChatModules then
  639.         local chatSettings = clientChatModules:FindFirstChild("ChatSettings")
  640.         if chatSettings then
  641.             chatSettings = require(chatSettings)
  642.             if chatSettings.BubbleChatMessageTypes then
  643.                 AllowedMessageTypes = chatSettings.BubbleChatMessageTypes
  644.                 return AllowedMessageTypes
  645.             end
  646.         end
  647.         local chatConstants = clientChatModules:FindFirstChild("ChatConstants")
  648.         if chatConstants then
  649.             chatConstants = require(chatConstants)
  650.             AllowedMessageTypes = {chatConstants.MessageTypeDefault, chatConstants.MessageTypeWhisper}
  651.         end
  652.         return AllowedMessageTypes
  653.     end
  654.     return {"Message", "Whisper"}
  655. end
  656.  
  657. function checkAllowedMessageType(messageData)
  658.     local allowedMessageTypes = getAllowedMessageTypes()
  659.     for i = 1, #allowedMessageTypes do
  660.         if allowedMessageTypes[i] == messageData.MessageType then
  661.             return true
  662.         end
  663.     end
  664.     return false
  665. end
  666.  
  667. local ChatEvents = ReplicatedStorage:WaitForChild("DefaultChatSystemChatEvents")
  668. local OnMessageDoneFiltering = ChatEvents:WaitForChild("OnMessageDoneFiltering")
  669. local OnNewMessage = ChatEvents:WaitForChild("OnNewMessage")
  670.  
  671. OnNewMessage.OnClientEvent:connect(function(messageData, channelName)
  672.     if not checkAllowedMessageType(messageData) then
  673.         return
  674.     end
  675.  
  676.     local sender = findPlayer(messageData.FromSpeaker)
  677.     if not sender then
  678.         return
  679.     end
  680.  
  681.     if not messageData.IsFiltered or messageData.FromSpeaker == LocalPlayer.Name then
  682.         if messageData.FromSpeaker ~= LocalPlayer.Name or this:ShowOwnFilteredMessage() then
  683.             return
  684.         end
  685.     end
  686.  
  687.     this:OnPlayerChatMessage(sender, messageData.Message, nil)
  688. end)
  689.  
  690. OnMessageDoneFiltering.OnClientEvent:connect(function(messageData, channelName)
  691.     if not checkAllowedMessageType(messageData) then
  692.         return
  693.     end
  694.  
  695.     local sender = findPlayer(messageData.FromSpeaker)
  696.     if not sender then
  697.         return
  698.     end
  699.  
  700.     if messageData.FromSpeaker == LocalPlayer.Name and not this:ShowOwnFilteredMessage() then
  701.         return
  702.     end
  703.  
  704.     this:OnPlayerChatMessage(sender, messageData.Message, nil)
  705. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement