Advertisement
Guest User

Custom Roblox Leaderboard

a guest
Mar 2nd, 2017
2,315
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 55.27 KB | None | 0 0
  1. --[[
  2.   // FileName: PlayerlistModule.lua
  3.   // Version 1.3
  4.   // Written by: jmargh
  5.   // Description: Implementation of in game player list and leaderboard
  6. ]]
  7. game:GetService("StarterGui"):SetCoreGuiEnabled(0, false)
  8. local CoreGui = game:GetService('CoreGui')
  9. local GuiService = game:GetService('GuiService')    -- NOTE: Can only use in core scripts
  10. local UserInputService = game:GetService('UserInputService')
  11. local TeamsService = game:FindService('Teams')
  12. local ContextActionService = game:GetService('ContextActionService')
  13. local StarterGui = game:GetService('StarterGui')
  14. local PlayersService = game:GetService('Players')
  15. local Settings = UserSettings()
  16. local GameSettings = Settings.GameSettings
  17.  
  18. local RbxGuiLibrary = nil
  19. if LoadLibrary then
  20.   RbxGuiLibrary = LoadLibrary("RbxGui")
  21. end
  22.  
  23. while not PlayersService.LocalPlayer do
  24.     -- This does not follow the usual pattern of PlayersService:PlayerAdded:Wait()
  25.     -- because it caused a bug where the local players name would show as Player in game.
  26.     -- The local players name is not yet set when the PlayerAdded event fires.
  27.   wait()
  28. end
  29.  
  30. local Player = PlayersService.LocalPlayer
  31. local RobloxGui = CoreGui:WaitForChild('RobloxGui')
  32.  
  33. local StatsUtils = require(RobloxGui.Modules.Stats.StatsUtils)
  34.  
  35. local TenFootInterface = require(RobloxGui.Modules.TenFootInterface)
  36. local isTenFootInterface = TenFootInterface:IsEnabled()
  37.  
  38. local playerDropDownModule = require(RobloxGui.Modules.PlayerDropDown)
  39. local blockingUtility = playerDropDownModule:CreateBlockingUtility()
  40. local playerDropDown = playerDropDownModule:CreatePlayerDropDown()
  41.  
  42. local PlayerPermissionsModule = require(RobloxGui.Modules.PlayerPermissionsModule)
  43.  
  44. --[[ Remotes ]]--
  45. local RemoveEvent_OnFollowRelationshipChanged = nil
  46. local RemoteFunc_GetFollowRelationships = nil
  47.  
  48. --[[ Start Module ]]--
  49. local Playerlist = {}
  50.  
  51. --[[ Public Event API ]]--
  52. -- Parameters: Sorted Array - see GameStats below
  53. Playerlist.OnLeaderstatsChanged = Instance.new('BindableEvent')
  54. -- Parameters: nameOfStat(string), formatedStringOfStat(string)
  55. Playerlist.OnStatChanged = Instance.new('BindableEvent')
  56.  
  57. --[[ Client Stat Table ]]--
  58. -- Sorted Array of tables
  59. local GameStats = {}
  60. -- Fields
  61. -- Name: String the developer has given the stat
  62. -- Text: Formated string of the stat value
  63. -- AddId: Child add order id
  64. -- IsPrimary: Is this the primary stat
  65. -- Priority: Sorting priority
  66. -- NOTE: IsPrimary and Priority are unofficially supported. They are left over legacy from the old player list.
  67. -- They can be un-supported at anytime. You should prefer using child add order to order your stats in the leader board.
  68.  
  69. --[[ Script Variables ]]--
  70. local topbarEnabled = true
  71. local playerlistCoreGuiEnabled = true
  72. local MyPlayerEntryTopFrame = nil
  73. local PlayerEntries = {}
  74. local StatAddId = 0
  75. local TeamEntries = {}
  76. local TeamAddId = 0
  77. local NeutralTeam = nil
  78. local IsShowingNeutralFrame = false
  79. local LastSelectedFrame = nil
  80. local LastSelectedPlayer = nil
  81. local MinContainerSize = UDim2.new(0, 165, 0.5, 0)
  82. if isTenFootInterface then
  83.   MinContainerSize = UDim2.new(0, 1000, 0, 720)
  84. end
  85. local TempHideKeys = {}
  86.  
  87. local PlayerEntrySizeY = 24
  88. if isTenFootInterface then
  89.   PlayerEntrySizeY = 80
  90. end
  91.  
  92. local TeamEntrySizeY = 18
  93.  
  94. if isTenFootInterface then
  95.   TeamEntrySizeY = 32
  96. end
  97.  
  98. local NameEntrySizeX = 170
  99. if isTenFootInterface then
  100.   NameEntrySizeX = 350
  101. end
  102.  
  103. local StatEntrySizeX = 75
  104. if isTenFootInterface then
  105.   StatEntrySizeX = 250
  106. end
  107.  
  108. local IsSmallScreenDevice = UserInputService.TouchEnabled and GuiService:GetScreenResolution().Y <= 500
  109.  
  110. local BaseUrl = game:GetService('ContentProvider').BaseUrl:lower()
  111. BaseUrl = string.gsub(BaseUrl, "/m.", "/www.")
  112. AssetGameUrl = string.gsub(BaseUrl, 'www', 'assetgame')
  113.  
  114. --[[ Constants ]]--
  115. local ENTRY_PAD = 2
  116. local BG_TRANSPARENCY = 0.5
  117. local BG_COLOR = Color3.new(31/255, 31/255, 31/255)
  118. local BG_COLOR_TOP = Color3.new(106/255, 106/255, 106/255)
  119. local TEXT_STROKE_TRANSPARENCY = 0.75
  120. local TEXT_COLOR = Color3.new(1, 1, 243/255)
  121. local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255)
  122. local TWEEN_TIME = 0.15
  123. local MAX_LEADERSTATS = 4
  124. local MAX_STR_LEN = 12
  125. local TILE_SPACING = 2
  126. if isTenFootInterface then
  127.   BG_COLOR_TOP = Color3.new(25/255, 25/255, 25/255)
  128.   BG_COLOR = Color3.new(60/255, 60/255, 60/255)
  129.   BG_TRANSPARENCY = 0.25
  130.   TEXT_STROKE_TRANSPARENCY = 1
  131.   TILE_SPACING = 5
  132. end
  133. local SHADOW_IMAGE = 'rbxasset://textures/ui/PlayerList/TileShadowMissingTop.png'--'http://www.roblox.com/asset?id=286965900'
  134. local SHADOW_SLICE_SIZE = 5
  135. local SHADOW_SLICE_RECT = Rect.new(SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE*2-1, SHADOW_SLICE_SIZE*2-1)
  136.  
  137. local CUSTOM_ICONS = {  -- Admins with special icons
  138.   ['7210880'] = 'rbxassetid://134032333', -- Jeditkacheff
  139.   ['13268404'] = 'rbxassetid://113059239', -- Sorcus
  140.   ['261'] = 'rbxassetid://105897927', -- shedlestky
  141.   ['20396599'] = 'rbxassetid://161078086', -- Robloxsai
  142.   ['34929389'] = 'rbxassetid://677262892', -- TheGrimDeathZombie
  143. }
  144.  
  145. local ABUSES = {
  146.   "Swearing",
  147.   "Bullying",
  148.   "Scamming",
  149.   "Dating",
  150.   "Cheating/Exploiting",
  151.   "Personal Questions",
  152.   "Offsite Links",
  153.   "Bad Username",
  154. }
  155.  
  156. --[[ Images ]]--
  157. local CHAT_ICON = 'rbxasset://textures/ui/chat_teamButton.png'
  158. local ADMIN_ICON = 'rbxasset://textures/ui/icon_admin-16.png'
  159. local INTERN_ICON = 'rbxasset://textures/ui/icon_intern-16.png'
  160. local PLACE_OWNER_ICON = 'rbxasset://textures/ui/icon_placeowner.png'
  161. local BC_ICON = 'rbxasset://textures/ui/icon_BC-16.png'
  162. local TBC_ICON = 'rbxasset://textures/ui/icon_TBC-16.png'
  163. local OBC_ICON = 'rbxasset://textures/ui/icon_OBC-16.png'
  164. local BLOCKED_ICON = 'rbxasset://textures/ui/PlayerList/BlockedIcon.png'
  165. local FRIEND_ICON = 'rbxasset://textures/ui/icon_friends_16.png'
  166. local FRIEND_REQUEST_ICON = 'rbxasset://textures/ui/icon_friendrequestsent_16.png'
  167. local FRIEND_RECEIVED_ICON = 'rbxasset://textures/ui/icon_friendrequestrecieved-16.png'
  168.  
  169. local FOLLOWER_ICON = 'rbxasset://textures/ui/icon_follower-16.png'
  170. local FOLLOWING_ICON = 'rbxasset://textures/ui/icon_following-16.png'
  171. local MUTUAL_FOLLOWING_ICON = 'rbxasset://textures/ui/icon_mutualfollowing-16.png'
  172.  
  173. local CHARACTER_BACKGROUND_IMAGE = 'rbxasset://textures/ui/PlayerList/CharacterBackgroundImage.png'
  174.  
  175. --[[ Helper Functions ]]--
  176. local function clamp(value, min, max)
  177.   if value < min then
  178.     value = min
  179.   elseif value > max then
  180.     value = max
  181.   end
  182.  
  183.   return value
  184. end
  185.  
  186. local function getFriendStatusIcon(friendStatus)
  187.   if friendStatus == Enum.FriendStatus.Unknown or friendStatus == Enum.FriendStatus.NotFriend then
  188.     return nil
  189.   elseif friendStatus == Enum.FriendStatus.Friend then
  190.     return FRIEND_ICON
  191.   elseif friendStatus == Enum.FriendStatus.FriendRequestSent then
  192.     return FRIEND_REQUEST_ICON
  193.   elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then
  194.     return FRIEND_RECEIVED_ICON
  195.   else
  196.     error("PlayerList: Unknown value for friendStatus: "..tostring(friendStatus))
  197.   end
  198. end
  199.  
  200. local function getCustomPlayerIcon(player)
  201.   local userIdStr = tostring(player.UserId)
  202.   if CUSTOM_ICONS[userIdStr] then return nil end
  203.   --
  204.  
  205.   if PlayerPermissionsModule.IsPlayerAdminAsync(player) then
  206.     return ADMIN_ICON
  207.   elseif PlayerPermissionsModule.IsPlayerInternAsync(player) then
  208.     return INTERN_ICON
  209.   end
  210. end
  211.  
  212. local function setAvatarIconAsync(player, iconImage)
  213.   -- this function is pretty much for xbox right now and makes use of modules that are part
  214.   -- of the xbox app. Please see Kip or Jason if you have any questions
  215.   local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function() return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end)
  216.   local thumbsUrl = BaseUrl
  217.   if(useSubdomainsFlagExists and useSubdomainsFlagValue and AssetGameUrl~=nil) then
  218.     thumbsUrl = AssetGameUrl
  219.   end
  220.  
  221.   local thumbnailLoader = nil
  222.   pcall(function()
  223.     thumbnailLoader = require(RobloxGui.Modules.Shell.ThumbnailLoader)
  224.   end)
  225.  
  226.   local isFinalSuccess = false
  227.   if thumbnailLoader then
  228.     local loader = thumbnailLoader:Create(iconImage, player.UserId,
  229.       thumbnailLoader.Sizes.Small, thumbnailLoader.AssetType.Avatar, true)
  230.     isFinalSuccess = loader:LoadAsync(false, true, nil)
  231.   end
  232.  
  233.   if not isFinalSuccess then
  234.     iconImage.Image = 'rbxasset://textures/ui/Shell/Icons/DefaultProfileIcon.png'
  235.   end
  236. end
  237.  
  238. local function getMembershipIcon(player)
  239.   if isTenFootInterface then
  240.     -- return nothing, we need to spawn off setAvatarIconAsync() as a later time to not block
  241.     return ""
  242.   else
  243.     if blockingUtility:IsPlayerBlockedByUserId(player.UserId) then
  244.       return BLOCKED_ICON
  245.     else
  246.       local userIdStr = tostring(player.UserId)
  247.       local membershipType = player.MembershipType
  248.       if CUSTOM_ICONS[userIdStr] then
  249.         return CUSTOM_ICONS[userIdStr]
  250.       elseif player.UserId == game.CreatorId and game.CreatorType == Enum.CreatorType.User then
  251.         return PLACE_OWNER_ICON
  252.       elseif membershipType == Enum.MembershipType.None then
  253.         return ""
  254.       elseif membershipType == Enum.MembershipType.BuildersClub then
  255.         return BC_ICON
  256.       elseif membershipType == Enum.MembershipType.TurboBuildersClub then
  257.         return TBC_ICON
  258.       elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then
  259.         return OBC_ICON
  260.       else
  261.         return ""
  262.       end
  263.     end
  264.   end
  265.  
  266.   return ""
  267. end
  268.  
  269. local function isValidStat(obj)
  270.   return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or
  271.   obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue')
  272. end
  273.  
  274. local function sortPlayerEntries(a, b)
  275.   if a.PrimaryStat == b.PrimaryStat then
  276.     return a.Player.Name:upper() < b.Player.Name:upper()
  277.   end
  278.   if not a.PrimaryStat then return false end
  279.   if not b.PrimaryStat then return true end
  280.   local statA = a.PrimaryStat
  281.   local statB = b.PrimaryStat
  282.   statA = tonumber(statA) or statA
  283.   statB = tonumber(statB) or statB
  284.   if type(statA) ~= type(statB) then
  285.     statA = tostring(statA)
  286.     statB = tostring(statB)
  287.   end
  288.   return statA > statB
  289. end
  290.  
  291. local function sortLeaderStats(a, b)
  292.   if a.IsPrimary ~= b.IsPrimary then
  293.     return a.IsPrimary
  294.   end
  295.   if a.Priority == b.Priority then
  296.     return a.AddId < b.AddId
  297.   end
  298.   return a.Priority < b.Priority
  299. end
  300.  
  301. local function sortTeams(a, b)
  302.   if a.TeamScore == b.TeamScore then
  303.     return a.Id < b.Id
  304.   end
  305.   if not a.TeamScore then return false end
  306.   if not b.TeamScore then return true end
  307.   return a.TeamScore < b.TeamScore
  308. end
  309.  
  310. -- Start of Gui Creation
  311. local Container = Instance.new('Frame')
  312. Container.Name = "PlayerListContainer"
  313. Container.Size = MinContainerSize
  314.  
  315. if isTenFootInterface then
  316.   Container.Position = UDim2.new(0.5, -MinContainerSize.X.Offset/2, 0.25, 0)
  317. else
  318.   Container.Position = UDim2.new(1, -167, 0, 2)
  319. end
  320.  
  321. -- Every time Performance Stats toggles on/off we need to
  322. -- reposition the main Container, so things don't overlap.
  323. -- Optimally I could just call an "UpdateContainerPosition" function
  324. -- that takes into account everything that affects Container position
  325. -- and recalculate things.
  326. --
  327. -- Unfortunately, the position of Container may be kind of hard to re-calculate
  328. -- on the fly when it's been shaped based on current leader board state.
  329. --
  330. -- So instead we do this:
  331. -- We always track where we'd be putting the widget if there were no
  332. -- position stats in targetContainerYOffset.
  333. -- Whenever we reposition Container, we first move it to the ignoring-stats
  334. -- location, (updating targetContainerYOffset), then call the
  335. -- AdjustContainerPosition function to derive final position.
  336. local targetContainerYOffset = Container.Position.Y.Offset
  337.  
  338. Container.BackgroundTransparency = 1
  339. Container.Visible = false
  340. Container.Parent = RobloxGui
  341.  
  342. local function AdjustContainerPosition()
  343.   -- A function to position the Container in light of presence of performance stats.
  344.   if Container == nil then
  345.     return
  346.   end
  347.  
  348.   -- Account for presence/absence of performance stats buttons.
  349.   local localPlayer = PlayersService.LocalPlayer
  350.   local isPerformanceStatsVisible = (GameSettings.PerformanceStatsVisible and localPlayer ~= nil)
  351.   local yOffset = targetContainerYOffset
  352.   if isPerformanceStatsVisible then
  353.     yOffset = yOffset + StatsUtils.ButtonHeight
  354.   end
  355.  
  356.   Container.Position = UDim2.new(Container.Position.X.Scale,
  357.     Container.Position.X.Offset,
  358.     Container.Position.Y.Scale,
  359.     yOffset)
  360. end
  361.  
  362. -- When quick profiler button row visiblity changes, update position of
  363. -- Container.
  364. GameSettings.PerformanceStatsVisibleChanged:connect(AdjustContainerPosition)
  365. AdjustContainerPosition()
  366.  
  367. -- Scrolling Frame
  368. local noSelectionObject = Instance.new("Frame")
  369. noSelectionObject.BackgroundTransparency = 1
  370. noSelectionObject.BorderSizePixel = 0
  371.  
  372. local ScrollList = Instance.new('ScrollingFrame')
  373. ScrollList.Name = "ScrollList"
  374. ScrollList.Size = UDim2.new(1, -1, 0, 0)
  375. if isTenFootInterface then
  376.   ScrollList.Position = UDim2.new(0, 0, 0, PlayerEntrySizeY + TILE_SPACING)
  377.   ScrollList.Size = UDim2.new(1, 19, 0, 0)
  378. end
  379. ScrollList.BackgroundTransparency = 1
  380. ScrollList.BackgroundColor3 = Color3.new()
  381. ScrollList.BorderSizePixel = 0
  382. ScrollList.CanvasSize = UDim2.new(0, 0, 0, 0)   -- NOTE: Look into if x needs to be set to anything
  383. ScrollList.ScrollBarThickness = 6
  384. ScrollList.BottomImage = 'rbxasset://textures/ui/scroll-bottom.png'
  385. ScrollList.MidImage = 'rbxasset://textures/ui/scroll-middle.png'
  386. ScrollList.TopImage = 'rbxasset://textures/ui/scroll-top.png'
  387. ScrollList.SelectionImageObject = noSelectionObject
  388. ScrollList.Selectable = false
  389. ScrollList.Parent = Container
  390.  
  391. -- PlayerDropDown clipping frame
  392. local PopupClipFrame = Instance.new('Frame')
  393. PopupClipFrame.Name = "PopupClipFrame"
  394. PopupClipFrame.Size = UDim2.new(0, 150, 1.5, 0)
  395. PopupClipFrame.Position = UDim2.new(0, -150 - ENTRY_PAD, 0, 0)
  396. PopupClipFrame.BackgroundTransparency = 1
  397. PopupClipFrame.ClipsDescendants = true
  398. PopupClipFrame.Parent = Container
  399.  
  400.  
  401. --[[ Creation Helper Functions ]]--
  402. local function createEntryFrame(name, sizeYOffset, isTopStat)
  403.   local containerFrame = Instance.new('Frame')
  404.   containerFrame.Name = name
  405.   containerFrame.Position = UDim2.new(0, 0, 0, 0)
  406.   containerFrame.Size = UDim2.new(1, 0, 0, sizeYOffset)
  407.   if isTenFootInterface then
  408.     containerFrame.Position = UDim2.new(0, 10, 0, 0)
  409.     containerFrame.Size = containerFrame.Size + UDim2.new(0, -20, 0, 0)
  410.   end
  411.   containerFrame.BackgroundTransparency = 1
  412.   containerFrame.ZIndex = isTenFootInterface and 2 or 1
  413.  
  414.   local nameFrame = Instance.new('TextButton')
  415.   nameFrame.Name = "BGFrame"
  416.   nameFrame.Position = UDim2.new(0, 0, 0, 0)
  417.   nameFrame.Size = UDim2.new(0, NameEntrySizeX, 0, sizeYOffset)
  418.   nameFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY
  419.   nameFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR
  420.   nameFrame.BorderSizePixel = 0
  421.   nameFrame.AutoButtonColor = false
  422.   nameFrame.Text = ""
  423.   nameFrame.Parent = containerFrame
  424.   nameFrame.ZIndex = isTenFootInterface and 2 or 1
  425.  
  426.   return containerFrame, nameFrame
  427. end
  428.  
  429. local function createEntryNameText(name, text, sizeXOffset, posXOffset)
  430.   local nameLabel = Instance.new('TextLabel')
  431.   nameLabel.Name = name
  432.   nameLabel.Size = UDim2.new(-0.01, sizeXOffset, 1, 0)
  433.   nameLabel.Position = UDim2.new(0.01, posXOffset, 0, 0)
  434.   nameLabel.BackgroundTransparency = 1
  435.   nameLabel.Font = Enum.Font.SourceSans
  436.   if isTenFootInterface then
  437.     nameLabel.FontSize = Enum.FontSize.Size32
  438.   else
  439.     nameLabel.FontSize = Enum.FontSize.Size14
  440.   end
  441.   nameLabel.TextColor3 = TEXT_COLOR
  442.   nameLabel.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
  443.   nameLabel.TextStrokeColor3 = TEXT_STROKE_COLOR
  444.   nameLabel.TextXAlignment = Enum.TextXAlignment.Left
  445.   nameLabel.ClipsDescendants = true
  446.   nameLabel.Text = text
  447.   nameLabel.ZIndex = isTenFootInterface and 2 or 1
  448.  
  449.   return nameLabel
  450. end
  451.  
  452. local function createStatFrame(offset, parent, name, isTopStat)
  453.   local statFrame = Instance.new('Frame')
  454.   statFrame.Name = name
  455.   statFrame.Size = UDim2.new(0, StatEntrySizeX, 1, 0)
  456.   statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0)
  457.   statFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY
  458.   statFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR
  459.   statFrame.BorderSizePixel = 0
  460.   statFrame.Parent = parent
  461.  
  462.   if isTenFootInterface then
  463.     statFrame.ZIndex = 2
  464.  
  465.     local shadow = Instance.new("ImageLabel")
  466.     shadow.BackgroundTransparency = 1
  467.     shadow.Name = 'Shadow'
  468.     shadow.Image = SHADOW_IMAGE
  469.     shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0)
  470.     shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE)
  471.     shadow.ScaleType = 'Slice'
  472.     shadow.SliceCenter = SHADOW_SLICE_RECT
  473.     shadow.Parent = statFrame
  474.   end
  475.  
  476.   return statFrame
  477. end
  478.  
  479. local function createStatText(parent, text, isTopStat, isTeamStat)
  480.   local statText = Instance.new('TextLabel')
  481.   statText.Name = "StatText"
  482.   statText.Size = isTopStat and UDim2.new(1, 0, 0.5, 0) or UDim2.new(1, 0, 1, 0)
  483.   statText.Position = isTopStat and UDim2.new(0, 0, 0.5, 0) or UDim2.new(0, 0, 0, 0)
  484.   statText.BackgroundTransparency = 1
  485.   statText.Font = isTopStat and Enum.Font.SourceSansBold or Enum.Font.SourceSans
  486.   if isTenFootInterface then
  487.     statText.FontSize = Enum.FontSize.Size32
  488.   else
  489.     statText.FontSize = Enum.FontSize.Size14
  490.   end
  491.   statText.TextColor3 = TEXT_COLOR
  492.   statText.TextStrokeColor3 = TEXT_STROKE_COLOR
  493.   statText.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
  494.   statText.Text = text
  495.   statText.Active = true
  496.   statText.Parent = parent
  497.   if isTenFootInterface then
  498.     statText.ZIndex = 2
  499.   end
  500.  
  501.   if isTopStat then
  502.     local statName = statText:Clone()
  503.     statName.Name = "StatName"
  504.     statName.Text = tostring(parent.Name)
  505.     statName.Position = UDim2.new(0,0,0,0)
  506.     statName.Font = Enum.Font.SourceSans
  507.     statName.ClipsDescendants = true
  508.     statName.Parent = parent
  509.     if isTenFootInterface then
  510.       statName.ZIndex = 2
  511.     end
  512.   end
  513.  
  514.   if isTeamStat then
  515.     statText.Font = 'SourceSansBold'
  516.   end
  517.  
  518.   return statText
  519. end
  520.  
  521. local function createImageIcon(image, name, xOffset, parent)
  522.   local imageLabel = Instance.new('ImageLabel')
  523.   imageLabel.Name = name
  524.   if isTenFootInterface then
  525.     imageLabel.Size = UDim2.new(0, 64, 0, 64)
  526.     imageLabel.ZIndex = 2
  527.  
  528.     local background = Instance.new("ImageLabel", imageLabel)
  529.     background.Name = 'Background'
  530.     background.BackgroundTransparency = 1
  531.     background.Image = CHARACTER_BACKGROUND_IMAGE
  532.     background.Size = UDim2.new(0, 66, 0, 66)
  533.     background.Position = UDim2.new(0.5, -66/2, 0.5, -66/2)
  534.     background.ZIndex = 2
  535.   else
  536.     imageLabel.Size = UDim2.new(0, 16, 0, 16)
  537.   end
  538.   imageLabel.Position = UDim2.new(0.01, xOffset, 0.5, -imageLabel.Size.Y.Offset/2)
  539.   imageLabel.BackgroundTransparency = 1
  540.   imageLabel.Image = image
  541.   imageLabel.BorderSizePixel = 0
  542.   imageLabel.Parent = parent
  543.  
  544.   return imageLabel
  545. end
  546.  
  547. local function getScoreValue(statObject)
  548.   if statObject:IsA('DoubleConstrainedValue') or statObject:IsA('IntConstrainedValue') then
  549.     return statObject.ConstrainedValue
  550.   elseif statObject:IsA('BoolValue') then
  551.     if statObject.Value then return 1 else return 0 end
  552.   else
  553.     return statObject.Value
  554.   end
  555. end
  556.  
  557. local THIN_CHARS = "[^%[iIl\%.,']"
  558. local function strWidth(str)
  559.   return string.len(str) - math.floor(string.len(string.gsub(str, THIN_CHARS, "")) / 2)
  560. end
  561.  
  562. local function formatNumber(value)
  563.   local _,_,minusSign, int, fraction = tostring(value):find('([-]?)(%d+)([.]?%d*)')
  564.   int = int:reverse():gsub("%d%d%d", "%1,")
  565.   return minusSign..int:reverse():gsub("^,", "")..fraction
  566. end
  567.  
  568. local function formatStatString(text)
  569.   local numberValue = tonumber(text)
  570.   if numberValue then
  571.     text = formatNumber(numberValue)
  572.   end
  573.  
  574.   if strWidth(text) <= MAX_STR_LEN then
  575.     return text
  576.   else
  577.     return string.sub(text, 1, MAX_STR_LEN - 3).."..."
  578.   end
  579. end
  580.  
  581. --[[ Resize Functions ]]--
  582. local LastMaxScrollSize = 0
  583. local function setScrollListSize()
  584.   local teamSize = #TeamEntries * TeamEntrySizeY
  585.   local playerSize = #PlayerEntries * PlayerEntrySizeY
  586.   local spacing = #PlayerEntries * ENTRY_PAD + #TeamEntries * ENTRY_PAD
  587.   local canvasSize = teamSize + playerSize + spacing
  588.   if #TeamEntries > 0 and NeutralTeam and IsShowingNeutralFrame then
  589.     canvasSize = canvasSize + TeamEntrySizeY + ENTRY_PAD
  590.   end
  591.   ScrollList.CanvasSize = UDim2.new(0, 0, 0, canvasSize)
  592.   local newScrollListSize = math.min(canvasSize, Container.AbsoluteSize.y)
  593.   if ScrollList.Size.Y.Offset == LastMaxScrollSize then
  594.     if isTenFootInterface then
  595.       ScrollList.Size = UDim2.new(1, 20, 0, newScrollListSize)
  596.     else
  597.       ScrollList.Size = UDim2.new(1, 0, 0, newScrollListSize)
  598.     end
  599.   end
  600.   LastMaxScrollSize = newScrollListSize
  601. end
  602.  
  603. --[[ Re-position Functions ]]--
  604. local function setPlayerEntryPositions()
  605.   local position = 0
  606.   for i = 1, #PlayerEntries do
  607.     if isTenFootInterface and PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then
  608.       PlayerEntries[i].Frame.Position = UDim2.new(0, 10, 0, position)
  609.       position = position + PlayerEntrySizeY + TILE_SPACING
  610.     elseif PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then
  611.       PlayerEntries[i].Frame.Position = UDim2.new(0, 0, 0, position)
  612.       position = position + PlayerEntrySizeY + TILE_SPACING
  613.     end
  614.   end
  615. end
  616.  
  617. local function setTeamEntryPositions()
  618.   local teams = {}
  619.   for _,teamEntry in ipairs(TeamEntries) do
  620.     local team = teamEntry.Team
  621.     teams[tostring(team.TeamColor)] = {}
  622.   end
  623.   if NeutralTeam then
  624.     teams.Neutral = {}
  625.   end
  626.  
  627.   for _,playerEntry in ipairs(PlayerEntries) do
  628.     if playerEntry.Frame ~= MyPlayerEntryTopFrame then
  629.       local player = playerEntry.Player
  630.       if player.Neutral then
  631.         table.insert(teams.Neutral, playerEntry)
  632.       elseif teams[tostring(player.TeamColor)] then
  633.         table.insert(teams[tostring(player.TeamColor)], playerEntry)
  634.       else
  635.         table.insert(teams.Neutral, playerEntry)
  636.       end
  637.     end
  638.   end
  639.  
  640.   local position = 0
  641.   for _,teamEntry in ipairs(TeamEntries) do
  642.     local team = teamEntry.Team
  643.     teamEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position)
  644.     position = position + TeamEntrySizeY + TILE_SPACING
  645.     local players = teams[tostring(team.TeamColor)]
  646.     for _,playerEntry in ipairs(players) do
  647.       playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position)
  648.       position = position + PlayerEntrySizeY + TILE_SPACING
  649.     end
  650.   end
  651.   if NeutralTeam then
  652.     NeutralTeam.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position)
  653.     position = position + TeamEntrySizeY + TILE_SPACING
  654.     if #teams.Neutral > 0 then
  655.       IsShowingNeutralFrame = true
  656.       local players = teams.Neutral
  657.       for _,playerEntry in ipairs(players) do
  658.         playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position)
  659.         position = position + PlayerEntrySizeY + TILE_SPACING
  660.       end
  661.     else
  662.       IsShowingNeutralFrame = false
  663.     end
  664.   end
  665. end
  666.  
  667. local function setEntryPositions()
  668.   table.sort(PlayerEntries, sortPlayerEntries)
  669.   if #TeamEntries > 0 then
  670.     setTeamEntryPositions()
  671.   else
  672.     setPlayerEntryPositions()
  673.   end
  674. end
  675.  
  676. local function updateSocialIcon(newIcon, bgFrame)
  677.   local socialIcon = bgFrame:FindFirstChild('SocialIcon')
  678.   local nameFrame = bgFrame:FindFirstChild('PlayerName')
  679.   local offset = 19
  680.   if socialIcon then
  681.     if newIcon then
  682.       socialIcon.Image = newIcon
  683.     else
  684.       if nameFrame then
  685.         local newSize = nameFrame.Size.X.Offset + socialIcon.Size.X.Offset + 2
  686.         nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0)
  687.         nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0)
  688.       end
  689.       socialIcon:Destroy()
  690.     end
  691.   elseif newIcon and bgFrame then
  692.     socialIcon = createImageIcon(newIcon, "SocialIcon", offset, bgFrame)
  693.     offset = offset + socialIcon.Size.X.Offset + 2
  694.     if nameFrame then
  695.       local newSize = bgFrame.Size.X.Offset - offset
  696.       nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0)
  697.       nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0)
  698.     end
  699.   end
  700. end
  701.  
  702. local function getFriendStatus(selectedPlayer)
  703.   if selectedPlayer == Player then
  704.     return Enum.FriendStatus.NotFriend
  705.   else
  706.     local success, result = pcall(function()
  707.         -- NOTE: Core script only
  708.         return Player:GetFriendStatus(selectedPlayer)
  709.       end)
  710.     if success then
  711.       return result
  712.     else
  713.       return Enum.FriendStatus.NotFriend
  714.     end
  715.   end
  716. end
  717.  
  718. function popupHidden()
  719.   if LastSelectedFrame then
  720.     for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do
  721.       if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then
  722.         childFrame.BackgroundColor3 = BG_COLOR
  723.       end
  724.     end
  725.   end
  726.   ScrollList.ScrollingEnabled = true
  727.   LastSelectedFrame = nil
  728.   LastSelectedPlayer = nil
  729. end
  730. playerDropDown.HiddenSignal:connect(popupHidden)
  731.  
  732. local function openPlatformProfileUI(rbxUid)
  733.   if not rbxUid or rbxUid < 1 then return end
  734.   pcall(function()
  735.       local platformService = game:GetService('PlatformService')
  736.       local platformId = platformService:GetPlatformId(rbxUid)
  737.       if platformId and #platformId > 0 then
  738.         platformService:PopupProfileUI(Enum.UserInputType.Gamepad1, platformId)
  739.       end
  740.     end)
  741. end
  742.  
  743. local function onEntryFrameSelected(selectedFrame, selectedPlayer)
  744.   if isTenFootInterface then
  745.     -- open the profile UI for the selected user. On console we allow user to select themselves
  746.     -- they may want quick access to platform profile features
  747.     openPlatformProfileUI(selectedPlayer.UserId)
  748.     return
  749.   end
  750.  
  751.   if selectedPlayer ~= Player and selectedPlayer.UserId > 1 and Player.UserId > 1 then
  752.     if LastSelectedFrame ~= selectedFrame then
  753.       if LastSelectedFrame then
  754.         for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do
  755.           if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then
  756.             childFrame.BackgroundColor3 = BG_COLOR
  757.           end
  758.         end
  759.       end
  760.       LastSelectedFrame = selectedFrame
  761.       LastSelectedPlayer = selectedPlayer
  762.       for _,childFrame in pairs(selectedFrame:GetChildren()) do
  763.         if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then
  764.           childFrame.BackgroundColor3 = Color3.new(0, 1, 1)
  765.         end
  766.       end
  767.       -- NOTE: Core script only
  768.       ScrollList.ScrollingEnabled = false
  769.  
  770.       local PopupFrame = playerDropDown:CreatePopup(selectedPlayer)
  771.       PopupFrame.Position = UDim2.new(1, 1, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y)
  772.       PopupFrame.Parent = PopupClipFrame
  773.       PopupFrame:TweenPosition(UDim2.new(0, 0, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y), Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, TWEEN_TIME, true)
  774.     else
  775.       playerDropDown:Hide()
  776.       LastSelectedFrame = nil
  777.       LastSelectedPlayer = nil
  778.     end
  779.   end
  780. end
  781.  
  782. local function onFriendshipChanged(otherPlayer, newFriendStatus)
  783.   local entryToUpdate = nil
  784.   for _,entry in ipairs(PlayerEntries) do
  785.     if entry.Player == otherPlayer then
  786.       entryToUpdate = entry
  787.       break
  788.     end
  789.   end
  790.   if not entryToUpdate then
  791.     return
  792.   end
  793.   local newIcon = getFriendStatusIcon(newFriendStatus)
  794.   local frame = entryToUpdate.Frame
  795.   local bgFrame = frame:FindFirstChild('BGFrame')
  796.   if bgFrame then
  797.     --no longer friends, but might still be following
  798.     -- TODO: We need to get follow relationship here; we currently don't have a way
  799.     -- to get a single users result, so the server script will need to be updated
  800.     -- issue will be when unfriending a user, but still following them, the icon
  801.     -- will not show correctly.
  802.     updateSocialIcon(newIcon, bgFrame)
  803.   end
  804. end
  805.  
  806. -- NOTE: Core script only. This fires when a player joins the game.
  807. -- Don't listen/show rbx friends status on xbox
  808. if not isTenFootInterface then
  809.   Player.FriendStatusChanged:connect(onFriendshipChanged)
  810. end
  811.  
  812. --[[ Begin New Server Followers ]]--
  813. local function setFollowRelationshipsView(relationshipTable)
  814.   if not relationshipTable then
  815.     return
  816.   end
  817.  
  818.   for i = 1, #PlayerEntries do
  819.     local entry = PlayerEntries[i]
  820.     local player = entry.Player
  821.     local userId = tostring(player.UserId)
  822.  
  823.     -- don't update icon if already friends
  824.     local friendStatus = getFriendStatus(player)
  825.     if friendStatus == Enum.FriendStatus.Friend then
  826.       return
  827.     end
  828.  
  829.     local icon = nil
  830.     if relationshipTable[userId] then
  831.       local relationship = relationshipTable[userId]
  832.       if relationship.IsMutual == true then
  833.         icon = MUTUAL_FOLLOWING_ICON
  834.       elseif relationship.IsFollowing == true then
  835.         icon = FOLLOWING_ICON
  836.       elseif relationship.IsFollower == true then
  837.         icon = FOLLOWER_ICON
  838.       end
  839.     end
  840.  
  841.     if icon then
  842.         local frame = entry.Frame
  843.         local bgFrame = frame:FindFirstChild('BGFrame')
  844.         if bgFrame then
  845.           updateSocialIcon(icon, bgFrame)
  846.         end
  847.     end
  848.   end
  849. end
  850.  
  851. local function getFollowRelationships()
  852.   local result = nil
  853.   if RemoteFunc_GetFollowRelationships then
  854.     result = RemoteFunc_GetFollowRelationships:InvokeServer()
  855.   end
  856.   return result
  857. end
  858.  
  859. --[[ End New Server Followers ]]--
  860.  
  861. local function updateAllTeamScores()
  862.   local teamScores = {}
  863.   for _,playerEntry in ipairs(PlayerEntries) do
  864.     local player = playerEntry.Player
  865.     local leaderstats = player:FindFirstChild('leaderstats')
  866.     local team = player.Neutral and 'Neutral' or tostring(player.TeamColor)
  867.     local isInValidColor = true
  868.     if team ~= 'Neutral' then
  869.       for _,teamEntry in ipairs(TeamEntries) do
  870.         local color = teamEntry.Team.TeamColor
  871.         if team == tostring(color) then
  872.           isInValidColor = false
  873.           break
  874.         end
  875.       end
  876.     end
  877.     if isInValidColor then
  878.       team = 'Neutral'
  879.     end
  880.     if not teamScores[team] then
  881.       teamScores[team] = {}
  882.     end
  883.     if playerEntry.Frame ~= MyPlayerEntryTopFrame then
  884.       if leaderstats then
  885.         for _,stat in ipairs(GameStats) do
  886.           local statObject = leaderstats:FindFirstChild(stat.Name)
  887.           if statObject and not statObject:IsA('StringValue') then
  888.             if not teamScores[team][stat.Name] then
  889.               teamScores[team][stat.Name] = 0
  890.             end
  891.             teamScores[team][stat.Name] = teamScores[team][stat.Name] + getScoreValue(statObject)
  892.           end
  893.         end
  894.       end
  895.     end
  896.   end
  897.  
  898.   for _,teamEntry in ipairs(TeamEntries) do
  899.     local team = teamEntry.Team
  900.     local frame = teamEntry.Frame
  901.     local color = tostring(team.TeamColor)
  902.     local stats = teamScores[color]
  903.     if stats then
  904.       for statName,statValue in pairs(stats) do
  905.         local statFrame = frame:FindFirstChild(statName)
  906.         if statFrame then
  907.           local statText = statFrame:FindFirstChild('StatText')
  908.           if statText then
  909.             statText.Text = formatStatString(tostring(statValue))
  910.           end
  911.         end
  912.       end
  913.     else
  914.       for _,childFrame in pairs(frame:GetChildren()) do
  915.         local statText = childFrame:FindFirstChild('StatText')
  916.         if statText then
  917.           statText.Text = ''
  918.         end
  919.       end
  920.     end
  921.   end
  922.   if NeutralTeam then
  923.     local frame = NeutralTeam.Frame
  924.     local stats = teamScores['Neutral']
  925.     if stats then
  926.       frame.Visible = true
  927.       for statName,statValue in pairs(stats) do
  928.         local statFrame = frame:FindFirstChild(statName)
  929.         if statFrame then
  930.           local statText = statFrame:FindFirstChild('StatText')
  931.           if statText then
  932.             statText.Text = formatStatString(tostring(statValue))
  933.           end
  934.         end
  935.       end
  936.     else
  937.       frame.Visible = false
  938.     end
  939.   end
  940. end
  941.  
  942. local function updateTeamEntry(entry)
  943.   local frame = entry.Frame
  944.   local team = entry.Team
  945.   local color = team.TeamColor.Color
  946.   local offset = NameEntrySizeX
  947.   for _,stat in ipairs(GameStats) do
  948.     local statFrame = frame:FindFirstChild(stat.Name)
  949.     if not statFrame then
  950.       statFrame = createStatFrame(offset, frame, stat.Name)
  951.       statFrame.BackgroundColor3 = color
  952.       createStatText(statFrame, "", false, true)
  953.     end
  954.     statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0)
  955.     offset = offset + statFrame.Size.X.Offset + TILE_SPACING
  956.   end
  957. end
  958.  
  959. local function updatePrimaryStats(statName)
  960.   for _,entry in ipairs(PlayerEntries) do
  961.     local player = entry.Player
  962.     local leaderstats = player:FindFirstChild('leaderstats')
  963.     entry.PrimaryStat = nil
  964.     if leaderstats then
  965.       local statObject = leaderstats:FindFirstChild(statName)
  966.       if statObject then
  967.         local scoreValue = getScoreValue(statObject)
  968.         entry.PrimaryStat = scoreValue
  969.       end
  970.     end
  971.   end
  972. end
  973.  
  974. local updateLeaderstatFrames = nil
  975. -- TODO: fire event to top bar?
  976. local function initializeStatText(stat, statObject, entry, statFrame, index, isTopStat)
  977.   local player = entry.Player
  978.   local statValue = getScoreValue(statObject)
  979.   if statObject.Name == GameStats[1].Name then
  980.     entry.PrimaryStat = statValue
  981.   end
  982.   local statText = createStatText(statFrame, formatStatString(tostring(statValue)), isTopStat)
  983.   -- Top Bar insertion
  984.   if player == Player then
  985.     stat.Text = statText.Text
  986.   end
  987.  
  988.   statObject.Changed:connect(function(newValue)
  989.       local scoreValue = getScoreValue(statObject)
  990.       statText.Text = formatStatString(tostring(scoreValue))
  991.       if statObject.Name == GameStats[1].Name then
  992.         entry.PrimaryStat = scoreValue
  993.       end
  994.       -- Top bar changed event
  995.       if player == Player then
  996.         stat.Text = statText.Text
  997.         Playerlist.OnStatChanged:Fire(stat.Name, stat.Text)
  998.       end
  999.       updateAllTeamScores()
  1000.       setEntryPositions()
  1001.     end)
  1002.   statObject.ChildAdded:connect(function(child)
  1003.       if child.Name == "IsPrimary" then
  1004.         GameStats[1].IsPrimary = false
  1005.         stat.IsPrimary = true
  1006.         updatePrimaryStats(stat.Name)
  1007.         if updateLeaderstatFrames then updateLeaderstatFrames() end
  1008.         Playerlist.OnLeaderstatsChanged:Fire(GameStats)
  1009.       end
  1010.     end)
  1011. end
  1012.  
  1013. updateLeaderstatFrames = function()
  1014.   table.sort(GameStats, sortLeaderStats)
  1015.   if #TeamEntries > 0 then
  1016.     for _,entry in ipairs(TeamEntries) do
  1017.       updateTeamEntry(entry)
  1018.     end
  1019.     if NeutralTeam then
  1020.       updateTeamEntry(NeutralTeam)
  1021.     end
  1022.   end
  1023.  
  1024.   for _,entry in ipairs(PlayerEntries) do
  1025.     local player = entry.Player
  1026.     local mainFrame = entry.Frame
  1027.     local offset = NameEntrySizeX
  1028.     local leaderstats = player:FindFirstChild('leaderstats')
  1029.     local isTopStat = (entry.Frame == MyPlayerEntryTopFrame)
  1030.  
  1031.     if leaderstats then
  1032.       for _,stat in ipairs(GameStats) do
  1033.         local statObject = leaderstats:FindFirstChild(stat.Name)
  1034.         local statFrame = mainFrame:FindFirstChild(stat.Name)
  1035.  
  1036.         if not statFrame then
  1037.           statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat)
  1038.           if statObject then
  1039.             initializeStatText(stat, statObject, entry, statFrame, _, isTopStat)
  1040.           end
  1041.         elseif statObject then
  1042.           local statText = statFrame:FindFirstChild('StatText')
  1043.           if not statText then
  1044.             initializeStatText(stat, statObject, entry, statFrame, _, isTopStat)
  1045.           end
  1046.         end
  1047.         statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0)
  1048.         offset = offset + statFrame.Size.X.Offset + TILE_SPACING
  1049.       end
  1050.     else
  1051.       for _,stat in ipairs(GameStats) do
  1052.         local statFrame = mainFrame:FindFirstChild(stat.Name)
  1053.         if not statFrame then
  1054.           statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat)
  1055.         end
  1056.         offset = offset + statFrame.Size.X.Offset + TILE_SPACING
  1057.       end
  1058.     end
  1059.  
  1060.     if entry.Frame ~= MyPlayerEntryTopFrame then
  1061.       if isTenFootInterface then
  1062.         Container.Position = UDim2.new(0.5, -offset/2, 0, 110)
  1063.         Container.Size = UDim2.new(0, offset, 0.8, 0)
  1064.       else
  1065.         Container.Position = UDim2.new(1, -offset, 0, 2)
  1066.         Container.Size = UDim2.new(0, offset, 0.5, 0)
  1067.       end
  1068.       targetContainerYOffset = Container.Position.Y.Offset
  1069.       AdjustContainerPosition()
  1070.  
  1071.       local newMinContainerOffset = offset
  1072.       MinContainerSize = UDim2.new(0, newMinContainerOffset, 0.5, 0)
  1073.     end
  1074.   end
  1075.   updateAllTeamScores()
  1076.   setEntryPositions()
  1077.   Playerlist.OnLeaderstatsChanged:Fire(GameStats)
  1078. end
  1079.  
  1080. local function addNewStats(leaderstats)
  1081.   for i,stat in ipairs(leaderstats:GetChildren()) do
  1082.     if isValidStat(stat) and #GameStats < MAX_LEADERSTATS then
  1083.       local gameHasStat = false
  1084.       for _,gStat in ipairs(GameStats) do
  1085.         if stat.Name == gStat.Name then
  1086.           gameHasStat = true
  1087.           break
  1088.         end
  1089.       end
  1090.  
  1091.       if not gameHasStat then
  1092.         local newStat = {}
  1093.         newStat.Name = stat.Name
  1094.         newStat.Text = "-"
  1095.         newStat.Priority = 0
  1096.         local priority = stat:FindFirstChild('Priority')
  1097.         if priority then newStat.Priority = priority end
  1098.         newStat.IsPrimary = false
  1099.         local isPrimary = stat:FindFirstChild('IsPrimary')
  1100.         if isPrimary then
  1101.           newStat.IsPrimary = true
  1102.         end
  1103.         newStat.AddId = StatAddId
  1104.         StatAddId = StatAddId + 1
  1105.         table.insert(GameStats, newStat)
  1106.         table.sort(GameStats, sortLeaderStats)
  1107.         if #GameStats == 1 then
  1108.           setScrollListSize()
  1109.           setEntryPositions()
  1110.         end
  1111.       end
  1112.     end
  1113.   end
  1114. end
  1115.  
  1116. local function removeStatFrameFromEntry(stat, frame)
  1117.   local statFrame = frame:FindFirstChild(stat.Name)
  1118.   if statFrame then
  1119.     statFrame:Destroy()
  1120.   end
  1121. end
  1122.  
  1123. local function doesStatExists(stat)
  1124.   local doesExists = false
  1125.   for _,entry in ipairs(PlayerEntries) do
  1126.     local player = entry.Player
  1127.     if player then
  1128.       local leaderstats = player:FindFirstChild('leaderstats')
  1129.       if leaderstats and leaderstats:FindFirstChild(stat.Name) then
  1130.         doesExists = true
  1131.         break
  1132.       end
  1133.     end
  1134.   end
  1135.  
  1136.   return doesExists
  1137. end
  1138.  
  1139. local function onStatRemoved(oldStat, entry)
  1140.   if isValidStat(oldStat) then
  1141.     removeStatFrameFromEntry(oldStat, entry.Frame)
  1142.     local statExists = doesStatExists(oldStat)
  1143.     --
  1144.     local toRemove = nil
  1145.     for i, stat in ipairs(GameStats) do
  1146.       if stat.Name == oldStat.Name then
  1147.         toRemove = i
  1148.         break
  1149.       end
  1150.     end
  1151.     -- removed from player but not from game; another player still has this stat
  1152.     if statExists then
  1153.       if toRemove and entry.Player == Player then
  1154.         GameStats[toRemove].Text = "-"
  1155.         Playerlist.OnStatChanged:Fire(GameStats[toRemove].Name, GameStats[toRemove].Text)
  1156.       end
  1157.       -- removed from game
  1158.     else
  1159.       for _,playerEntry in ipairs(PlayerEntries) do
  1160.         removeStatFrameFromEntry(oldStat, playerEntry.Frame)
  1161.       end
  1162.       for _,teamEntry in ipairs(TeamEntries) do
  1163.         removeStatFrameFromEntry(oldStat, teamEntry.Frame)
  1164.       end
  1165.       if toRemove then
  1166.         table.remove(GameStats, toRemove)
  1167.         table.sort(GameStats, sortLeaderStats)
  1168.       end
  1169.     end
  1170.     if GameStats[1] then
  1171.       updatePrimaryStats(GameStats[1].Name)
  1172.     end
  1173.     updateLeaderstatFrames()
  1174.   end
  1175. end
  1176.  
  1177. local function onStatAdded(leaderstats, entry)
  1178.   leaderstats.ChildAdded:connect(function(newStat)
  1179.       if isValidStat(newStat) then
  1180.         addNewStats(newStat.Parent)
  1181.         updateLeaderstatFrames()
  1182.       end
  1183.     end)
  1184.   leaderstats.ChildRemoved:connect(function(child)
  1185.       onStatRemoved(child, entry)
  1186.     end)
  1187.   addNewStats(leaderstats)
  1188.   updateLeaderstatFrames()
  1189. end
  1190.  
  1191. local function setLeaderStats(entry)
  1192.   local player = entry.Player
  1193.   local leaderstats = player:FindFirstChild('leaderstats')
  1194.  
  1195.   if leaderstats then
  1196.     onStatAdded(leaderstats, entry)
  1197.   end
  1198.  
  1199.   local function onPlayerChildChanged(property, child)
  1200.     if property == 'Name' and child.Name == 'leaderstats' then
  1201.       onStatAdded(child, entry)
  1202.     end
  1203.   end
  1204.  
  1205.   player.ChildAdded:connect(function(child)
  1206.       if child.Name == 'leaderstats' then
  1207.         onStatAdded(child, entry)
  1208.       end
  1209.       child.Changed:connect(function(property) onPlayerChildChanged(property, child) end)
  1210.     end)
  1211.   for _,child in pairs(player:GetChildren()) do
  1212.     child.Changed:connect(function(property) onPlayerChildChanged(property, child) end)
  1213.   end
  1214.  
  1215.   player.ChildRemoved:connect(function(child)
  1216.       if child.Name == 'leaderstats' then
  1217.         for i,stat in ipairs(child:GetChildren()) do
  1218.           onStatRemoved(stat, entry)
  1219.         end
  1220.         updateLeaderstatFrames()
  1221.       end
  1222.     end)
  1223. end
  1224.  
  1225. local offsetSize = 18
  1226. if isTenFootInterface then offsetSize = 32 end
  1227.  
  1228. local function createPlayerEntry(player, isTopStat)
  1229.   local playerEntry = {}
  1230.   local name = player.Name
  1231.  
  1232.   local containerFrame, entryFrame = createEntryFrame(name, PlayerEntrySizeY, isTopStat)
  1233.   entryFrame.Active = true
  1234.  
  1235.   entryFrame.MouseButton1Click:connect(function()
  1236.       onEntryFrameSelected(containerFrame, player)
  1237.     end)
  1238.  
  1239.   local currentXOffset = 1
  1240.  
  1241.   -- check membership
  1242.   local membershipIconImage = getMembershipIcon(player)
  1243.   local membershipIcon = nil
  1244.   if membershipIconImage then
  1245.     membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", currentXOffset, entryFrame)
  1246.     currentXOffset = currentXOffset + membershipIcon.Size.X.Offset + 2
  1247.   else
  1248.     currentXOffset = currentXOffset + offsetSize
  1249.   end
  1250.  
  1251.   spawn(function()
  1252.       if isTenFootInterface and membershipIcon then
  1253.         setAvatarIconAsync(player, membershipIcon)
  1254.       end
  1255.     end)
  1256.  
  1257.   -- Some functions yield, so we need to spawn off in order to not cause a race condition with other events like PlayersService.ChildRemoved
  1258.   spawn(function()
  1259.       local success, result = pcall(function()
  1260.           return player:GetRankInGroup(game.CreatorId) == 255
  1261.         end)
  1262.       if success then
  1263.         if game.CreatorType == Enum.CreatorType.Group and result then
  1264.           membershipIconImage = PLACE_OWNER_ICON
  1265.           if not membershipIcon then
  1266.             membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", 1, entryFrame)
  1267.           else
  1268.             membershipIcon.Image = membershipIconImage
  1269.           end
  1270.         end
  1271.       else
  1272.         print("PlayerList: GetRankInGroup failed because", result)
  1273.       end
  1274.       local iconImage = getCustomPlayerIcon(player)
  1275.       if iconImage then
  1276.         if not membershipIcon then
  1277.           membershipIcon = createImageIcon(iconImage, "MembershipIcon", 1, entryFrame)
  1278.         else
  1279.           membershipIcon.Image = iconImage
  1280.         end
  1281.       end
  1282.       -- Friendship and Follower status is checked by onFriendshipChanged, which is called by the FriendStatusChanged
  1283.       -- event. This event is fired when any player joins the game. onFriendshipChanged will check Follower status in
  1284.       -- the case that we are not friends with the new player who is joining.
  1285.     end)
  1286.  
  1287.   local playerNameXSize = entryFrame.Size.X.Offset - currentXOffset
  1288.   local playerName = createEntryNameText("PlayerName", name, playerNameXSize, currentXOffset)
  1289.   playerName.Parent = entryFrame
  1290.   playerEntry.Player = player
  1291.   playerEntry.Frame = containerFrame
  1292.  
  1293.   if isTenFootInterface then
  1294.     local shadow = Instance.new("ImageLabel")
  1295.     shadow.BackgroundTransparency = 1
  1296.     shadow.Name = 'Shadow'
  1297.     shadow.Image = SHADOW_IMAGE
  1298.     shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0)
  1299.     shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE)
  1300.     shadow.ScaleType = 'Slice'
  1301.     shadow.SliceCenter = SHADOW_SLICE_RECT
  1302.     shadow.Parent = entryFrame
  1303.   end
  1304.  
  1305.   if isTopStat then
  1306.     playerName.Font = 'SourceSansBold'
  1307.   end
  1308.  
  1309.   return playerEntry
  1310. end
  1311.  
  1312. local function createTeamEntry(team)
  1313.   local teamEntry = {}
  1314.   teamEntry.Team = team
  1315.   teamEntry.TeamScore = 0
  1316.  
  1317.   local containerFrame, entryFrame = createEntryFrame(team.Name, TeamEntrySizeY)
  1318.   entryFrame.Selectable = false -- dont allow gamepad selection of team frames
  1319.   entryFrame.BackgroundColor3 = team.TeamColor.Color
  1320.  
  1321.   local teamName = createEntryNameText("TeamName", team.Name, entryFrame.AbsoluteSize.x, 1)
  1322.   teamName.Parent = entryFrame
  1323.  
  1324.   teamEntry.Frame = containerFrame
  1325.  
  1326.   if isTenFootInterface then
  1327.     local shadow = Instance.new("ImageLabel")
  1328.     shadow.BackgroundTransparency = 1
  1329.     shadow.Name = 'Shadow'
  1330.     shadow.Image = SHADOW_IMAGE
  1331.     shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0)
  1332.     shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE)
  1333.     shadow.ScaleType = 'Slice'
  1334.     shadow.SliceCenter = SHADOW_SLICE_RECT
  1335.     shadow.Parent = entryFrame
  1336.   end
  1337.  
  1338.   -- connections
  1339.   team.Changed:connect(function(property)
  1340.       if property == 'Name' then
  1341.         teamName.Text = team.Name
  1342.       elseif property == 'TeamColor' then
  1343.         for _,childFrame in pairs(containerFrame:GetChildren()) do
  1344.           if childFrame:IsA('GuiObject') then
  1345.             childFrame.BackgroundColor3 = team.TeamColor.Color
  1346.           end
  1347.         end
  1348.  
  1349.         setTeamEntryPositions()
  1350.         updateAllTeamScores()
  1351.         setEntryPositions()
  1352.         setScrollListSize()
  1353.       end
  1354.     end)
  1355.  
  1356.   return teamEntry
  1357. end
  1358.  
  1359. local function createNeutralTeam()
  1360.   if not NeutralTeam then
  1361.     local team = Instance.new('Team')
  1362.     team.Name = 'Neutral'
  1363.     team.TeamColor = BrickColor.new('White')
  1364.     NeutralTeam = createTeamEntry(team)
  1365.     NeutralTeam.Frame.Parent = ScrollList
  1366.   end
  1367. end
  1368.  
  1369. --[[ Insert/Remove Player Functions ]]--
  1370. local function setupEntry(player, newEntry, isTopStat)
  1371.   setLeaderStats(newEntry)
  1372.  
  1373.   if isTopStat then
  1374.     newEntry.Frame.Parent = Container
  1375.     table.insert(PlayerEntries, newEntry)
  1376.   else
  1377.     newEntry.Frame.Parent = ScrollList
  1378.     table.insert(PlayerEntries, newEntry)
  1379.     setScrollListSize()
  1380.   end
  1381.  
  1382.   updateLeaderstatFrames()
  1383.  
  1384.   player.Changed:connect(function(property)
  1385.       if #TeamEntries > 0 and (property == 'Neutral' or property == 'TeamColor') then
  1386.         setTeamEntryPositions()
  1387.         updateAllTeamScores()
  1388.         setEntryPositions()
  1389.         setScrollListSize()
  1390.       end
  1391.     end)
  1392. end
  1393.  
  1394. local function insertPlayerEntry(player)
  1395.   local entry = createPlayerEntry(player)
  1396.   setupEntry(player, entry)
  1397.  
  1398.   -- create an entry on the top of the playerlist
  1399.   if player == Player and isTenFootInterface then
  1400.     local localEntry = createPlayerEntry(player, true)
  1401.     MyPlayerEntryTopFrame = localEntry.Frame
  1402.     MyPlayerEntryTopFrame.BackgroundTransparency = 1
  1403.     MyPlayerEntryTopFrame.BorderSizePixel = 0
  1404.     setupEntry(player, localEntry, true)
  1405.   end
  1406. end
  1407.  
  1408. local function removePlayerEntry(player)
  1409.   for i = 1, #PlayerEntries do
  1410.     if PlayerEntries[i].Player == player then
  1411.       PlayerEntries[i].Frame:Destroy()
  1412.       table.remove(PlayerEntries, i)
  1413.       break
  1414.     end
  1415.   end
  1416.   setEntryPositions()
  1417.   setScrollListSize()
  1418. end
  1419.  
  1420. --[[ Team Functions ]]--
  1421. local function onTeamAdded(team)
  1422.   for i = 1, #TeamEntries do
  1423.     if TeamEntries[i].Team.TeamColor == team.TeamColor then
  1424.       TeamEntries[i].Frame:Destroy()
  1425.       table.remove(TeamEntries, i)
  1426.       break
  1427.     end
  1428.   end
  1429.   local entry = createTeamEntry(team)
  1430.   entry.Id = TeamAddId
  1431.   TeamAddId = TeamAddId + 1
  1432.   if not NeutralTeam then
  1433.     createNeutralTeam()
  1434.   end
  1435.   table.insert(TeamEntries, entry)
  1436.   table.sort(TeamEntries, sortTeams)
  1437.   setTeamEntryPositions()
  1438.   updateLeaderstatFrames()
  1439.   setScrollListSize()
  1440.   entry.Frame.Parent = ScrollList
  1441. end
  1442.  
  1443. local function onTeamRemoved(removedTeam)
  1444.   for i = 1, #TeamEntries do
  1445.     local team = TeamEntries[i].Team
  1446.     if team.Name == removedTeam.Name then
  1447.       TeamEntries[i].Frame:Destroy()
  1448.       table.remove(TeamEntries, i)
  1449.       break
  1450.     end
  1451.   end
  1452.   if #TeamEntries == 0 then
  1453.     if NeutralTeam then
  1454.       NeutralTeam.Frame:Destroy()
  1455.       NeutralTeam.Team:Destroy()
  1456.       NeutralTeam = nil
  1457.       IsShowingNeutralFrame = false
  1458.     end
  1459.   end
  1460.   setEntryPositions()
  1461.   updateLeaderstatFrames()
  1462.   setScrollListSize()
  1463. end
  1464.  
  1465. --[[ Resize/Position Functions ]]--
  1466. local function clampCanvasPosition()
  1467.   local maxCanvasPosition = ScrollList.CanvasSize.Y.Offset - ScrollList.Size.Y.Offset
  1468.   if maxCanvasPosition >= 0 and ScrollList.CanvasPosition.y > maxCanvasPosition then
  1469.     ScrollList.CanvasPosition = Vector2.new(0, maxCanvasPosition)
  1470.   end
  1471. end
  1472.  
  1473. local function resizePlayerList()
  1474.   setScrollListSize()
  1475.   clampCanvasPosition()
  1476. end
  1477.  
  1478. RobloxGui.Changed:connect(function(property)
  1479.     if property == 'AbsoluteSize' then
  1480.       spawn(function()  -- must spawn because F11 delays when abs size is set
  1481.           resizePlayerList()
  1482.         end)
  1483.     end
  1484.   end)
  1485.  
  1486. UserInputService.InputBegan:connect(function(inputObject, isProcessed)
  1487.     if isProcessed then return end
  1488.     local inputType = inputObject.UserInputType
  1489.     if (inputType == Enum.UserInputType.Touch and  inputObject.UserInputState == Enum.UserInputState.Begin) or
  1490.     inputType == Enum.UserInputType.MouseButton1 then
  1491.       if LastSelectedFrame then
  1492.         playerDropDown:Hide()
  1493.       end
  1494.     end
  1495.   end)
  1496.  
  1497. -- NOTE: Core script only
  1498.  
  1499. --[[ Player Add/Remove Connections ]]--
  1500. PlayersService.PlayerAdded:connect(function(child)
  1501.   insertPlayerEntry(child)
  1502. end)
  1503.  
  1504. for _, player in ipairs(PlayersService:GetPlayers()) do
  1505.   insertPlayerEntry(player)
  1506. end
  1507.  
  1508. --[[ Begin new Server Followers ]]--
  1509. -- Don't listen/show rbx followers status on console
  1510. if not isTenFootInterface then
  1511.   -- spawn so we don't block script
  1512.   spawn(function()
  1513.     local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
  1514.     RemoveEvent_OnFollowRelationshipChanged = RobloxReplicatedStorage:WaitForChild('FollowRelationshipChanged', 86400) or RobloxReplicatedStorage:WaitForChild('FollowRelationshipChanged')
  1515.     RemoteFunc_GetFollowRelationships = RobloxReplicatedStorage:WaitForChild('GetFollowRelationships')
  1516.  
  1517.     RemoveEvent_OnFollowRelationshipChanged.OnClientEvent:connect(function(result)
  1518.       setFollowRelationshipsView(result)
  1519.     end)
  1520.  
  1521.     local result = getFollowRelationships()
  1522.     setFollowRelationshipsView(result)
  1523.   end)
  1524. end
  1525.  
  1526. PlayersService.ChildRemoved:connect(function(child)
  1527.   if child:IsA("Player") then
  1528.     if LastSelectedPlayer and child == LastSelectedPlayer then
  1529.       playerDropDown:Hide()
  1530.     end
  1531.     removePlayerEntry(child)
  1532.   end
  1533. end)
  1534.  
  1535. --[[ Teams ]]--
  1536. local function initializeTeams(teams)
  1537.   for _,team in pairs(teams:GetTeams()) do
  1538.     onTeamAdded(team)
  1539.   end
  1540.  
  1541.   teams.ChildAdded:connect(function(team)
  1542.       if team:IsA('Team') then
  1543.         onTeamAdded(team)
  1544.       end
  1545.     end)
  1546.  
  1547.   teams.ChildRemoved:connect(function(team)
  1548.       if team:IsA('Team') then
  1549.         onTeamRemoved(team)
  1550.       end
  1551.     end)
  1552. end
  1553.  
  1554. TeamsService = game:FindService('Teams')
  1555. if TeamsService then
  1556.   initializeTeams(TeamsService)
  1557. end
  1558.  
  1559. game.ChildAdded:connect(function(child)
  1560.     if child:IsA('Teams') then
  1561.       initializeTeams(child)
  1562.     end
  1563.   end)
  1564.  
  1565. --[[ Public API ]]--
  1566. Playerlist.GetStats = function()
  1567.   return GameStats
  1568. end
  1569.  
  1570. local noOpFunc = function ( )
  1571. end
  1572.  
  1573. local isOpen = not isTenFootInterface
  1574.  
  1575. local closeListFunc = function(name, state, input)
  1576.   if state ~= Enum.UserInputState.Begin then return end
  1577.  
  1578.   isOpen = false
  1579.   Container.Visible = false
  1580.   spawn(function() GuiService:SetMenuIsOpen(false) end)
  1581.   ContextActionService:UnbindCoreAction("CloseList")
  1582.   ContextActionService:UnbindCoreAction("StopAction")
  1583.   GuiService:RemoveSelectionGroup("PlayerlistGuiSelection")
  1584.   GuiService.SelectedCoreObject = nil
  1585.   UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None
  1586. end
  1587.  
  1588. local setVisible = function(state, fromTemp)
  1589.   Container.Visible = state
  1590.  
  1591.   if state then
  1592.     local children = ScrollList:GetChildren()
  1593.     if children and #children > 0 then
  1594.       local frame = children[1]
  1595.       local frameChildren = frame:GetChildren()
  1596.       for i = 1, #frameChildren do
  1597.         if frameChildren[i]:IsA("TextButton") then
  1598.           local lastInputType = UserInputService:GetLastInputType()
  1599.           local isUsingGamepad = (lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or
  1600.             lastInputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4)
  1601.  
  1602.           if isUsingGamepad and not fromTemp then
  1603.             GuiService.SelectedCoreObject = frameChildren[i]
  1604.             GuiService:AddSelectionParent("PlayerlistGuiSelection", ScrollList)
  1605.             UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide
  1606.             ContextActionService:BindCoreAction("StopAction", noOpFunc, false, Enum.UserInputType.Gamepad1)
  1607.             ContextActionService:BindCoreAction("CloseList", closeListFunc, false, Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart)
  1608.           end
  1609.           break
  1610.         end
  1611.       end
  1612.     end
  1613.   else
  1614.     if isUsingGamepad then
  1615.       UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None
  1616.     end
  1617.  
  1618.     ContextActionService:UnbindCoreAction("CloseList")
  1619.     ContextActionService:UnbindCoreAction("StopAction")
  1620.  
  1621.     if GuiService.SelectedCoreObject and GuiService.SelectedCoreObject:IsDescendantOf(Container) then
  1622.       GuiService.SelectedCoreObject = nil
  1623.       GuiService:RemoveSelectionGroup("PlayerlistGuiSelection")
  1624.     end
  1625.   end
  1626. end
  1627.  
  1628. Playerlist.ToggleVisibility = function(name, inputState, inputObject)
  1629.   if inputState and inputState ~= Enum.UserInputState.Begin then return end
  1630.   if IsSmallScreenDevice then return end
  1631.   if not playerlistCoreGuiEnabled then return end
  1632.  
  1633.   isOpen = not isOpen
  1634.  
  1635.   if next(TempHideKeys) == nil then
  1636.     setVisible(isOpen)
  1637.   end
  1638. end
  1639.  
  1640. Playerlist.IsOpen = function()
  1641.   return isOpen
  1642. end
  1643.  
  1644. Playerlist.HideTemp = function(self, key, hidden)
  1645.   if not playerlistCoreGuiEnabled then return end
  1646.   if IsSmallScreenDevice then return end
  1647.  
  1648.   TempHideKeys[key] = hidden and true or nil
  1649.  
  1650.   if next(TempHideKeys) == nil then
  1651.     if isOpen then
  1652.       setVisible(true, true)
  1653.     end
  1654.   else
  1655.     if isOpen then
  1656.       setVisible(false, true)
  1657.     end
  1658.   end
  1659. end
  1660. local topStat = nil
  1661. if isTenFootInterface then
  1662.   topStat = TenFootInterface:SetupTopStat()
  1663. end
  1664.  
  1665. --[[ Core Gui Changed events ]]--
  1666. -- NOTE: Core script only
  1667. local function onCoreGuiChanged(coreGuiType, enabled)
  1668.   if coreGuiType == Enum.CoreGuiType.All or coreGuiType == Enum.CoreGuiType.PlayerList then
  1669.     -- on console we can always toggle on/off, ignore change
  1670.     if isTenFootInterface then
  1671.       playerlistCoreGuiEnabled = true
  1672.       return
  1673.     end
  1674.  
  1675.     playerlistCoreGuiEnabled = enabled and topbarEnabled
  1676.  
  1677.     -- not visible on small screen devices
  1678.     if IsSmallScreenDevice then
  1679.       Container.Visible = false
  1680.       return
  1681.     end
  1682.  
  1683.     setVisible(playerlistCoreGuiEnabled and isOpen and next(TempHideKeys) == nil, true)
  1684.  
  1685.     if isTenFootInterface and topStat then
  1686.       topStat:SetTopStatEnabled(playerlistCoreGuiEnabled)
  1687.     end
  1688.  
  1689.     if playerlistCoreGuiEnabled then
  1690.       ContextActionService:BindCoreAction("RbxPlayerListToggle", Playerlist.ToggleVisibility, false, Enum.KeyCode.Tab)
  1691.     else
  1692.       ContextActionService:UnbindCoreAction("RbxPlayerListToggle")
  1693.     end
  1694.   end
  1695. end
  1696. resizePlayerList()
  1697.  
  1698. local blockStatusChanged = function(userId, isBlocked)
  1699.   if userId < 0 then return end
  1700.  
  1701.   for _,playerEntry in ipairs(PlayerEntries) do
  1702.     if playerEntry.Player.UserId == userId then
  1703.       playerEntry.Frame.BGFrame.MembershipIcon.Image = getMembershipIcon(playerEntry.Player)
  1704.       return
  1705.     end
  1706.   end
  1707. end
  1708.  
  1709. blockingUtility:GetBlockedStatusChangedEvent():connect(blockStatusChanged)
  1710.  
  1711. return Playerlist
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement