Advertisement
Derek1017

Test

May 10th, 2015
287
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 71.12 KB | None | 0 0
  1. --[[
  2.     // FileName: ChatScript.lua
  3.     // Written by: SolarCrane
  4.     // Description: Code for lua side chat on ROBLOX.
  5. ]]
  6.  
  7. --[[ CONSTANTS ]]
  8.  
  9. -- NOTE: IF YOU WANT TO USE THIS CHAT SCRIPT IN YOUR OWN GAME:
  10. -- 1) COPY THE CONTENTS OF THIS FILE INTO A LOCALSCRIPT THAT YOU MADE IN STARTERGUI
  11. -- 2) SET THE FOLLOWING TWO VARIABLES TO TRUE
  12. -- 3) CONFIGURE YOUR PLACE ON THE WEBSITE TO USE BUBBLE-CHAT
  13. local FORCE_CHAT_GUI = false
  14. local NON_CORESCRIPT_MODE = false
  15. -- 4) (OPTIONAL) PUT THE FOLLOWING LINE IN A SERVER SCRIPT TO MAKE CHAT PERSIST THROUGH RESPAWNING
  16. --  game:GetService('StarterGui').ResetPlayerGuiOnSpawn = false
  17. ---------------------------------
  18.  
  19. local MESSAGES_FADE_OUT_TIME = 30
  20. local MAX_BLOCKLIST_SIZE = 50
  21. local MAX_UDIM_SIZE = 2^15 - 1
  22.  
  23. local CHAT_COLORS =
  24. {
  25.     Color3.new(253/255, 41/255, 67/255), -- BrickColor.new("Bright red").Color,
  26.     Color3.new(1/255, 162/255, 255/255), -- BrickColor.new("Bright blue").Color,
  27.     Color3.new(2/255, 184/255, 87/255), -- BrickColor.new("Earth green").Color,
  28.     BrickColor.new("Bright violet").Color,
  29.     BrickColor.new("Bright orange").Color,
  30.     BrickColor.new("Bright yellow").Color,
  31.     BrickColor.new("Light reddish violet").Color,
  32.     BrickColor.new("Brick yellow").Color,
  33. }
  34.  
  35. local ADMIN_LIST = {
  36.     ['23873450'] = true, -- Derek1017
  37.     ['32345429'] = true, -- Rbadam
  38.     ['48453004'] = true, -- Adamintygum
  39.     ['57705391'] = true, -- androidtest
  40.     ['58491921'] = true, -- RobloxFrenchie
  41.     ['29341155'] = true, -- JacksSmirkingRevenge
  42.     ['60629145'] = true, -- Mandaari
  43.     ['6729993'] = true, -- vaiobot
  44.     ['9804369'] = true, -- Goddessnoob
  45.     ['67906358'] = true, -- Thr33pakShak3r
  46.     ['41101356'] = true, -- effward
  47.     ['29667843'] = true, -- Blockhaak
  48.     ['26076267'] = true, -- Drewbda
  49.     ['65171466'] = true, -- triptych999
  50.     ['264635'] = true, -- Tone
  51.     ['59257875'] = true, -- fasterbuilder19
  52.     ['30068452'] = true, -- Zeuxcg
  53.     ['53627251'] = true, -- concol2
  54.     ['56449'] = true, -- ReeseMcBlox
  55.     ['7210880'] = true, -- Jeditkacheff
  56.     ['35187797'] = true, -- ChiefJustus
  57.     ['21964644'] = true, -- Ellissar
  58.     ['63971416'] = true, -- geekndestroy
  59.     ['111627'] = true, -- Noob007
  60.     ['482238'] = true, -- Limon
  61.     ['39861325'] = true, -- hawkington
  62.     ['32580099'] = true, -- Tabemono
  63.     ['504316'] = true, -- BrightEyes
  64.     ['35825637'] = true, -- Monsterinc3D
  65.     ['55311255'] = true, -- IsolatedEvent
  66.     ['48988254'] = true, -- CountOnConnor
  67.     ['357346'] = true, -- Scubasomething
  68.     ['28969907'] = true, -- OnlyTwentyCharacters
  69.     ['17707636'] = true, -- LordRugdumph
  70.     ['26714811'] = true, -- bellavour
  71.     ['24941'] = true, -- david.baszucki
  72.     ['13057592'] = true, -- ibanez2189
  73.     ['66766775'] = true, -- ConvexHero
  74.     ['13268404'] = true, -- Sorcus
  75.     ['26065068'] = true, -- DeeAna00
  76.     ['4108667'] = true, -- TheLorekt
  77.     ['605367'] = true, -- MSE6
  78.     ['28350010'] = true, -- CorgiParade
  79.     ['1636196'] = true, -- Varia
  80.     ['27861308'] = true, -- 4runningwolves
  81.     ['26699190'] = true, -- pulmoesflor
  82.     ['9733258'] = true, -- Olive71
  83.     ['2284059'] = true, -- groundcontroll2
  84.     ['28080592'] = true, -- GuruKrish
  85.     ['28137935'] = true, -- Countvelcro
  86.     ['25964666'] = true, -- IltaLumi
  87.     ['31221099'] = true, -- juanjuan23
  88.     ['13965343'] = true, -- OstrichSized
  89.     ['541489'] = true, -- jackintheblox
  90.     ['38324232'] = true, -- SlingshotJunkie
  91.     ['146569'] = true, -- gordonrox24
  92.     ['61666252'] = true, -- sharpnine
  93.     ['25540124'] = true, -- Motornerve
  94.     ['29044576'] = true, -- watchmedogood
  95.     ['49626068'] = true, -- jmargh
  96.     ['57352126'] = true, -- JayKorean
  97.     ['25682044'] = true, -- Foyle
  98.     ['1113299'] = true, -- MajorTom4321
  99.     ['30598693'] = true, -- supernovacaine
  100.     ['1311'] = true, -- FFJosh
  101.     ['23603273'] = true, -- Sickenedmonkey
  102.     ['28568151'] = true, -- Doughtless
  103.     ['8298697'] = true, -- KBUX
  104.     ['39871898'] = true, -- totallynothere
  105.     ['57708043'] = true, -- ErzaStar
  106.     ['22'] = true, -- Keith
  107.     ['2430782'] = true, -- Chro
  108.     ['29373363'] = true, -- SolarCrane
  109.     ['29116915'] = true, -- GloriousSalt
  110.     ['6783205'] = true, -- UristMcSparks
  111.     ['62155769'] = true, -- ITOlaurEN
  112.     ['24162607'] = true, -- Malcomso
  113.     ['66692187'] = true, -- HeySeptember
  114.     ['80254'] = true, -- Stickmasterluke
  115.     ['66093461'] = true, -- chefdeletat
  116.     ['62968051'] = true, -- windlight13
  117.     ['80119'] = true, -- Stravant
  118.     ['61890000'] = true, -- imaginationsensation
  119.     ['916'] = true, -- Matt Dusek
  120.     ['4550725'] = true, -- CrimmsonGhost
  121.     ['59737068'] = true, -- Mcrtest
  122.     ['5600283'] = true, -- Seranok
  123.     ['48656806'] = true, -- maxvee
  124.     ['48656806'] = true, -- Coatp0cketninja
  125.     ['35231885'] = true, -- Screenme
  126.     ['55958416'] = true, -- b1tsh1ft
  127.     ['51763936'] = true, -- ConvexRumbler
  128.     ['59638684'] = true, -- mpliner476
  129.     ['44231609'] = true, -- Totbl
  130.     ['16906083'] = true, -- Aquabot8
  131.     ['23984372'] = true, -- grossinger
  132.     ['13416513'] = true, -- Merely
  133.     ['27416429'] = true, -- CDakkar
  134.     ['46526337'] = true, -- logitek00
  135.     ['21969613'] = true, -- Siekiera
  136.     ['39488230'] = true, -- Robloxkidsaccount
  137.     ['60425210'] = true, -- flotsamthespork
  138.     ['16732061'] = true, -- Soggoth
  139.     ['33904052'] = true, -- Phil
  140.     ['39882028'] = true, -- OrcaSparkles
  141.     ['62060462'] = true, -- skullgoblin
  142.     ['29044708'] = true, -- RickROSStheB0SS
  143.     ['15782010'] = true, -- ArgonPirate
  144.     ['6949935'] = true, -- NobleDragon
  145.     ['41256555'] = true, -- Squidcod
  146.     ['16150324'] = true, -- Raeglyn
  147.     ['24419770'] = true, -- Xerolayne
  148.     ['20396599'] = true, -- Robloxsai
  149.     ['55579189'] = true, -- Briarroze
  150.     ['21641566'] = true, -- hawkeyebandit
  151.     ['39871292'] = true, -- DapperBuffalo
  152.     ['48725400'] = true, -- Vukota
  153.     ['60880618'] = true, -- swiftstone
  154.     ['8736269'] = true, -- Gemlocker
  155.     ['17199995'] = true, -- Tarabyte
  156.     ['6983145'] = true, -- Timobius
  157.     ['20048521'] = true, -- Tobotrobot
  158.     ['1644345'] = true, -- Foster008
  159.     ['33067469'] = true, -- Twberg
  160.     ['57741156'] = true, -- DarthVaden
  161.     ['51164101'] = true, -- Khanovich
  162.     ['61380399'] = true, -- oLEFTo
  163.     ['39876101'] = true, -- CodeWriter
  164.     ['23598967'] = true, -- VladTheFirst
  165.     ['39299049'] = true, -- Phaedre
  166.     ['39855185'] = true, -- gorroth
  167.     ['61004766'] = true, -- jynj1984
  168.     ['10261020'] = true, -- RoboYZ
  169.     ['44564747'] = true, -- ZodiacZak
  170. }
  171. --[[ END OF CONSTANTS ]]
  172.  
  173. --[[ SERVICES ]]
  174. local RunService = game:GetService('RunService')
  175. local CoreGuiService = game:GetService('CoreGui')
  176. local PlayersService = game:GetService('Players')
  177. local DebrisService = game:GetService('Debris')
  178. local GuiService = game:GetService('GuiService')
  179. local InputService = game:GetService('UserInputService')
  180. local StarterGui = game:GetService('StarterGui')
  181. --[[ END OF SERVICES ]]
  182.  
  183. --[[ SCRIPT VARIABLES ]]
  184.  
  185. -- I am not fond of waiting at the top of the script here...
  186. while PlayersService.LocalPlayer == nil do PlayersService.ChildAdded:wait() end
  187. local Player = PlayersService.LocalPlayer
  188. -- GuiRoot will act as the top-node for parenting GUIs
  189. local GuiRoot = nil
  190. if NON_CORESCRIPT_MODE then
  191.     GuiRoot = Instance.new("ScreenGui")
  192.     GuiRoot.Name = "RobloxGui"
  193.     GuiRoot.Parent = Player:WaitForChild('PlayerGui')
  194. else
  195.     GuiRoot = CoreGuiService:WaitForChild('RobloxGui')
  196. end
  197. --[[ END OF SCRIPT VARIABLES ]]
  198.  
  199. local function GetBlockedUsersFlag()
  200.     local blockUserFlagSuccess, blockUserFlagFlagValue = pcall(function() return settings():GetFFlag("BlockUsersInLuaChat") end)
  201.     return blockUserFlagSuccess and blockUserFlagFlagValue == true
  202. end
  203.  
  204. local function GetUsePlayerInGroupFlag()
  205.     local flagSuccess, flagValue = pcall(function() return settings():GetFFlag("UsePlayerInGroupLuaChat") end)
  206.     return flagSuccess and flagValue == true
  207. end
  208.  
  209. local Util = {}
  210. do
  211.     -- Check if we are running on a touch device
  212.     function Util.IsTouchDevice()
  213.         local touchEnabled = false
  214.         pcall(function() touchEnabled = InputService.TouchEnabled end)
  215.         return touchEnabled
  216.     end
  217.  
  218.     function Util.Create(instanceType)
  219.         return function(data)
  220.             local obj = Instance.new(instanceType)
  221.             for k, v in pairs(data) do
  222.                 if type(k) == 'number' then
  223.                     v.Parent = obj
  224.                 else
  225.                     obj[k] = v
  226.                 end
  227.             end
  228.             return obj
  229.         end
  230.     end
  231.  
  232.     function Util.Clamp(low, high, input)
  233.         return math.max(low, math.min(high, input))
  234.     end
  235.  
  236.     function Util.Linear(t, b, c, d)
  237.         if t >= d then return b + c end
  238.  
  239.         return c*t/d + b
  240.     end
  241.  
  242.     function Util.EaseOutQuad(t, b, c, d)
  243.         if t >= d then return b + c end
  244.  
  245.         t = t/d;
  246.         return -c * t*(t-2) + b
  247.     end
  248.  
  249.     function Util.EaseInOutQuad(t, b, c, d)
  250.         if t >= d then return b + c end
  251.  
  252.         t = t / (d/2);
  253.         if (t < 1) then return c/2*t*t + b end;
  254.         t = t - 1;
  255.         return -c/2 * (t*(t-2) - 1) + b;
  256.     end
  257.  
  258.     function Util.PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc)
  259.         local this = {}
  260.         this.StartTime = tick()
  261.         this.EndTime = this.StartTime + duration
  262.         this.Cancelled = false
  263.  
  264.         local finished = false
  265.         local percentComplete = 0
  266.         spawn(function()
  267.             local now = tick()
  268.             while now < this.EndTime and instance do
  269.                 if this.Cancelled then
  270.                     return
  271.                 end
  272.                 instance[prop] = easingFunc(now - this.StartTime, start, final - start, duration)
  273.                 percentComplete = Util.Clamp(0, 1, (now - this.StartTime) / duration)
  274.                 RunService.RenderStepped:wait()
  275.                 now = tick()
  276.             end
  277.             if this.Cancelled == false and instance then
  278.                 instance[prop] = final
  279.                 finished = true
  280.                 percentComplete = 1
  281.                 if cbFunc then
  282.                     cbFunc()
  283.                 end
  284.             end
  285.         end)
  286.  
  287.         function this:GetPercentComplete()
  288.             return percentComplete
  289.         end
  290.  
  291.         function this:IsFinished()
  292.             return finished
  293.         end
  294.  
  295.         function this:Cancel()
  296.             this.Cancelled = true
  297.         end
  298.  
  299.         return this
  300.     end
  301.  
  302.     function Util.Signal()
  303.         local sig = {}
  304.  
  305.         local mSignaler = Instance.new('BindableEvent')
  306.  
  307.         local mArgData = nil
  308.         local mArgDataCount = nil
  309.  
  310.         function sig:fire(...)
  311.             mArgData = {...}
  312.             mArgDataCount = select('#', ...)
  313.             mSignaler:Fire()
  314.         end
  315.  
  316.         function sig:connect(f)
  317.             if not f then error("connect(nil)", 2) end
  318.             return mSignaler.Event:connect(function()
  319.                 f(unpack(mArgData, 1, mArgDataCount))
  320.             end)
  321.         end
  322.  
  323.         function sig:wait()
  324.             mSignaler.Event:wait()
  325.             assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.")
  326.             return unpack(mArgData, 1, mArgDataCount)
  327.         end
  328.  
  329.         return sig
  330.     end
  331.  
  332.     function Util.DisconnectEvent(conn)
  333.         if conn then
  334.             conn:disconnect()
  335.         end
  336.         return nil
  337.     end
  338.  
  339.     function Util.SetGUIInsetBounds(x, y)
  340.         local success, _ = pcall(function() GuiService:SetGlobalGuiInset(0, x, 0, y) end)
  341.         if not success then
  342.             pcall(function() GuiService:SetGlobalSizeOffsetPixel(-x, -y) end) -- Legacy GUI-offset function
  343.         end
  344.     end
  345.  
  346.     local baseUrl = game:GetService("ContentProvider").BaseUrl:lower()
  347.     baseUrl = string.gsub(baseUrl,"/m.","/www.") --mobile site does not work for this stuff!
  348.     function Util.GetSecureApiBaseUrl()
  349.         local secureApiUrl = baseUrl
  350.         secureApiUrl = string.gsub(secureApiUrl,"http","https")
  351.         secureApiUrl = string.gsub(secureApiUrl,"www","api")
  352.         return secureApiUrl
  353.     end
  354.  
  355.     function Util.GetPlayerByName(playerName)
  356.         -- O(n), may be faster if I store a reverse hash from the players list; can't trust FindFirstChild in PlayersService because anything can be parented to there.
  357.         local lowerName = string.lower(playerName)
  358.         for _, player in pairs(PlayersService:GetPlayers()) do
  359.             if string.lower(player.Name) == lowerName then
  360.                 return player
  361.             end
  362.         end
  363.         return nil -- Found no player
  364.     end
  365.  
  366.     local adminCache = {}
  367.     function Util.IsPlayerAdminAsync(player)
  368.         local userId = player and player.userId
  369.         if userId then
  370.             if GetUsePlayerInGroupFlag() then
  371.                 if adminCache[userId] == nil then
  372.                     local isAdmin = false
  373.                     -- Many things can error is the IsInGroup check
  374.                     pcall(function()
  375.                         isAdmin = player:IsInGroup(1200769)
  376.                     end)
  377.                     adminCache[userId] = isAdmin
  378.                 end
  379.                 return adminCache[userId]
  380.             end
  381.             return ADMIN_LIST[tostring(userId)]
  382.         end
  383.         return false
  384.     end
  385.  
  386.     local function GetNameValue(pName)
  387.         local value = 0
  388.         for index = 1, #pName do
  389.             local cValue = string.byte(string.sub(pName, index, index))
  390.             local reverseIndex = #pName - index + 1
  391.             if #pName%2 == 1 then
  392.                 reverseIndex = reverseIndex - 1
  393.             end
  394.             if reverseIndex%4 >= 2 then
  395.                 cValue = -cValue
  396.             end
  397.             value = value + cValue
  398.         end
  399.         return value
  400.     end
  401.  
  402.     function Util.ComputeChatColor(pName)
  403.         return CHAT_COLORS[(GetNameValue(pName) % #CHAT_COLORS) + 1]
  404.     end
  405.  
  406.     -- This is a memo-izing function
  407.     local testLabel = Instance.new('TextLabel')
  408.     testLabel.TextWrapped = true;
  409.     testLabel.Position = UDim2.new(1,0,1,0)
  410.     testLabel.Parent = GuiRoot -- Note: We have to parent it to check TextBounds
  411.     -- The TextSizeCache table looks like this Text->Font->sizeBounds->FontSize
  412.     local TextSizeCache = {}
  413.     function Util.GetStringTextBounds(text, font, fontSize, sizeBounds)
  414.         -- If no sizeBounds are specified use some huge number
  415.         sizeBounds = sizeBounds or false
  416.         if not TextSizeCache[text] then
  417.             TextSizeCache[text] = {}
  418.         end
  419.         if not TextSizeCache[text][font] then
  420.             TextSizeCache[text][font] = {}
  421.         end
  422.         if not TextSizeCache[text][font][sizeBounds] then
  423.             TextSizeCache[text][font][sizeBounds] = {}
  424.         end
  425.         if not TextSizeCache[text][font][sizeBounds][fontSize] then
  426.             testLabel.Text = text
  427.             testLabel.Font = font
  428.             testLabel.FontSize = fontSize
  429.             if sizeBounds then
  430.                 testLabel.TextWrapped = true;
  431.                 testLabel.Size = sizeBounds
  432.             else
  433.                 testLabel.TextWrapped = false;
  434.             end
  435.             TextSizeCache[text][font][sizeBounds][fontSize] = testLabel.TextBounds
  436.         end
  437.         return TextSizeCache[text][font][sizeBounds][fontSize]
  438.     end
  439. end
  440.  
  441. local SelectChatModeEvent = Util.Signal()
  442. local SelectPlayerEvent = Util.Signal()
  443.  
  444. local function CreateChatMessage()
  445.     local this = {}
  446.     this.FadeRoutines = {}
  447.  
  448.     function this:OnResize()
  449.         -- Nothing!
  450.     end
  451.  
  452.     function this:FadeIn()
  453.         local gui = this:GetGui()
  454.         if gui then
  455.             gui.Visible = true
  456.         end
  457.     end
  458.  
  459.     function this:FadeOut()
  460.         local gui = this:GetGui()
  461.         if gui then
  462.             gui.Visible = false
  463.         end
  464.     end
  465.  
  466.     function this:GetGui()
  467.         return this.Container
  468.     end
  469.  
  470.     function this:Destroy()
  471.         if this.Container ~= nil then
  472.             this.Container:Destroy()
  473.             this.Container = nil
  474.         end
  475.         if this.FadeRoutines then
  476.             for _, routine in pairs(this.FadeRoutines) do
  477.                 routine:Cancel()
  478.             end
  479.             this.FadeRoutines = {}
  480.         end
  481.     end
  482.  
  483.     return this
  484. end
  485.  
  486. local function CreateSystemChatMessage(settings, chattedMessage)
  487.     local this = CreateChatMessage()
  488.  
  489.     this.Settings = settings
  490.     this.chatMessage = chattedMessage
  491.  
  492.     function this:OnResize(containerSize)
  493.         if this.Container and this.ChatMessage then
  494.             this.Container.Size = UDim2.new(1,0,0,1000)
  495.             local textHeight = this.ChatMessage.TextBounds.Y
  496.             this.Container.Size = UDim2.new(1,0,0,textHeight + 1)
  497.             return textHeight
  498.         end
  499.     end
  500.  
  501.     function this:FadeIn()
  502.         local gui = this:GetGui()
  503.         if gui then
  504.             gui.Visible = true
  505.             for _, routine in pairs(this.FadeRoutines) do
  506.                 routine:Cancel()
  507.             end
  508.             this.FadeRoutines = {}
  509.             local tweenableObjects = {
  510.                 this.ChatMessage;
  511.             }
  512.             for _, object in pairs(tweenableObjects) do
  513.                 object.TextTransparency = 0;
  514.                 object.TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  515.             end
  516.         end
  517.     end
  518.  
  519.     function this:FadeOut(instant)
  520.         local gui = this:GetGui()
  521.         if gui then
  522.             if instant then
  523.                 gui.Visible = false
  524.             else
  525.                 local tweenableObjects = {
  526.                     this.ChatMessage;
  527.                 }
  528.                 for _, object in pairs(tweenableObjects) do
  529.                     table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear))
  530.                     table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear))
  531.                 end
  532.             end
  533.         end
  534.     end
  535.  
  536.     local function CreateMessageGuiElement()
  537.         local systemMesasgeDisplayText = this.chatMessage or ""
  538.         local systemMessageSize = Util.GetStringTextBounds(systemMesasgeDisplayText, this.Settings.Font, this.Settings.FontSize, UDim2.new(0, 400, 0, 1000))
  539.  
  540.         local container = Util.Create'Frame'
  541.         {
  542.             Name = 'MessageContainer';
  543.             Position = UDim2.new(0, 0, 0, 0);
  544.             ZIndex = 1;
  545.             BackgroundColor3 = Color3.new(0, 0, 0);
  546.             BackgroundTransparency = 1;
  547.         };
  548.  
  549.             local chatMessage = Util.Create'TextLabel'
  550.             {
  551.                 Name = 'SystemChatMessage';
  552.                 Position = UDim2.new(0, 0, 0, 0);
  553.                 Size = UDim2.new(1, 0, 1, 0);
  554.                 Text = systemMesasgeDisplayText;
  555.                 ZIndex = 1;
  556.                 BackgroundColor3 = Color3.new(0, 0, 0);
  557.                 BackgroundTransparency = 1;
  558.                 TextXAlignment = Enum.TextXAlignment.Left;
  559.                 TextYAlignment = Enum.TextYAlignment.Top;
  560.                 TextWrapped = true;
  561.                 TextColor3 = this.Settings.DefaultMessageTextColor;
  562.                 FontSize = this.Settings.FontSize;
  563.                 Font = this.Settings.Font;
  564.                 TextStrokeColor3 = this.Settings.TextStrokeColor;
  565.                 TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  566.                 Parent = container;
  567.             };
  568.  
  569.         container.Size = UDim2.new(1, 0, 0, systemMessageSize.Y + 1);
  570.         this.Container = container
  571.         this.ChatMessage = chatMessage
  572.     end
  573.  
  574.     CreateMessageGuiElement()
  575.  
  576.     return this
  577. end
  578.  
  579. local function CreatePlayerChatMessage(settings, playerChatType, sendingPlayer, chattedMessage, receivingPlayer)
  580.     local this = CreateChatMessage()
  581.  
  582.     this.Settings = settings
  583.     this.PlayerChatType = playerChatType
  584.     this.SendingPlayer = sendingPlayer
  585.     this.RawMessageContent = chattedMessage
  586.     this.ReceivingPlayer = receivingPlayer
  587.     this.ReceivedTime = tick()
  588.  
  589.     this.Neutral = this.SendingPlayer and this.SendingPlayer.Neutral or true
  590.     this.TeamColor = this.SendingPlayer and this.SendingPlayer.TeamColor or BrickColor.new("White")
  591.  
  592.     function this:OnResize(containerSize)
  593.         if this.Container and this.ChatMessage then
  594.             this.Container.Size = UDim2.new(1,0,0,1000)
  595.             local textHeight = this.ChatMessage.TextBounds.Y
  596.             this.Container.Size = UDim2.new(1,0,0,textHeight + 1)
  597.             return textHeight
  598.         end
  599.     end
  600.  
  601.     function this:FormatMessage()
  602.         local result = ""
  603.         if this.RawMessageContent then
  604.             local message = this.RawMessageContent
  605.             result = message
  606.         end
  607.         return result
  608.     end
  609.  
  610.     function this:FormatChatType()
  611.         if this.PlayerChatType then
  612.             if this.PlayerChatType == Enum.PlayerChatType.All then
  613.                 --return "[All]"
  614.             elseif this.PlayerChatType == Enum.PlayerChatType.Team then
  615.                 return "[Team]"
  616.             elseif this.PlayerChatType == Enum.PlayerChatType.Whisper then
  617.                 -- nothing!
  618.             end
  619.         end
  620.     end
  621.  
  622.     function this:FormatPlayerNameText()
  623.         local playerName = ""
  624.         -- If we are sending a whisper to someone, then we should show their name
  625.         if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer and this.SendingPlayer == Player then
  626.             playerName = (this.ReceivingPlayer and this.ReceivingPlayer.Name or "")
  627.         else
  628.             playerName = (this.SendingPlayer and this.SendingPlayer.Name or "")
  629.         end
  630.         return "[" ..  playerName .. "]:"
  631.     end
  632.  
  633.     function this:FadeIn()
  634.         local gui = this:GetGui()
  635.         if gui then
  636.             gui.Visible = true
  637.             for _, routine in pairs(this.FadeRoutines) do
  638.                 routine:Cancel()
  639.             end
  640.             this.FadeRoutines = {}
  641.             local tweenableObjects = {
  642.                     this.WhisperToText;
  643.                     this.WhisperFromText;
  644.                     this.ChatModeButton;
  645.                     this.UserNameButton;
  646.                     this.ChatMessage;
  647.                 }
  648.             for _, object in pairs(tweenableObjects) do
  649.                 object.TextTransparency = 0;
  650.                 object.TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  651.                 object.Active = true
  652.             end
  653.             if this.UserNameDot then
  654.                 this.UserNameDot.ImageTransparency = 0
  655.             end
  656.         end
  657.     end
  658.  
  659.     function this:FadeOut(instant)
  660.         local gui = this:GetGui()
  661.         if gui then
  662.             if instant then
  663.                 gui.Visible = false
  664.             else
  665.                 local tweenableObjects = {
  666.                     this.WhisperToText;
  667.                     this.WhisperFromText;
  668.                     this.ChatModeButton;
  669.                     this.UserNameButton;
  670.                     this.ChatMessage;
  671.                 }
  672.                 for _, object in pairs(tweenableObjects) do
  673.                     table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear))
  674.                     table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear))
  675.                     object.Active = false
  676.                 end
  677.                 if this.UserNameDot then
  678.                     table.insert(this.FadeRoutines, Util.PropertyTweener(this.UserNameDot, 'ImageTransparency', this.UserNameDot.ImageTransparency, 1, 1, Util.Linear))
  679.                 end
  680.             end
  681.         end
  682.     end
  683.  
  684.     function this:Destroy()
  685.         if this.Container ~= nil then
  686.             this.Container:Destroy()
  687.             this.Container = nil
  688.         end
  689.         this.ClickedOnModeConn = Util.DisconnectEvent(this.ClickedOnModeConn)
  690.         this.ClickedOnPlayerConn = Util.DisconnectEvent(this.ClickedOnPlayerConn)
  691.     end
  692.  
  693.     local function CreateMessageGuiElement()
  694.         local toMesasgeDisplayText = "To "
  695.         local toMessageSize = Util.GetStringTextBounds(toMesasgeDisplayText, this.Settings.Font, this.Settings.FontSize)
  696.         local fromMesasgeDisplayText = "From "
  697.         local fromMessageSize = Util.GetStringTextBounds(fromMesasgeDisplayText, this.Settings.Font, this.Settings.FontSize)
  698.         local chatTypeDisplayText = this:FormatChatType()
  699.         local chatTypeSize = chatTypeDisplayText and Util.GetStringTextBounds(chatTypeDisplayText, this.Settings.Font, this.Settings.FontSize) or Vector2.new(0,0)
  700.         local playerNameDisplayText = this:FormatPlayerNameText()
  701.         local playerNameSize = Util.GetStringTextBounds(playerNameDisplayText, this.Settings.Font, this.Settings.FontSize)
  702.  
  703.         local singleSpaceSize = Util.GetStringTextBounds(" ", this.Settings.Font, this.Settings.FontSize)
  704.         local numNeededSpaces = math.ceil(playerNameSize.X / singleSpaceSize.X) + 1
  705.         local chatMessageDisplayText = string.rep(" ", numNeededSpaces) .. this:FormatMessage()
  706.         local chatMessageSize = Util.GetStringTextBounds(chatMessageDisplayText, this.Settings.Font, this.Settings.FontSize, UDim2.new(0, 400 - 5 - playerNameSize.X, 0, 1000))
  707.  
  708.  
  709.         local playerColor = this.Settings.DefaultMessageTextColor
  710.         if this.SendingPlayer then
  711.             if this.PlayerChatType == Enum.PlayerChatType.Whisper then
  712.                 if this.SendingPlayer == Player and this.ReceivingPlayer then
  713.                     playerColor = Util.ComputeChatColor(this.ReceivingPlayer.Name)
  714.                 else
  715.                     playerColor = Util.ComputeChatColor(this.SendingPlayer.Name)
  716.                 end
  717.             else
  718.                 if this.SendingPlayer.Neutral then
  719.                     playerColor = Util.ComputeChatColor(this.SendingPlayer.Name)
  720.                 else
  721.                     playerColor = this.SendingPlayer.TeamColor.Color
  722.                 end
  723.             end
  724.         end
  725.  
  726.         local container = Util.Create'Frame'
  727.         {
  728.             Name = 'MessageContainer';
  729.             Position = UDim2.new(0, 0, 0, 0);
  730.             ZIndex = 1;
  731.             BackgroundColor3 = Color3.new(0, 0, 0);
  732.             BackgroundTransparency = 1;
  733.         };
  734.             local xOffset = 0
  735.  
  736.             if this.SendingPlayer and this.SendingPlayer == Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then
  737.                 local whisperToText = Util.Create'TextLabel'
  738.                 {
  739.                     Name = 'WhisperTo';
  740.                     Position = UDim2.new(0, 0, 0, 0);
  741.                     Size = UDim2.new(0, toMessageSize.X, 0, toMessageSize.Y);
  742.                     Text = toMesasgeDisplayText;
  743.                     ZIndex = 1;
  744.                     BackgroundColor3 = Color3.new(0, 0, 0);
  745.                     BackgroundTransparency = 1;
  746.                     TextXAlignment = Enum.TextXAlignment.Left;
  747.                     TextYAlignment = Enum.TextYAlignment.Top;
  748.                     TextWrapped = true;
  749.                     TextColor3 = this.Settings.DefaultMessageTextColor;
  750.                     FontSize = this.Settings.FontSize;
  751.                     Font = this.Settings.Font;
  752.                     TextStrokeColor3 = this.Settings.TextStrokeColor;
  753.                     TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  754.                     Parent = container;
  755.                 };
  756.                 xOffset = xOffset + toMessageSize.X
  757.                 this.WhisperToText = whisperToText
  758.             elseif this.SendingPlayer and this.SendingPlayer ~= Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then
  759.                 local whisperFromText = Util.Create'TextLabel'
  760.                 {
  761.                     Name = 'WhisperFromText';
  762.                     Position = UDim2.new(0, 0, 0, 0);
  763.                     Size = UDim2.new(0, fromMessageSize.X, 0, fromMessageSize.Y);
  764.                     Text = fromMesasgeDisplayText;
  765.                     ZIndex = 1;
  766.                     BackgroundColor3 = Color3.new(0, 0, 0);
  767.                     BackgroundTransparency = 1;
  768.                     TextXAlignment = Enum.TextXAlignment.Left;
  769.                     TextYAlignment = Enum.TextYAlignment.Top;
  770.                     TextWrapped = true;
  771.                     TextColor3 = this.Settings.DefaultMessageTextColor;
  772.                     FontSize = this.Settings.FontSize;
  773.                     Font = this.Settings.Font;
  774.                     TextStrokeColor3 = this.Settings.TextStrokeColor;
  775.                     TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  776.                     Parent = container;
  777.                 };
  778.                 xOffset = xOffset + fromMessageSize.X
  779.                 this.WhisperFromText = whisperFromText
  780.             else
  781.                 local userNameDot = Util.Create'ImageLabel'
  782.                 {
  783.                     Name = "UserNameDot";
  784.                     Size = UDim2.new(0, 14, 0, 14);
  785.                     BackgroundTransparency = 1;
  786.                     Position = UDim2.new(0, 0, 0, math.max(0, ((playerNameSize and playerNameSize.Y or 0) - 14)/2) + 2);
  787.                     BorderSizePixel = 0;
  788.                     Image = "rbxasset://textures/ui/chat_teamButton.png";
  789.                     ImageColor3 = playerColor;
  790.                     Parent = container;
  791.                 }
  792.                 xOffset = xOffset + 14 + 3
  793.                 this.UserNameDot = userNameDot
  794.             end
  795.         if chatTypeDisplayText then
  796.             local chatModeButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton')
  797.             {
  798.                 Name = 'ChatMode';
  799.                 BackgroundTransparency = 1;
  800.                 ZIndex = 2;
  801.                 Text = chatTypeDisplayText;
  802.                 TextColor3 = this.Settings.DefaultMessageTextColor;
  803.                 Position = UDim2.new(0, xOffset, 0, 0);
  804.                 TextXAlignment = Enum.TextXAlignment.Left;
  805.                 TextYAlignment = Enum.TextYAlignment.Top;
  806.                 FontSize = this.Settings.FontSize;
  807.                 Font = this.Settings.Font;
  808.                 Size = UDim2.new(0, chatTypeSize.X, 0, chatTypeSize.Y);
  809.                 TextStrokeColor3 = this.Settings.TextStrokeColor;
  810.                 TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  811.                 Parent = container
  812.             }
  813.             if chatModeButton:IsA('TextButton') then
  814.                 this.ClickedOnModeConn = chatModeButton.MouseButton1Click:connect(function()
  815.                     SelectChatModeEvent:fire(this.PlayerChatType)
  816.                 end)
  817.             end
  818.             if this.PlayerChatType == Enum.PlayerChatType.Team then
  819.                 chatModeButton.TextColor3 = playerColor
  820.             end
  821.             xOffset = xOffset + chatTypeSize.X + 1
  822.             this.ChatModeButton = chatModeButton
  823.         end
  824.             local userNameButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton')
  825.             {
  826.                 Name = 'PlayerName';
  827.                 BackgroundTransparency = 1;
  828.                 ZIndex = 2;
  829.                 Text = playerNameDisplayText;
  830.                 TextColor3 = playerColor;
  831.                 Position = UDim2.new(0, xOffset, 0, 0);
  832.                 TextXAlignment = Enum.TextXAlignment.Left;
  833.                 TextYAlignment = Enum.TextYAlignment.Top;
  834.                 FontSize = this.Settings.FontSize;
  835.                 Font = this.Settings.Font;
  836.                 Size = UDim2.new(0, playerNameSize.X, 0, playerNameSize.Y);
  837.                 TextStrokeColor3 = this.Settings.TextStrokeColor;
  838.                 TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  839.                 Parent = container
  840.             }
  841.             if userNameButton:IsA('TextButton') then
  842.                 this.ClickedOnPlayerConn = userNameButton.MouseButton1Click:connect(function()
  843.                     if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer == Player and this.ReceivingPlayer then
  844.                         SelectPlayerEvent:fire(this.ReceivingPlayer)
  845.                     else
  846.                         SelectPlayerEvent:fire(this.SendingPlayer)
  847.                     end
  848.                 end)
  849.             end
  850.  
  851.             local chatMessage = Util.Create'TextLabel'
  852.             {
  853.                 Name = 'ChatMessage';
  854.                 Position = UDim2.new(0, xOffset, 0, 0);
  855.                 Size = UDim2.new(1, -xOffset, 1, 0);
  856.                 Text = chatMessageDisplayText;
  857.                 ZIndex = 1;
  858.                 BackgroundColor3 = Color3.new(0, 0, 0);
  859.                 BackgroundTransparency = 1;
  860.                 TextXAlignment = Enum.TextXAlignment.Left;
  861.                 TextYAlignment = Enum.TextYAlignment.Top;
  862.                 TextWrapped = true;
  863.                 TextColor3 = this.Settings.DefaultMessageTextColor;
  864.                 FontSize = this.Settings.FontSize;
  865.                 Font = this.Settings.Font;
  866.                 TextStrokeColor3 = this.Settings.TextStrokeColor;
  867.                 TextStrokeTransparency = this.Settings.TextStrokeTransparency;
  868.                 Parent = container;
  869.             };
  870.             -- Check if they got moderated and put up a real message instead of Label
  871.             if chatMessage.Text == 'Label' and chatMessageDisplayText ~= 'Label' then
  872.                 chatMessage.Text = string.rep(" ", numNeededSpaces) .. '[Content Deleted]'
  873.             end
  874.             if this.SendingPlayer and Util.IsPlayerAdminAsync(this.SendingPlayer) then
  875.                 chatMessage.TextColor3 = this.Settings.AdminTextColor
  876.             end
  877.             chatMessage.Size = chatMessage.Size + UDim2.new(0, 0, 0, chatMessage.TextBounds.Y);
  878.  
  879.         container.Size = UDim2.new(1, 0, 0, math.max(chatMessageSize.Y + 1, userNameButton.Size.Y.Offset + 1));
  880.         this.Container = container
  881.         this.ChatMessage = chatMessage
  882.         this.UserNameButton = userNameButton
  883.     end
  884.  
  885.     CreateMessageGuiElement()
  886.  
  887.     return this
  888. end
  889.  
  890. local function CreateChatBarWidget(settings)
  891.     local this = {}
  892.  
  893.     -- MessageModes: {All, Team, Whisper}
  894.     this.MessageMode = 'All'
  895.     this.TargetWhisperPlayer = nil
  896.     this.Settings = settings
  897.  
  898.     this.ChatBarGainedFocusEvent = Util.Signal()
  899.     this.ChatBarLostFocusEvent = Util.Signal()
  900.     this.ChatCommandEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures]
  901.     this.ChatErrorEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures]
  902.  
  903.     -- This function while lets string.find work case-insensitively without clobbering the case of the captures
  904.     local function nocase(s)
  905.       s = string.gsub(s, "%a", function (c)
  906.             return string.format("[%s%s]", string.lower(c),
  907.                                            string.upper(c))
  908.           end)
  909.       return s
  910.     end
  911.  
  912.     this.ChatMatchingRegex =
  913.     {
  914.         [function(chatBarText) return string.find(chatBarText, nocase("^/w ") .. "(%w+)") end] = "Whisper";
  915.         [function(chatBarText) return string.find(chatBarText, nocase("^/whisper ") .. "(%w+)") end] = "Whisper";
  916.  
  917.         [function(chatBarText) return string.find(chatBarText, "^%%") end] = "Team";
  918.         [function(chatBarText) return string.find(chatBarText, "^%(TEAM%)") end] = "Team";
  919.         [function(chatBarText) return string.find(chatBarText, nocase("^/t")) end] = "Team";
  920.         [function(chatBarText) return string.find(chatBarText, nocase("^/team")) end] = "Team";
  921.  
  922.         [function(chatBarText) return string.find(chatBarText, nocase("^/a")) end] = "All";
  923.         [function(chatBarText) return string.find(chatBarText, nocase("^/all")) end] = "All";
  924.         [function(chatBarText) return string.find(chatBarText, nocase("^/s")) end] = "All";
  925.         [function(chatBarText) return string.find(chatBarText, nocase("^/say")) end] = "All";
  926.  
  927.         [function(chatBarText) return string.find(chatBarText, nocase("^/e")) end] = "Emote";
  928.         [function(chatBarText) return string.find(chatBarText, nocase("^/emote")) end] = "Emote";
  929.  
  930.         [function(chatBarText) return string.find(chatBarText, "^/%?") end] = "Help";
  931.         [function(chatBarText) return string.find(chatBarText, nocase("^/help")) end] = "Help";
  932.  
  933.         [function(chatBarText) return string.find(chatBarText, nocase("^/ignore ") .. "(%w+)") end] = "Block";
  934.         [function(chatBarText) return string.find(chatBarText, nocase("^/block ") .. "(%w+)") end] = "Block";
  935.  
  936.         [function(chatBarText) return string.find(chatBarText, nocase("^/unignore ") .. "(%w+)") end] = "Unblock";
  937.         [function(chatBarText) return string.find(chatBarText, nocase("^/unblock ") .. "(%w+)") end] = "Unblock";
  938.     }
  939.  
  940.     local ChatModesDict =
  941.     {
  942.         ['Whisper'] = 'Whisper';
  943.         ['Team'] = 'Team';
  944.         ['All'] = 'All';
  945.         [Enum.PlayerChatType.Whisper] = 'Whisper';
  946.         [Enum.PlayerChatType.Team] = 'Team';
  947.         [Enum.PlayerChatType.All] = 'All';
  948.     }
  949.  
  950.     local function TearDownEvents()
  951.         -- Note: This is a new api so we need to pcall it
  952.         pcall(function() GuiService:RemoveSpecialKey(Enum.SpecialKey.ChatHotkey) end)
  953.         this.SpecialKeyPressedConn = Util.DisconnectEvent(this.SpecialKeyPressedConn)
  954.         this.ClickToChatButtonConn = Util.DisconnectEvent(this.ClickToChatButtonConn)
  955.         this.ChatBarFocusLostConn = Util.DisconnectEvent(this.ChatBarFocusLostConn)
  956.         this.ChatBarLostFocusConn = Util.DisconnectEvent(this.ChatBarLostFocusConn)
  957.         this.SelectChatModeConn = Util.DisconnectEvent(this.SelectChatModeConn)
  958.         this.SelectPlayerConn = Util.DisconnectEvent(this.SelectPlayerConn)
  959.         this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn)
  960.         this.InputBeganConn = Util.DisconnectEvent(this.InputBeganConn)
  961.     end
  962.  
  963.     local function HookUpEvents()
  964.         TearDownEvents() -- Cleanup old events
  965.  
  966.         pcall(function()
  967.             -- ChatHotKey is '/'
  968.             GuiService:AddSpecialKey(Enum.SpecialKey.ChatHotkey)
  969.             this.SpecialKeyPressedConn = GuiService.SpecialKeyPressed:connect(function(key)
  970.                 if key == Enum.SpecialKey.ChatHotkey then
  971.                     this:FocusChatBar()
  972.                 end
  973.             end)
  974.         end)
  975.  
  976.         if this.ClickToChatButton then this.ClickToChatButtonConn = this.ClickToChatButton.MouseButton1Click:connect(function() this:FocusChatBar() end) end
  977.  
  978.         if this.ChatBar then this.ChatBarFocusLostConn = this.ChatBar.FocusLost:connect(function(...) this.ChatBarLostFocusEvent:fire(...) end) end
  979.  
  980.         if this.ChatBarLostFocusEvent then this.ChatBarLostFocusConn = this.ChatBarLostFocusEvent:connect(function(...) this:OnChatBarFocusLost(...) end) end
  981.  
  982.         this.SelectChatModeConn = SelectChatModeEvent:connect(function(chatType)
  983.             this:SetMessageMode(chatType)
  984.             this:FocusChatBar()
  985.         end)
  986.  
  987.         this.SelectPlayerConn = SelectPlayerEvent:connect(function(chatPlayer)
  988.             this.TargetWhisperPlayer = chatPlayer
  989.             this:SetMessageMode("Whisper")
  990.             this:FocusChatBar()
  991.         end)
  992.  
  993.         this.InputBeganConn = InputService.InputBegan:connect(function(inputObject)
  994.             if inputObject.KeyCode == Enum.KeyCode.Escape then
  995.                 -- Clear text when they press escape
  996.                 this:SetChatBarText("")
  997.             end
  998.         end)
  999.     end
  1000.  
  1001.     function this:CoreGuiChanged(coreGuiType, enabled)
  1002.         if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then
  1003.             if enabled then
  1004.                 HookUpEvents()
  1005.             else
  1006.                 TearDownEvents()
  1007.             end
  1008.             if this.ChatBarContainer then
  1009.                 this.ChatBarContainer.Visible = enabled
  1010.             end
  1011.         end
  1012.         if NON_CORESCRIPT_MODE then
  1013.             this.ChatBarContainer.Visible = false
  1014.         end
  1015.     end
  1016.  
  1017.     function this:IsAChatMode(mode)
  1018.         return ChatModesDict[mode] ~= nil
  1019.     end
  1020.  
  1021.     function this:ProcessChatBarModes(requireWhitespaceAfterChatMode)
  1022.         local matchedAChatCommand = false
  1023.         if this.ChatBar then
  1024.             local chatBarText = this:SanitizeInput(this:GetChatBarText())
  1025.             for regexFunc, actionType in pairs(this.ChatMatchingRegex) do
  1026.                 local start, finish, capture = regexFunc(chatBarText)
  1027.                 if start and finish then
  1028.                     -- The following line is for whether or not to try setting the chatmode as-you-type
  1029.                     -- versus when you press enter.
  1030.                     local whitespaceAfterSlashCommand = string.find(string.sub(chatBarText, finish+1, finish+1), "%s")
  1031.                     if (not requireWhitespaceAfterChatMode and finish == #chatBarText) or whitespaceAfterSlashCommand then
  1032.                         if this:IsAChatMode(actionType) then
  1033.                             if actionType == "Whisper" then
  1034.                                 local targetPlayer = capture and Util.GetPlayerByName(capture)
  1035.                                 if targetPlayer then --and targetPlayer ~= Player then
  1036.                                     this.TargetWhisperPlayer = targetPlayer
  1037.                                     -- start from two over to eat the space or tab character after the slash command
  1038.                                     this:SetChatBarText(string.sub(chatBarText, finish + 2))
  1039.                                     this:SetMessageMode(actionType)
  1040.                                     this.ChatCommandEvent:fire(true, actionType, capture)
  1041.                                 else
  1042.                                     -- This is an indirect way of detecting if they used enter to close submit this chat
  1043.                                     if not requireWhitespaceAfterChatMode then
  1044.                                         this:SetChatBarText("")
  1045.                                         this.ChatCommandEvent:fire(false, actionType, capture)
  1046.                                     end
  1047.                                 end
  1048.                             else
  1049.                                 -- start from two over to eat the space or tab character after the slash command
  1050.                                 this:SetChatBarText(string.sub(chatBarText, finish + 2))
  1051.                                 this:SetMessageMode(actionType)
  1052.                                 this.ChatCommandEvent:fire(true, actionType, capture)
  1053.                             end
  1054.                         elseif actionType == "Emote" then
  1055.                             -- You can only emote to everyone.
  1056.                             this:SetMessageMode('All')
  1057.                         elseif not requireWhitespaceAfterChatMode then -- Some non-chat related command
  1058.                             if actionType == "Help" then
  1059.                                 this:SetChatBarText("") -- Clear the chat so we don't send /? to everyone
  1060.                             end
  1061.                             this.ChatCommandEvent:fire(true, actionType, capture)
  1062.                         end
  1063.                         -- should we break here since we already matched a slash command or keep going?
  1064.                         matchedAChatCommand = true
  1065.                     end
  1066.                 end
  1067.             end
  1068.         end
  1069.         return matchedAChatCommand
  1070.     end
  1071.  
  1072.     local previousText = ""
  1073.     function this:OnChatBarTextChanged()
  1074.         if not Util.IsTouchDevice() then
  1075.             this:ProcessChatBarModes(true)
  1076.             local newText = this:GetChatBarText()
  1077.             if #newText > this.Settings.MaxCharactersInMessage then
  1078.                 local fixedText = ""
  1079.                 -- This is a hack to deal with the bug that holding down a key for repeated input doesn't trigger the textChanged event
  1080.                 if #newText == #previousText + 1 then
  1081.                     fixedText = string.sub(previousText, 1, this.Settings.MaxCharactersInMessage)
  1082.                 else
  1083.                     fixedText = string.sub(newText, 1, this.Settings.MaxCharactersInMessage)
  1084.                 end
  1085.                 this:SetChatBarText(fixedText)
  1086.                 previousText = fixedText
  1087.             else
  1088.                 previousText = newText
  1089.             end
  1090.         end
  1091.     end
  1092.  
  1093.     function this:GetChatBarText()
  1094.         return this.ChatBar and this.ChatBar.Text or ""
  1095.     end
  1096.  
  1097.     function this:SetChatBarText(newText)
  1098.         if this.ChatBar then
  1099.             this.ChatBar.Text = newText
  1100.         end
  1101.     end
  1102.  
  1103.     function this:GetMessageMode()
  1104.         return this.MessageMode
  1105.     end
  1106.  
  1107.     function this:SetMessageMode(newMessageMode)
  1108.         newMessageMode = ChatModesDict[newMessageMode]
  1109.  
  1110.         local chatRecipientText = "[" .. (this.TargetWhisperPlayer and this.TargetWhisperPlayer.Name or "") .. "]"
  1111.         if this.MessageMode ~= newMessageMode or (newMessageMode == 'Whisper' and this.ChatModeText and chatRecipientText ~= this.ChatModeText.Text) then
  1112.             if this.ChatModeText then
  1113.                 this.MessageMode = newMessageMode
  1114.                 if newMessageMode == 'Whisper' then
  1115.                     local chatRecipientTextBounds = Util.GetStringTextBounds(chatRecipientText, this.ChatModeText.Font, this.ChatModeText.FontSize)
  1116.  
  1117.                     this.ChatModeText.TextColor3 = this.Settings.WhisperTextColor
  1118.                     this.ChatModeText.Text = chatRecipientText
  1119.                     this.ChatModeText.Size = UDim2.new(0, chatRecipientTextBounds.X, 1, 0)
  1120.                 elseif newMessageMode == 'Team' then
  1121.                     local chatTeamText = '[Team]'
  1122.                     local chatTeamTextBounds = Util.GetStringTextBounds(chatTeamText, this.ChatModeText.Font, this.ChatModeText.FontSize)
  1123.  
  1124.                     this.ChatModeText.TextColor3 = this.Settings.TeamTextColor
  1125.                     this.ChatModeText.Text = "[Team]"
  1126.                     this.ChatModeText.Size = UDim2.new(0, chatTeamTextBounds.X, 1, 0)
  1127.                 else
  1128.                     this.ChatModeText.Text = ""
  1129.                     this.ChatModeText.Size = UDim2.new(0, 0, 1, 0)
  1130.                 end
  1131.                 if this.ChatBar then
  1132.                     local offset = this.ChatModeText.Size.X.Offset + this.ChatModeText.Position.X.Offset
  1133.                     this.ChatBar.Size = UDim2.new(1, -offset - 5, 1, 0)
  1134.                     this.ChatBar.Position = UDim2.new(0, offset + 5, 0, 0)
  1135.                 end
  1136.             end
  1137.         end
  1138.     end
  1139.  
  1140.     function this:FocusChatBar()
  1141.         if this.ChatBar then
  1142.             this.ChatBar.Visible = true
  1143.             this.ChatBar:CaptureFocus()
  1144.             if self.ClickToChatButton then
  1145.                 self.ClickToChatButton.Visible = false
  1146.             end
  1147.             if this.ChatModeText then
  1148.                 this.ChatModeText.Visible = true
  1149.             end
  1150.             this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn)
  1151.             this.ChatBarChangedConn = this.ChatBar.Changed:connect(function(prop)
  1152.                 if prop == "Text" then
  1153.                     this:OnChatBarTextChanged()
  1154.                 end
  1155.             end)
  1156.             if Util.IsTouchDevice() then
  1157.                 this:SetMessageMode('All') -- Don't remember message mode on mobile devices
  1158.             else
  1159.                 -- Use a count to check for double backspace out of a chatmode
  1160.                 local count = 0
  1161.                 this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn)
  1162.                 this.FocusChatBarInputBeganConn = InputService.InputBegan:connect(function(inputObj)
  1163.                     if inputObj.KeyCode == Enum.KeyCode.Backspace and this:GetChatBarText() == "" then
  1164.                         if count == 0 then
  1165.                             count = count + 1
  1166.                         else
  1167.                             this:SetMessageMode('All')
  1168.                         end
  1169.                     else
  1170.                         count = 0
  1171.                     end
  1172.                 end)
  1173.             end
  1174.             this.ChatBarGainedFocusEvent:fire()
  1175.         end
  1176.     end
  1177.  
  1178.     function this:SanitizeInput(input)
  1179.         local sanitizedInput = input
  1180.         -- Chomp the whitespace at the front and end of the string
  1181.         -- TODO: maybe only chop off the front space if there are more than a few?
  1182.         local _, _, capture = string.find(sanitizedInput, "^%s*(.*)%s*$")
  1183.         sanitizedInput = capture or ""
  1184.  
  1185.         return sanitizedInput
  1186.     end
  1187.  
  1188.     function this:OnChatBarFocusLost(enterPressed)
  1189.         if self.ChatBar then
  1190.             self.ChatBar.Visible = false
  1191.             if enterPressed then
  1192.                 local didMatchSlashCommand = this:ProcessChatBarModes(false)
  1193.                 local cText = this:SanitizeInput(this:GetChatBarText())
  1194.                 if cText ~= "" then
  1195.                     -- For now we will let any slash command go through, NOTE: these will show up in bubble-chat
  1196.                     --if not didMatchSlashCommand and string.sub(cText,1,1) == "/" then
  1197.                     --  this.ChatCommandEvent:fire(false, "Unknown", cText)
  1198.                     --else
  1199.                         local currentMessageMode = this:GetMessageMode()
  1200.                         -- {All, Team, Whisper}
  1201.                         if currentMessageMode == 'Team' then
  1202.                             if Player and Player.Neutral == true then
  1203.                                 this.ChatErrorEvent:fire("You are not in any team.")
  1204.                             else
  1205.                                 pcall(function() PlayersService:TeamChat(cText) end)
  1206.                             end
  1207.                         elseif currentMessageMode == 'Whisper' then
  1208.                             if this.TargetWhisperPlayer then
  1209.                                 if this.TargetWhisperPlayer == Player then
  1210.                                     this.ChatErrorEvent:fire("You cannot send a whisper to yourself.")
  1211.                                 else
  1212.                                     pcall(function() PlayersService:WhisperChat(cText, this.TargetWhisperPlayer) end)
  1213.                                 end
  1214.                             else
  1215.                                 this.ChatErrorEvent:fire("Invalid whisper target.")
  1216.                             end
  1217.                         elseif currentMessageMode == 'All' then
  1218.                             pcall(function() PlayersService:Chat(cText) end)
  1219.                         else
  1220.                             spawn(function() error("ChatScript: Unknown Message Mode of " .. tostring(currentMessageMode)) end)
  1221.                         end
  1222.                     --end
  1223.                 end
  1224.                 this:SetChatBarText("")
  1225.             end
  1226.         end
  1227.         if self.ClickToChatButton then
  1228.             self.ClickToChatButton.Visible = true
  1229.         end
  1230.         if this.ChatModeText then
  1231.             this.ChatModeText.Visible = false
  1232.         end
  1233.         this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn)
  1234.         this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn)
  1235.     end
  1236.  
  1237.     local function CreateChatBar()
  1238.         local chatBarContainer = Util.Create'Frame'
  1239.         {
  1240.             Name = 'ChatBarContainer';
  1241.             Position = UDim2.new(0, 0, 1, 0);
  1242.             Size = UDim2.new(1, 0, 0, 20);
  1243.             ZIndex = 1;
  1244.             BackgroundColor3 = Color3.new(0, 0, 0);
  1245.             BackgroundTransparency = 0.25;
  1246.         };
  1247.             local clickToChatButton = Util.Create'TextButton'
  1248.             {
  1249.                 Name = 'ClickToChat';
  1250.                 Position = UDim2.new(0,9,0,0);
  1251.                 Size = UDim2.new(1, -9, 1, 0);
  1252.                 BackgroundTransparency = 1;
  1253.                 ZIndex = 3;
  1254.                 Text = 'To chat click here or press "/" key';
  1255.                 TextColor3 = this.Settings.GlobalTextColor;
  1256.                 TextXAlignment = Enum.TextXAlignment.Left;
  1257.                 TextYAlignment = Enum.TextYAlignment.Top;
  1258.                 Font = Enum.Font.SourceSansBold;
  1259.                 FontSize = Enum.FontSize.Size18;
  1260.                 Parent = chatBarContainer;
  1261.             }
  1262.             local chatBar = Util.Create'TextBox'
  1263.             {
  1264.                 Name = 'ChatBar';
  1265.                 Position = UDim2.new(0, 9, 0, 0);
  1266.                 Size = UDim2.new(1, -9, 1, 0);
  1267.                 Text = "";
  1268.                 ZIndex = 1;
  1269.                 BackgroundColor3 = Color3.new(0, 0, 0);
  1270.                 Active = false;
  1271.                 BackgroundTransparency = 1;
  1272.                 TextXAlignment = Enum.TextXAlignment.Left;
  1273.                 TextYAlignment = Enum.TextYAlignment.Top;
  1274.                 TextColor3 = this.Settings.GlobalTextColor;
  1275.                 Font = Enum.Font.SourceSansBold;
  1276.                 FontSize = Enum.FontSize.Size18;
  1277.                 ClearTextOnFocus = false;
  1278.                 Visible = not Util.IsTouchDevice();
  1279.                 Parent = chatBarContainer;
  1280.             }
  1281.             local chatModeText = Util.Create'TextButton'
  1282.             {
  1283.                 Name = 'ChatModeText';
  1284.                 Position = UDim2.new(0, 9, 0, 0);
  1285.                 Size = UDim2.new(1, -9, 1, 0);
  1286.                 BackgroundTransparency = 1;
  1287.                 ZIndex = 2;
  1288.                 Text = '';
  1289.                 TextColor3 = this.Settings.WhisperTextColor;
  1290.                 TextXAlignment = Enum.TextXAlignment.Left;
  1291.                 TextYAlignment = Enum.TextYAlignment.Top;
  1292.                 Font = Enum.Font.SourceSansBold;
  1293.                 FontSize = Enum.FontSize.Size18;
  1294.                 Parent = chatBarContainer;
  1295.             }
  1296.  
  1297.         this.ChatBarContainer = chatBarContainer
  1298.         this.ClickToChatButton = clickToChatButton
  1299.         this.ChatBar = chatBar
  1300.         this.ChatModeText = chatModeText
  1301.         this.ChatBarContainer.Parent = GuiRoot
  1302.     end
  1303.  
  1304.     CreateChatBar()
  1305.     return this
  1306. end
  1307.  
  1308. local function CreateChatWindowWidget(settings)
  1309.     local this = {}
  1310.     this.Settings = settings
  1311.     this.Chats = {}
  1312.     this.BackgroundVisible = false
  1313.     this.ChatsVisible = false
  1314.  
  1315.     this.ChatWindowPagingConn = nil
  1316.  
  1317.     local lastMoveTime = tick()
  1318.     local lastEnterTime = tick()
  1319.     local lastLeaveTime = tick()
  1320.  
  1321.     local lastFadeOutTime = 0
  1322.     local lastFadeInTime = 0
  1323.     local lastChatActivity = 0
  1324.  
  1325.     local FadeLock = false
  1326.  
  1327.     local function PointInChatWindow(pt)
  1328.         local point0 = this.ChatContainer.AbsolutePosition
  1329.         local point1 = point0 + this.ChatContainer.AbsoluteSize
  1330.         return point0.X <= pt.X and point1.X >= pt.X and
  1331.                point0.Y <= pt.Y and point1.Y >= pt.Y
  1332.     end
  1333.  
  1334.     function this:IsHovering()
  1335.         if this.ChatContainer and this.LastMousePosition then
  1336.             return PointInChatWindow(this.LastMousePosition)
  1337.         end
  1338.         return false
  1339.     end
  1340.  
  1341.     function this:SetFadeLock(lock)
  1342.         FadeLock = lock
  1343.     end
  1344.  
  1345.     function this:GetFadeLock()
  1346.         return FadeLock
  1347.     end
  1348.  
  1349.     function this:SetCanvasPosition(newCanvasPosition)
  1350.         if this.ScrollingFrame then
  1351.             local maxSize = Vector2.new(math.max(0, this.ScrollingFrame.CanvasSize.X.Offset - this.ScrollingFrame.AbsoluteWindowSize.X),
  1352.                                         math.max(0, this.ScrollingFrame.CanvasSize.Y.Offset - this.ScrollingFrame.AbsoluteWindowSize.Y))
  1353.             this.ScrollingFrame.CanvasPosition = Vector2.new(Util.Clamp(0, maxSize.X, newCanvasPosition.X),
  1354.                                                              Util.Clamp(0, maxSize.Y, newCanvasPosition.Y))
  1355.         end
  1356.     end
  1357.  
  1358.     function this:ScrollToBottom()
  1359.         if this.ScrollingFrame then
  1360.             this:SetCanvasPosition(Vector2.new(this.ScrollingFrame.CanvasPosition.X, this.ScrollingFrame.CanvasSize.Y.Offset))
  1361.         end
  1362.     end
  1363.  
  1364.     function this:FadeIn(duration, lockFade)
  1365.         if not FadeLock then
  1366.             duration = duration or 0.75
  1367.             -- fade in
  1368.             if this.BackgroundTweener then
  1369.                 this.BackgroundTweener:Cancel()
  1370.             end
  1371.             lastFadeInTime = tick()
  1372.             lastChatActivity = tick()
  1373.             this.ScrollingFrame.ScrollingEnabled = true
  1374.             this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, 0.7, duration, Util.Linear)
  1375.             this.BackgroundVisible = true
  1376.             this:FadeInChats()
  1377.  
  1378.             this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn)
  1379.             this.ChatWindowPagingConn = InputService.InputBegan:connect(function(inputObject)
  1380.                 local key = inputObject.KeyCode
  1381.                 if key == Enum.KeyCode.PageUp then
  1382.                     this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition - Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y))
  1383.                 elseif key == Enum.KeyCode.PageDown then
  1384.                     this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition + Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y))
  1385.                 elseif key == Enum.KeyCode.Home then
  1386.                     this:SetCanvasPosition(Vector2.new(0, 0))
  1387.                 elseif key == Enum.KeyCode.End then
  1388.                     this:ScrollToBottom()
  1389.                 end
  1390.             end)
  1391.         end
  1392.     end
  1393.     function this:FadeOut(duration, unlockFade)
  1394.         if not FadeLock then
  1395.             duration = duration or 0.75
  1396.             -- fade out
  1397.             if this.BackgroundTweener then
  1398.                 this.BackgroundTweener:Cancel()
  1399.             end
  1400.             lastFadeOutTime = tick()
  1401.             lastChatActivity = tick()
  1402.             this.ScrollingFrame.ScrollingEnabled = false
  1403.             this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, 1, duration, Util.Linear)
  1404.             this.BackgroundVisible = false
  1405.  
  1406.             this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn)
  1407.         end
  1408.     end
  1409.  
  1410.     function this:FadeInChats()
  1411.         if this.ChatsVisible == true then return end
  1412.         this.ChatsVisible = true
  1413.         for index, message in pairs(this.Chats) do
  1414.             message:FadeIn()
  1415.         end
  1416.     end
  1417.  
  1418.     function this:FadeOutChats()
  1419.         if this.ChatsVisible == false then return end
  1420.         this.ChatsVisible = false
  1421.         for index, message in pairs(this.Chats) do
  1422.             local messageGui = message:GetGui()
  1423.             local instant = false
  1424.             if messageGui and this.ScrollingFrame then
  1425.                 -- If the chat is not in the visible frame then don't waste cpu cycles fading it out
  1426.                 if messageGui.AbsolutePosition.Y > (this.ScrollingFrame.AbsolutePosition + this.ScrollingFrame.AbsoluteWindowSize).Y or
  1427.                         messageGui.AbsolutePosition.Y + messageGui.AbsoluteSize.Y < this.ScrollingFrame.AbsolutePosition.Y then
  1428.                     instant = true
  1429.                 end
  1430.             end
  1431.             message:FadeOut(instant)
  1432.         end
  1433.     end
  1434.  
  1435.     local ResizeCount = 0
  1436.     function this:OnResize()
  1437.         ResizeCount = ResizeCount + 1
  1438.         local currentResizeCount = ResizeCount
  1439.         local isScrolledDown = this:IsScrolledDown()
  1440.         -- Unfortunately there is a race condition so we need this wait here.
  1441.         wait()
  1442.         if this.ScrollingFrame then
  1443.             if currentResizeCount ~= ResizeCount then return end
  1444.             local scrollingFrameAbsoluteSize = this.ScrollingFrame.AbsoluteWindowSize
  1445.             if scrollingFrameAbsoluteSize ~= nil and scrollingFrameAbsoluteSize.X > 0 and scrollingFrameAbsoluteSize.Y > 0 then
  1446.                 local ySize = 0
  1447.  
  1448.                 if this.ScrollingFrame then
  1449.                     for index, message in pairs(this.Chats) do
  1450.                         local newHeight = message:OnResize(scrollingFrameAbsoluteSize)
  1451.                         if newHeight then
  1452.                             local chatMessageElement = message:GetGui()
  1453.                             if chatMessageElement then
  1454.                                 local chatMessageElementYSize = chatMessageElement.Size.Y.Offset
  1455.                                 chatMessageElement.Position = UDim2.new(0, 0, 0, ySize)
  1456.                                 ySize = ySize + chatMessageElementYSize
  1457.                             end
  1458.                         end
  1459.                     end
  1460.                 end
  1461.                 if this.MessageContainer and this.ScrollingFrame then
  1462.                     this.MessageContainer.Size = UDim2.new(
  1463.                             this.MessageContainer.Size.X.Scale,
  1464.                             this.MessageContainer.Size.X.Offset,
  1465.                             0,
  1466.                             ySize)
  1467.                     this.MessageContainer.Position = UDim2.new(0, 0, 1, -this.MessageContainer.Size.Y.Offset)
  1468.                     this.ScrollingFrame.CanvasSize = UDim2.new(this.ScrollingFrame.CanvasSize.X.Scale, this.ScrollingFrame.CanvasSize.X.Offset, this.ScrollingFrame.CanvasSize.Y.Scale, ySize)
  1469.                 end
  1470.             end
  1471.             this:ScrollToBottom()
  1472.         end
  1473.     end
  1474.  
  1475.     function this:FilterMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer)
  1476.         if chattedMessage and string.sub(chattedMessage, 1, 1) ~= '/' then
  1477.             return true
  1478.         end
  1479.         return false
  1480.     end
  1481.  
  1482.     function this:PushMessageIntoQueue(chatMessage, silently)
  1483.         table.insert(this.Chats, chatMessage)
  1484.  
  1485.         local isScrolledDown = this:IsScrolledDown()
  1486.  
  1487.         local chatMessageElement = chatMessage:GetGui()
  1488.  
  1489.         chatMessageElement.Parent = this.MessageContainer
  1490.         chatMessage:OnResize()
  1491.         local ySize = this.MessageContainer.Size.Y.Offset
  1492.         local chatMessageElementYSize = UDim2.new(0, 0, 0, chatMessageElement.Size.Y.Offset)
  1493.  
  1494.         chatMessageElement.Position = chatMessageElement.Position + UDim2.new(0, 0, 0, ySize)
  1495.         this.MessageContainer.Size = this.MessageContainer.Size + chatMessageElementYSize
  1496.         this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize + chatMessageElementYSize
  1497.  
  1498.         if this.Settings.MaxWindowChatMessages < #this.Chats then
  1499.             this:RemoveOldestMessage()
  1500.         end
  1501.         if isScrolledDown then
  1502.             this:ScrollToBottom()
  1503.         elseif not silently then
  1504.             -- Raise unread message alert!
  1505.         end
  1506.  
  1507.         if silently then
  1508.             chatMessage:FadeOut(true)
  1509.         else
  1510.             this:FadeInChats()
  1511.             lastChatActivity = tick()
  1512.         end
  1513.  
  1514.         -- NOTE: Sort of hacky, but if we are approaching the max 16 bit size
  1515.         -- we need to rebase y back to 0 which can be done with the resize function
  1516.         if ySize > (MAX_UDIM_SIZE / 2) then
  1517.             self:OnResize()
  1518.         end
  1519.     end
  1520.  
  1521.     function this:AddSystemChatMessage(chattedMessage, silently)
  1522.         local chatMessage = CreateSystemChatMessage(this.Settings, chattedMessage)
  1523.         this:PushMessageIntoQueue(chatMessage, silently)
  1524.     end
  1525.  
  1526.     function this:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer, silently)
  1527.         if this:FilterMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) then
  1528.             local chatMessage = CreatePlayerChatMessage(this.Settings, playerChatType, sendingPlayer, chattedMessage, receivingPlayer)
  1529.             this:PushMessageIntoQueue(chatMessage, silently)
  1530.         end
  1531.     end
  1532.  
  1533.     function this:RemoveOldestMessage()
  1534.         local oldestChat = this.Chats[1]
  1535.         if oldestChat then
  1536.             return this:RemoveChatMessage(oldestChat)
  1537.         end
  1538.     end
  1539.  
  1540.     function this:RemoveChatMessage(chatMessage)
  1541.         if chatMessage then
  1542.             for index, message in pairs(this.Chats) do
  1543.                 if chatMessage == message then
  1544.                     local guiObj = chatMessage:GetGui()
  1545.                     if guiObj then
  1546.                         local ySize = guiObj.Size.Y.Offset
  1547.                         this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize - UDim2.new(0,0,0,ySize)
  1548.                         -- Clamp the canvasposition
  1549.                         this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition)
  1550.                         guiObj.Parent = nil
  1551.                     end
  1552.                     message:Destroy()
  1553.                     return table.remove(this.Chats, index)
  1554.                 end
  1555.             end
  1556.         end
  1557.     end
  1558.  
  1559.     function this:IsScrolledDown()
  1560.         if this.ScrollingFrame then
  1561.             local yCanvasSize = this.ScrollingFrame.CanvasSize.Y.Offset
  1562.             local yContainerSize = this.ScrollingFrame.AbsoluteWindowSize.Y
  1563.             local yScrolledPosition = this.ScrollingFrame.CanvasPosition.Y
  1564.             -- Check if the messages are at the bottom
  1565.             return yCanvasSize < yContainerSize or
  1566.                    yCanvasSize - yScrolledPosition <= yContainerSize + 5 -- a little wiggle room
  1567.         end
  1568.         return false
  1569.     end
  1570.  
  1571.     function this:CoreGuiChanged(coreGuiType, enabled)
  1572.         if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then
  1573.             if this.ChatContainer then
  1574.                 this.ChatContainer.Visible = enabled
  1575.             end
  1576.         end
  1577.         -- If we are using bubble-chat then do not show chat window
  1578.         if this.ChatContainer and not PlayersService.ClassicChat then
  1579.             this.ChatContainer.Visible = false
  1580.         end
  1581.         if NON_CORESCRIPT_MODE then
  1582.             this.ChatContainer.Visible = true
  1583.         end
  1584.     end
  1585.  
  1586.     local function CreateChatWindow()
  1587.         local container = Util.Create'Frame'
  1588.         {
  1589.             Name = 'ChatWindowContainer';
  1590.             Size = UDim2.new(0.3, 0, 0.25, 0);
  1591.             Position = UDim2.new(0, 8, 0, 37);
  1592.             ZIndex = 1;
  1593.             BackgroundColor3 = Color3.new(0, 0, 0);
  1594.             BackgroundTransparency = 1;
  1595.         };
  1596.             local scrollingFrame = Util.Create'ScrollingFrame'
  1597.             {
  1598.                 Name = 'ChatWindow';
  1599.                 Size = UDim2.new(1, -4 - 10, 1, -20);
  1600.                 CanvasSize = UDim2.new(1, -4 - 10, 0, 0);
  1601.                 Position = UDim2.new(0, 10, 0, 10);
  1602.                 ZIndex = 1;
  1603.                 BackgroundColor3 = Color3.new(0, 0, 0);
  1604.                 BackgroundTransparency = 1;
  1605.                 BottomImage = "rbxasset://textures/ui/scroll-bottom.png";
  1606.                 MidImage = "rbxasset://textures/ui/scroll-middle.png";
  1607.                 TopImage = "rbxasset://textures/ui/scroll-top.png";
  1608.                 ScrollBarThickness = 7;
  1609.                 BorderSizePixel = 0;
  1610.                 ScrollingEnabled = false;
  1611.                 Parent = container;
  1612.             };
  1613.                 local messageContainer = Util.Create'Frame'
  1614.                 {
  1615.                     Name = 'MessageContainer';
  1616.                     Size = UDim2.new(1, -scrollingFrame.ScrollBarThickness - 1, 0, 0);
  1617.                     Position = UDim2.new(0, 0, 1, 0);
  1618.                     ZIndex = 1;
  1619.                     BackgroundColor3 = Color3.new(0, 0, 0);
  1620.                     BackgroundTransparency = 1;
  1621.                     Parent = scrollingFrame
  1622.                 };
  1623.  
  1624.         -- This is some trickery we are doing to make the first chat messages appear at the bottom and go towards the top.
  1625.         local function OnChatWindowResize(prop)
  1626.             if prop == 'AbsoluteSize' then
  1627.                 messageContainer.Position = UDim2.new(0, 0, 1, -messageContainer.Size.Y.Offset)
  1628.             end
  1629.         end
  1630.         container.Changed:connect(function(prop) if prop == 'AbsoluteSize' then this:OnResize() end end)
  1631.  
  1632.         local function RobloxClientScreenSizeChanged(newSize)
  1633.             if container then
  1634.                 -- Phone
  1635.                 if newSize.X <= 640 then
  1636.                     container.Size = UDim2.new(0.5,0,0.5,0) - container.Position
  1637.                 -- Tablet
  1638.                 elseif newSize.X <= 1024 then
  1639.                     container.Size = UDim2.new(0.4,0,0.3,0) - container.Position
  1640.                 -- Desktop
  1641.                 else
  1642.                     container.Size = UDim2.new(0.3,0,0.25,0) - container.Position
  1643.                 end
  1644.             end
  1645.         end
  1646.  
  1647.         GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end)
  1648.         RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize)
  1649.  
  1650.         messageContainer.Changed:connect(OnChatWindowResize)
  1651.         scrollingFrame.Changed:connect(OnChatWindowResize)
  1652.  
  1653.         this.ChatContainer = container
  1654.         this.ScrollingFrame = scrollingFrame
  1655.         this.MessageContainer = messageContainer
  1656.         this.ChatContainer.Parent = GuiRoot
  1657.  
  1658.         --- BACKGROUND FADING CODE ---
  1659.         -- This is so we don't accidentally fade out when we are scrolling and mess with the scrollbar.
  1660.         local dontFadeOutOnMouseLeave = false
  1661.  
  1662.         if Util:IsTouchDevice() then
  1663.             local touchCount = 0
  1664.             this.InputBeganConn = InputService.InputBegan:connect(function(inputObject)
  1665.                 if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin then
  1666.                     if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then
  1667.                         touchCount = touchCount + 1
  1668.                         dontFadeOutOnMouseLeave = true
  1669.                     end
  1670.                 end
  1671.             end)
  1672.  
  1673.             this.InputEndedConn = InputService.InputEnded:connect(function(inputObject)
  1674.                 if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then
  1675.                     local endedCount = touchCount
  1676.                     wait(2)
  1677.                     if touchCount == endedCount then
  1678.                         dontFadeOutOnMouseLeave = false
  1679.                     end
  1680.                 end
  1681.             end)
  1682.  
  1683.             spawn(function()
  1684.                 local now = tick()
  1685.                 while true do
  1686.                     wait()
  1687.                     now = tick()
  1688.                     if this.BackgroundVisible then
  1689.                         if not dontFadeOutOnMouseLeave then
  1690.                             this:FadeOut(0.25)
  1691.                         end
  1692.                     -- If background is not visible/in-focus
  1693.                     elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then
  1694.                         this:FadeOutChats()
  1695.                     end
  1696.                 end
  1697.             end)
  1698.         else
  1699.             this.LastMousePosition = Vector2.new()
  1700.  
  1701.             this.MouseEnterFrameConn = this.ChatContainer.MouseEnter:connect(function()
  1702.                 lastEnterTime = tick()
  1703.                 if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and not this.BackgroundVisible then
  1704.                     this:FadeIn()
  1705.                 end
  1706.             end)
  1707.  
  1708.             this.MouseMoveConn = InputService.InputChanged:connect(function(inputObject)
  1709.                 if inputObject.UserInputType == Enum.UserInputType.MouseMovement then
  1710.                     lastMoveTime = tick()
  1711.                     this.LastMousePosition = Vector2.new(inputObject.Position.X, inputObject.Position.Y)
  1712.                     if this.BackgroundTweener and this.BackgroundTweener:GetPercentComplete() < 0.5 and this.BackgroundVisible then
  1713.                         if not dontFadeOutOnMouseLeave then
  1714.                             this:FadeOut()
  1715.                         end
  1716.                     end
  1717.                 end
  1718.             end)
  1719.  
  1720.             local clickCount = 0
  1721.             this.InputBeganConn = InputService.InputBegan:connect(function(inputObject)
  1722.                 if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.Begin then
  1723.                     if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then
  1724.                         clickCount = clickCount + 1
  1725.                         dontFadeOutOnMouseLeave = true
  1726.                     end
  1727.                 end
  1728.             end)
  1729.  
  1730.             this.InputEndedConn = InputService.InputEnded:connect(function(inputObject)
  1731.                 if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.End then
  1732.                     local nowCount = clickCount
  1733.                     wait(1.3)
  1734.                     if nowCount == clickCount then
  1735.                         dontFadeOutOnMouseLeave = false
  1736.                     end
  1737.                 end
  1738.             end)
  1739.  
  1740.             this.MouseLeaveFrameConn = this.ChatContainer.MouseLeave:connect(function()
  1741.                 lastLeaveTime = tick()
  1742.                 if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and this.BackgroundVisible then
  1743.                     if not dontFadeOutOnMouseLeave then
  1744.                         this:FadeOut()
  1745.                     end
  1746.                 end
  1747.             end)
  1748.  
  1749.             spawn(function()
  1750.                 while true do
  1751.                     wait()
  1752.                     local now = tick()
  1753.                     if this:IsHovering() then
  1754.                         if now - lastMoveTime > 1.3 and not this.BackgroundVisible then
  1755.                             this:FadeIn()
  1756.                         end
  1757.                     else -- not this:IsHovering()
  1758.                         if this.BackgroundVisible then
  1759.                             if not dontFadeOutOnMouseLeave then
  1760.                                 this:FadeOut(0.25)
  1761.                             end
  1762.                         -- If background is not visible/in-focus
  1763.                         elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then
  1764.                             this:FadeOutChats()
  1765.                         end
  1766.                     end
  1767.                 end
  1768.             end)
  1769.         end
  1770.         --- END OF BACKGROUND FADING CODE ---
  1771.     end
  1772.  
  1773.     CreateChatWindow()
  1774.  
  1775.     return this
  1776. end
  1777.  
  1778.  
  1779. local function CreateChat()
  1780.     local this = {}
  1781.  
  1782.     this.Settings =
  1783.     {
  1784.         GlobalTextColor = Color3.new(255/255, 255/255, 243/255);
  1785.         WhisperTextColor = Color3.new(77/255, 139/255, 255/255);
  1786.         TeamTextColor = Color3.new(230/255, 207/255, 0);
  1787.         DefaultMessageTextColor = Color3.new(255/255, 255/255, 243/255);
  1788.         AdminTextColor = Color3.new(1, 215/255, 0);
  1789.         TextStrokeTransparency = 0.75;
  1790.         TextStrokeColor = Color3.new(34/255,34/255,34/255);
  1791.         Font = Enum.Font.SourceSansBold;
  1792.         --Font = Enum.Font.ArialBold;
  1793.         FontSize = Enum.FontSize.Size18;
  1794.         MaxWindowChatMessages = 50;
  1795.         MaxCharactersInMessage = 140;
  1796.     }
  1797.  
  1798.     this.BlockList = {}
  1799.  
  1800.     function this:CoreGuiChanged(coreGuiType, enabled)
  1801.         if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then
  1802.             if Util:IsTouchDevice() then
  1803.                 Util.SetGUIInsetBounds(0, 0)
  1804.             else
  1805.                 if enabled and this.ChatBarWidget then
  1806.                     -- Reserve bottom 20 pixels for our chat bar
  1807.                     Util.SetGUIInsetBounds(0, 20)
  1808.                 else
  1809.                     Util.SetGUIInsetBounds(0, 0)
  1810.                 end
  1811.             end
  1812.             if this.MobileChatButton then
  1813.                 if enabled == true then
  1814.                     this.MobileChatButton.Parent = GuiRoot
  1815.                     -- we need to set it to be visible in-case we missed a lost focus event while chat was turned off.
  1816.                     this.MobileChatButton.Visible = true
  1817.                 else
  1818.                     this.MobileChatButton.Parent = nil
  1819.                 end
  1820.             end
  1821.         end
  1822.         if this.ChatWindowWidget then
  1823.             this.ChatWindowWidget:CoreGuiChanged(coreGuiType, enabled)
  1824.         end
  1825.         if this.ChatBarWidget then
  1826.             this.ChatBarWidget:CoreGuiChanged(coreGuiType, enabled)
  1827.         end
  1828.     end
  1829.  
  1830.     -- This event has 4 callback arguments
  1831.     -- Enum.PlayerChatType.{All|Team|Whisper}, chatPlayer, message, targetPlayer
  1832.     function this:OnPlayerChatted(playerChatType, sendingPlayer, chattedMessage, receivingPlayer)
  1833.         if this.ChatWindowWidget then
  1834.             -- Don't add messages from blocked players
  1835.             if not this:IsPlayerBlocked(sendingPlayer) then
  1836.                 this.ChatWindowWidget:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer)
  1837.             end
  1838.         end
  1839.     end
  1840.  
  1841.     function this:OnPlayerAdded(newPlayer)
  1842.         if newPlayer then
  1843.             spawn(function() Util.IsPlayerAdminAsync(newPlayer) end)
  1844.         end
  1845.         if NON_CORESCRIPT_MODE then
  1846.             newPlayer.Chatted:connect(function(msg, recipient)
  1847.                 this:OnPlayerChatted(Enum.PlayerChatType.All, newPlayer, msg, recipient)
  1848.             end)
  1849.         else
  1850.             this.PlayerChattedConn = Util.DisconnectEvent(this.PlayerChattedConn)
  1851.             this.PlayerChattedConn = PlayersService.PlayerChatted:connect(function(...)
  1852.                 this:OnPlayerChatted(...)
  1853.             end)
  1854.         end
  1855.     end
  1856.  
  1857.     function this:IsPlayerBlockedByUserId(userId)
  1858.         for _, currentBlockedUserId in pairs(this.BlockList) do
  1859.             if currentBlockedUserId == userId then
  1860.                 return true
  1861.             end
  1862.         end
  1863.         return false
  1864.     end
  1865.  
  1866.     function this:IsPlayerBlocked(player)
  1867.         return player and this:IsPlayerBlockedByUserId(player.userId)
  1868.     end
  1869.  
  1870.     function this:GetBlockedPlayersAsync()
  1871.         local userId = Player.userId
  1872.         local secureBaseUrl = Util.GetSecureApiBaseUrl()
  1873.         local url = secureBaseUrl .. "userblock/getblockedusers" .. "?" .. "userId=" .. tostring(userId) .. "&" .. "page=" .. "1"
  1874.         if userId > 0 then
  1875.             local blockList = nil
  1876.             local success, msg = ypcall(function()
  1877.                 local request = game:HttpGetAsync(url)
  1878.                 blockList = request and game:GetService('HttpService'):JSONDecode(request)
  1879.             end)
  1880.             if blockList and blockList['success'] == true and blockList['userList'] then
  1881.                 return blockList['userList']
  1882.             end
  1883.         end
  1884.         return {}
  1885.     end
  1886.  
  1887.     function this:BlockPlayerAsync(playerToBlock)
  1888.         if playerToBlock and Player ~= playerToBlock then
  1889.             local blockUserId = playerToBlock.userId
  1890.             local playerToBlockName = playerToBlock.Name
  1891.             if blockUserId > 0 then
  1892.                 if not this:IsPlayerBlockedByUserId(blockUserId) then
  1893.                     -- TODO: We may want to use a more dynamic way of changing the blockList size.
  1894.                     --if #this.BlockList < MAX_BLOCKLIST_SIZE then
  1895.                         table.insert(this.BlockList, blockUserId)
  1896.                         this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is now blocked.")
  1897.                         -- Make Block call
  1898.                         pcall(function()
  1899.                             local success = PlayersService:BlockUser(Player.userId, blockUserId)
  1900.                         end)
  1901.                     --else
  1902.                     --  this.ChatWindowWidget:AddSystemChatMessage("You cannot block " .. playerToBlockName .. " because your list is full.")
  1903.                     --end
  1904.                 else
  1905.                     this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is already blocked.")
  1906.                 end
  1907.             else
  1908.                 this.ChatWindowWidget:AddSystemChatMessage("You cannot block guests.")
  1909.             end
  1910.         else
  1911.             this.ChatWindowWidget:AddSystemChatMessage("You cannot block yourself.")
  1912.         end
  1913.     end
  1914.  
  1915.     function this:UnblockPlayerAsync(playerToUnblock)
  1916.         if playerToUnblock then
  1917.             local unblockUserId = playerToUnblock.userId
  1918.             local playerToUnblockName = playerToUnblock.Name
  1919.  
  1920.             if this:IsPlayerBlockedByUserId(unblockUserId) then
  1921.                 local blockedUserIndex = nil
  1922.                 for index, blockedUserId in pairs(this.BlockList) do
  1923.                     if blockedUserId == unblockUserId then
  1924.                         blockedUserIndex = index
  1925.                     end
  1926.                 end
  1927.                 if blockedUserIndex then
  1928.                     table.remove(this.BlockList, blockedUserIndex)
  1929.                 end
  1930.                 this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is no longer blocked.")
  1931.                 -- Make Unblock call
  1932.                 pcall(function()
  1933.                     local success = PlayersService:UnblockUser(Player.userId, unblockUserId)
  1934.                 end)
  1935.             else
  1936.                 this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is not blocked.")
  1937.             end
  1938.         end
  1939.     end
  1940.  
  1941.     function this:CreateTouchDeviceChatButton()
  1942.         return Util.Create'ImageButton'
  1943.         {
  1944.             Name = 'TouchDeviceChatButton';
  1945.             Size = UDim2.new(0, 128, 0, 32);
  1946.             Position = UDim2.new(0, 88, 0, 0);
  1947.             BackgroundTransparency = 1.0;
  1948.             Image = 'http://www.roblox.com/asset/?id=97078724';
  1949.         };
  1950.     end
  1951.  
  1952.     function this:PrintWelcome()
  1953.         if this.ChatWindowWidget then
  1954.             this.ChatWindowWidget:AddSystemChatMessage("Please type /? for a list of commands", true)
  1955.         end
  1956.     end
  1957.  
  1958.     function this:PrintHelp()
  1959.         if this.ChatWindowWidget then
  1960.             this.ChatWindowWidget:AddSystemChatMessage("Help Menu")
  1961.             this.ChatWindowWidget:AddSystemChatMessage("Chat Commands:")
  1962.             this.ChatWindowWidget:AddSystemChatMessage("/w [PlayerName] or /whisper [PlayerName] - Whisper Chat")
  1963.             this.ChatWindowWidget:AddSystemChatMessage("/t or /team - Team Chat")
  1964.             this.ChatWindowWidget:AddSystemChatMessage("/a or /all - All Chat")
  1965.             if GetBlockedUsersFlag() then
  1966.                 this.ChatWindowWidget:AddSystemChatMessage("/block [PlayerName] or /ignore [PlayerName] - Block communications from Target Player")
  1967.                 this.ChatWindowWidget:AddSystemChatMessage("/unblock [PlayerName] or /unignore [PlayerName] - Restore communications with Target Player")
  1968.             end
  1969.         end
  1970.     end
  1971.  
  1972.     function this:CreateGUI()
  1973.         if FORCE_CHAT_GUI or Player.ChatMode == Enum.ChatMode.TextAndMenu then
  1974.             -- NOTE: eventually we will make multiple chat window frames
  1975.             this.ChatWindowWidget = CreateChatWindowWidget(this.Settings)
  1976.             this.ChatBarWidget = CreateChatBarWidget(this.Settings)
  1977.             this.ChatWindowWidget:FadeOut(0)
  1978.             local focusCount = 0
  1979.             this.ChatBarWidget.ChatBarGainedFocusEvent:connect(function()
  1980.                 focusCount = focusCount + 1
  1981.                 this.ChatWindowWidget:FadeIn(0.25)
  1982.                 this.ChatWindowWidget:SetFadeLock(true)
  1983.             end)
  1984.             this.ChatBarWidget.ChatBarLostFocusEvent:connect(function()
  1985.                 local focusNow = focusCount
  1986.                 if Util:IsTouchDevice() then
  1987.                     wait(2)
  1988.                     if focusNow == focusCount then
  1989.                         this.ChatWindowWidget:SetFadeLock(false)
  1990.                     end
  1991.                 else
  1992.                     this.ChatWindowWidget:SetFadeLock(false)
  1993.                 end
  1994.             end)
  1995.  
  1996.             this.ChatBarWidget.ChatErrorEvent:connect(function(msg)
  1997.                 if msg then
  1998.                     this.ChatWindowWidget:AddSystemChatMessage(msg)
  1999.                 end
  2000.             end)
  2001.  
  2002.             this.ChatBarWidget.ChatCommandEvent:connect(function(success, actionType, capture)
  2003.                 if actionType == "Help" then
  2004.                     this:PrintHelp()
  2005.                 elseif actionType == "Block" then
  2006.                     if GetBlockedUsersFlag() then
  2007.                         local blockPlayerName = capture and tostring(capture) or ""
  2008.                         local playerToBlock = Util.GetPlayerByName(blockPlayerName)
  2009.                         if playerToBlock then
  2010.                             spawn(function() this:BlockPlayerAsync(playerToBlock) end)
  2011.                         else
  2012.                             this.ChatWindowWidget:AddSystemChatMessage("Cannot block " .. blockPlayerName .. " because they are not in the game.")
  2013.                         end
  2014.                     end
  2015.                 elseif actionType == "Unblock" then
  2016.                     if GetBlockedUsersFlag() then
  2017.                         local unblockPlayerName = capture and tostring(capture) or ""
  2018.                         local playerToBlock = Util.GetPlayerByName(unblockPlayerName)
  2019.                         if playerToBlock then
  2020.                             spawn(function() this:UnblockPlayerAsync(playerToBlock) end)
  2021.                         else
  2022.                             this.ChatWindowWidget:AddSystemChatMessage("Cannot unblock " .. unblockPlayerName .. " because they are not in the game.")
  2023.                         end
  2024.                     end
  2025.                 elseif actionType == "Whisper" then
  2026.                     if success == false then
  2027.                         local playerName = capture and tostring(capture) or "Unknown"
  2028.                         this.ChatWindowWidget:AddSystemChatMessage("Unable to Send a Whisper to Player: " .. playerName)
  2029.                     end
  2030.                 elseif actionType == "Unknown" then
  2031.                     if success == false then
  2032.                         local commandText = capture and tostring(capture) or "Unknown"
  2033.                         this.ChatWindowWidget:AddSystemChatMessage("Invalid Slash Command: " .. commandText)
  2034.                     end
  2035.                 end
  2036.             end)
  2037.  
  2038.             if Util.IsTouchDevice() then
  2039.                 local mobileChatButton = this:CreateTouchDeviceChatButton()
  2040.                 if StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat) then
  2041.                     mobileChatButton.Parent = GuiRoot
  2042.                 end
  2043.  
  2044.                 mobileChatButton.TouchTap:connect(function()
  2045.                     mobileChatButton.Visible = false
  2046.                     if this.ChatBarWidget then
  2047.                         this.ChatBarWidget:FocusChatBar()
  2048.                     end
  2049.                 end)
  2050.  
  2051.                 this.ChatBarWidget.ChatBarLostFocusEvent:connect(function()
  2052.                     mobileChatButton.Visible = true
  2053.                 end)
  2054.  
  2055.                 this.MobileChatButton = mobileChatButton
  2056.             end
  2057.         end
  2058.     end
  2059.  
  2060.     function this:Initialize()
  2061.         if GetBlockedUsersFlag() then
  2062.             spawn(function()
  2063.                 this.BlockList = this:GetBlockedPlayersAsync()
  2064.             end)
  2065.         end
  2066.  
  2067.         this:OnPlayerAdded(Player)
  2068.         -- Upsettingly, it seems everytime a player is added, you have to redo the connection
  2069.         -- NOTE: PlayerAdded only fires on the server, hence ChildAdded is used here
  2070.         PlayersService.ChildAdded:connect(function(child)
  2071.             if child:IsA('Player') then
  2072.                 this:OnPlayerAdded(child)
  2073.             end
  2074.         end)
  2075.  
  2076.         this:CreateGUI()
  2077.  
  2078.  
  2079.         this:CoreGuiChanged(Enum.CoreGuiType.Chat, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat))
  2080.         this.CoreGuiChangedConn = Util.DisconnectEvent(this.CoreGuiChangedConn)
  2081.         pcall(function()
  2082.             this.CoreGuiChangedConn = StarterGui.CoreGuiChangedSignal:connect(
  2083.                 function(coreGuiType,enabled)
  2084.                     this:CoreGuiChanged(coreGuiType, enabled)
  2085.                 end)
  2086.         end)
  2087.  
  2088.         if not NON_CORESCRIPT_MODE then
  2089.             this:PrintWelcome()
  2090.         end
  2091.     end
  2092.  
  2093.     return this
  2094. end
  2095.  
  2096. -- Main Entry Point
  2097. do
  2098.     local ChatInstance = CreateChat()
  2099.     ChatInstance:Initialize()
  2100. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement