SHARE
TWEET

Untitled

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