Files
watrbx-game-engine/content/scripts/CoreScripts/PlayerListScript2.lua
T
2025-09-18 17:55:52 -04:00

1753 lines
55 KiB
Lua

--[[
// FileName: PlayerListScript.lua
// Written by: jmargh
// Description: Implementation of in game player list and leaderboard
]]
local GuiService = game:GetService('GuiService') -- NOTE: Can only use in core scripts
local UserInputService = game:GetService('UserInputService')
local Players = game:GetService('Players')
local TeamsService = game:FindService('Teams')
if LoadLibrary then
RbxGui = LoadLibrary("RbxGui")
end
while not Players.LocalPlayer do
wait()
end
local Player = Players.LocalPlayer
local RobloxGui = script.Parent
--[[ Script Variables ]]--
local MyPlayerEntry = nil
local PlayerEntries = {}
local GameStats = {}
local StatAddId = 0
local TeamEntries = {}
local TeamAddId = 0
local ScaleX = 1
local NeutralTeam = nil
local IsShowingNeutralFrame = false
local IsExpanding = false
local LastSelectedFrame = nil
local LastSelectedPlayer = nil
local IsPlayerListExpanded = false
local MinContainerSize = UDim2.new(0, 200, 0.5, 0)
local StatNameFrame = nil
local PlayerEntrySizeY = 20
local TeamEntrySizeY = 20
local NameEntrySizeX = 165
local StatEntrySizeX = 60
local IsPersonalServer = false
local PersonalServerService = nil
if workspace:FindFirstChild('PSVariable') then
IsPersonalServer = true
PersonalServerService = game:GetService('PersonalServerService')
end
workspace.ChildAdded:connect(function(child)
if child.Name == 'PSVariable' and child:IsA('BoolValue') then
IsPersonalServer = true
PersonalServerService = game:GetService('PersonalServerService')
end
end)
--Report Abuse
local AbusingPlayer = nil
local AbuseReason = nil
--[[ Constants ]]--
local ENTRY_PAD = 1
local BG_TRANSPARENCY = 0.7
local TEXT_STROKE_TRANSPARENCY = 0.75
local TEXT_COLOR = Color3.new(1, 1, 243/255)
local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255)
local TWEEN_TIME = 0.15
local MAX_LEADERSTATS = 4
local MAX_STR_LEN = 10
local ADMINS = { -- Admins with special icons
['67'] = 'http://www.watrbx.wtf/asset/?id=134032333', -- Jeditkacheff
}
local ABUSES = {
"Swearing",
"Bullying",
"Scamming",
"Dating",
"Cheating/Exploiting",
"Personal Questions",
"Offsite Links",
"Bad Username",
}
local PRIVILEGE_LEVEL = {
OWNER = 255,
ADMIN = 240,
MEMBER = 128,
VISITOR = 10,
BANNED = 0,
}
--[[ Images ]]--
local EXPAND_ICON = 'rbxasset://textures/ui/expandPlayerList.png'
local CHAT_ICON = 'rbxasset://textures/ui/chat_teamButton.png'
local ADMIN_ICON = 'rbxasset://textures/ui/icon_admin-16.png'
local PLACE_OWNER_ICON = 'rbxasset://textures/ui/icon_placeowner.png'
local BC_ICON = 'rbxasset://textures/ui/icon_BC-16.png'
local TBC_ICON = 'rbxasset://textures/ui/icon_TBC-16.png'
local OBC_ICON = 'rbxasset://textures/ui/icon_OBC-16.png'
local FRIEND_ICON = 'rbxasset://textures/ui/icon_friends_16.png'
local FRIEND_REQUEST_ICON = 'rbxasset://textures/ui/icon_friendrequestsent_16.png'
local FRIEND_RECEIVED_ICON = 'rbxasset://textures/ui/icon_friendrequestrecieved-16.png'
local FOLLOWER_ICON = 'rbxasset://textures/ui/icon_follower-16.png'
local FOLLOWING_ICON = 'rbxasset://textures/ui/icon_following-16.png'
local MUTUAL_FOLLOWING_ICON = 'rbxasset://textures/ui/icon_mutualfollowing-16.png'
--[[ Helper Functions ]]--
local function clamp(value, min, max)
if value < min then
value = min
elseif value > max then
value = max
end
return value
end
local function getFriendStatus(selectedPlayer)
if selectedPlayer == Player then
return Enum.FriendStatus.NotFriend
else
local success, result = pcall(function()
-- NOTE: Core script only
return Player:GetFriendStatus(selectedPlayer)
end)
if success then
return result
else
return Enum.FriendStatus.NotFriend
end
end
end
local function getFriendStatusIcon(friendStatus)
if friendStatus == Enum.FriendStatus.Unknown or friendStatus == Enum.FriendStatus.NotFriend then
return nil
elseif friendStatus == Enum.FriendStatus.Friend then
return FRIEND_ICON
elseif friendStatus == Enum.FriendStatus.FriendRequestSent then
return FRIEND_REQUEST_ICON
elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then
return FRIEND_RECEIVED_ICON
else
error("PlayerList: Unknown value for friendStatus: "..tostring(friendStatus))
end
end
local function getMembershipIcon(player)
local userIdStr = tostring(player.userId)
local membershipType = player.MembershipType
local isAdmin = player:IsInGroup(1200769) -- yields
if isAdmin then
if ADMINS[userIdStr] then
return ADMINS[userIdStr]
else
return ADMIN_ICON
end
elseif ADMINS[userIdStr] then
return ADMINS[userIdStr]
elseif player.userId == game.CreatorId then
return PLACE_OWNER_ICON
elseif membershipType == Enum.MembershipType.None then
return nil
elseif membershipType == Enum.MembershipType.BuildersClub then
return BC_ICON
elseif membershipType == Enum.MembershipType.TurboBuildersClub then
return TBC_ICON
elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then
return OBC_ICON
else
error("PlayerList: Unknown value for membershipType"..tostring(membershipType))
end
end
local function isValidStat(obj)
return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or
obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue')
end
local function sortPlayerEntries(a, b)
if a.IsPrimary == b.IsPrimary then
return a.Player.Name:upper() < b.Player.Name:upper()
end
if not a.IsPrimary then return false end
if not b.IsPrimary then return true end
return a.IsPrimary < b.IsPrimary
end
local function sortLeaderStats(a, b)
if a.IsPrimary ~= b.IsPrimary then
return a.IsPrimary
end
if a.Priority == b.Priority then
return a.AddId < b.AddId
end
return a.Priority < b.Priority
end
local function sortTeams(a, b)
if a.TeamScore == b.TeamScore then
return a.Id < b.Id
end
if not a.TeamScore then return false end
if not b.TeamScore then return true end
return a.TeamScore < b.TeamScore
end
-- Start of Gui Creation
local Container = Instance.new('Frame')
Container.Name = "PlayerListContainer"
Container.Position = UDim2.new(1, -202, 0, 2)
Container.Size = MinContainerSize
Container.BackgroundTransparency = 1
Container.Visible = false
Container.Parent = RobloxGui
-- Header
local Header = Instance.new('Frame')
Header.Name = "Header"
Header.Position = UDim2.new(0, 0, 0, 0)
Header.Size = UDim2.new(1, 0, 0, 40)
Header.BackgroundTransparency = BG_TRANSPARENCY
Header.BackgroundColor3 = Color3.new()
Header.BorderSizePixel = 0
Header.Active = true
Header.ClipsDescendants = true
Header.Parent = Container
local HeaderName = Instance.new('TextLabel')
HeaderName.Name = "HeaderName"
HeaderName.Size = UDim2.new(1, 0, 0.5, 0)
HeaderName.Position = UDim2.new(-0.02, 0, 0.245, 0)
HeaderName.BackgroundTransparency = 1
HeaderName.Font = Enum.Font.SourceSansBold
HeaderName.FontSize = Enum.FontSize.Size18
HeaderName.TextColor3 = TEXT_COLOR
HeaderName.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
HeaderName.TextStrokeColor3 = TEXT_STROKE_COLOR
HeaderName.TextXAlignment = Enum.TextXAlignment.Right
HeaderName.Text = Player.Name
HeaderName.Parent = Header
local HeaderScore = Instance.new('TextLabel')
HeaderScore.Name = "HeaderScore"
HeaderScore.Size = UDim2.new(1, 0, 0.5, 0)
HeaderScore.Position = UDim2.new(-0.02, 0, 0.495, 0)
HeaderScore.BackgroundTransparency = 1
HeaderScore.Font = Enum.Font.SourceSansBold
HeaderScore.FontSize = Enum.FontSize.Size18
HeaderScore.TextColor3 = TEXT_COLOR
HeaderScore.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
HeaderScore.TextStrokeColor3 = TEXT_STROKE_COLOR
HeaderScore.TextXAlignment = Enum.TextXAlignment.Right
HeaderScore.Text = ""
HeaderScore.Parent = Header
-- Scrolling Frame
local ScrollList = Instance.new('ScrollingFrame')
ScrollList.Name = "ScrollList"
ScrollList.Size = UDim2.new(1, -1, 0, 0)
ScrollList.Position = UDim2.new(0, 0, 0.1, 1)
ScrollList.BackgroundTransparency = 1
ScrollList.BackgroundColor3 = Color3.new()
ScrollList.BorderSizePixel = 0
ScrollList.CanvasSize = UDim2.new(0, 0, 0, 0) -- NOTE: Look into if x needs to be set to anything
ScrollList.ScrollBarThickness = 6
ScrollList.BottomImage = 'rbxasset://textures/ui/scroll-bottom.png'
ScrollList.MidImage = 'rbxasset://textures/ui/scroll-middle.png'
ScrollList.TopImage = 'rbxasset://textures/ui/scroll-top.png'
ScrollList.Parent = Container
-- Expand Frame
local ExpandFrame = Instance.new('Frame')
ExpandFrame.Name = "ExpandFrame"
ExpandFrame.Size = UDim2.new(1, 0, 0, 22)
ExpandFrame.Position = UDim2.new(0, 0, 0, 0)
ExpandFrame.BackgroundTransparency = 1
ExpandFrame.Active = true
ExpandFrame.Parent = Container
local ExpandImage = Instance.new('ImageLabel')
ExpandImage.Name = "ExpandImage"
ExpandImage.Size = UDim2.new(0, 27, 0, ExpandFrame.Size.Y.Offset/2)
ExpandImage.Position = UDim2.new(0.5, -ExpandImage.Size.X.Offset/2, 0, 0)
ExpandImage.BackgroundTransparency = 1
ExpandImage.Image = EXPAND_ICON
ExpandImage.Parent = ExpandFrame
-- Friend/Report Popup
local PopupFrame = nil
local PopupClipFrame = Instance.new('Frame')
PopupClipFrame.Name = "PopupClipFrame"
PopupClipFrame.Size = UDim2.new(0, 150, 1, 0)
PopupClipFrame.Position = UDim2.new(0, -151, 0, 2)
PopupClipFrame.BackgroundTransparency = 1
PopupClipFrame.ClipsDescendants = true
PopupClipFrame.Parent = Container
-- Report Abuse Gui
local ReportAbuseShield = Instance.new('TextButton')
ReportAbuseShield.Name = "ReportAbuseShield"
ReportAbuseShield.Size = UDim2.new(1, 0, 1, 0)
ReportAbuseShield.Position = UDim2.new(0, 0, 0, 0)
ReportAbuseShield.BackgroundColor3 = Color3.new(51/255, 51/255, 51/255)
ReportAbuseShield.BackgroundTransparency = 0.4
ReportAbuseShield.ZIndex = 1
ReportAbuseShield.Text = ""
ReportAbuseShield.AutoButtonColor = false
local ReportAbuseFrame = Instance.new('Frame')
ReportAbuseFrame.Name = "ReportAbuseFrame"
ReportAbuseFrame.Size = UDim2.new(0, 480, 0, 320)
ReportAbuseFrame.Position = UDim2.new(0.5, -240, 0.5, -160)
ReportAbuseFrame.BackgroundTransparency = 0.7
ReportAbuseFrame.BackgroundColor3 = Color3.new(0, 0, 0)
ReportAbuseFrame.Style = Enum.FrameStyle.DropShadow
ReportAbuseFrame.Parent = ReportAbuseShield
local ReportAbuseDescription = Instance.new('TextLabel')
ReportAbuseDescription.Name = "ReportAbuseDescription"
ReportAbuseDescription.Text = "This will send a complete report to a moderator. The moderator will review the chat log and take appropriate action."
ReportAbuseDescription.Size = UDim2.new(1, -20, 0, 40)
ReportAbuseDescription.Position = UDim2.new(0, 10, 0, 10)
ReportAbuseDescription.BackgroundTransparency = 1
ReportAbuseDescription.Font = Enum.Font.SourceSans
ReportAbuseDescription.FontSize = Enum.FontSize.Size18
ReportAbuseDescription.TextColor3 = Color3.new(1, 1, 1)
ReportAbuseDescription.TextWrap = true
ReportAbuseDescription.TextXAlignment = Enum.TextXAlignment.Left
ReportAbuseDescription.TextYAlignment = Enum.TextYAlignment.Top
ReportAbuseDescription.Parent = ReportAbuseFrame
local ReportPlayerLabel = Instance.new('TextLabel')
ReportPlayerLabel.Name = "ReportPlayerLabel"
ReportPlayerLabel.Text = "Player Reporting:"
ReportPlayerLabel.Size = UDim2.new(0.4, 0, 0, 36)
ReportPlayerLabel.Position = UDim2.new(0.025, 20, 0, 80)
ReportPlayerLabel.BackgroundTransparency = 1
ReportPlayerLabel.Font = Enum.Font.SourceSans
ReportPlayerLabel.FontSize = Enum.FontSize.Size18
ReportPlayerLabel.TextColor3 = Color3.new(1, 1, 1)
ReportPlayerLabel.TextXAlignment = Enum.TextXAlignment.Left
ReportPlayerLabel.Parent = ReportAbuseFrame
local ReportPlayerName = Instance.new('TextLabel')
ReportPlayerName.Name = "ReportPlayerName"
ReportPlayerName.Text = "jmargh"
ReportPlayerName.Size = UDim2.new(0.95, 0, 0, 36)
ReportPlayerName.Position = UDim2.new(0.025, 0, 0, 80)
ReportPlayerName.BackgroundTransparency = 1
ReportPlayerName.Font = Enum.Font.SourceSans
ReportPlayerName.FontSize = Enum.FontSize.Size18
ReportPlayerName.TextColor3 = Color3.new(1, 1, 1)
ReportPlayerName.TextXAlignment = Enum.TextXAlignment.Right
ReportPlayerName.Parent = ReportAbuseFrame
local ReportReasonLabel = Instance.new('TextLabel')
ReportReasonLabel.Name = "ReportReasonLabel"
ReportReasonLabel.Text = "Type of Abuse:"
ReportReasonLabel.Size = UDim2.new(0.4, 0, 0, 36)
ReportReasonLabel.Position = UDim2.new(0.025, 20, 0, 119)
ReportReasonLabel.BackgroundTransparency = 1
ReportReasonLabel.Font = Enum.Font.SourceSans
ReportReasonLabel.FontSize = Enum.FontSize.Size18
ReportReasonLabel.TextColor3 = Color3.new(1, 1, 1)
ReportReasonLabel.TextXAlignment = Enum.TextXAlignment.Left
ReportReasonLabel.Parent = ReportAbuseFrame
local ReportDescriptionLabel = Instance.new('TextLabel')
ReportDescriptionLabel.Name = "ReportDescriptionLabel"
ReportDescriptionLabel.Text = "Short Description: (optional)"
ReportDescriptionLabel.Size = UDim2.new(0.95, 0, 0, 36)
ReportDescriptionLabel.Position = UDim2.new(0.025, 0, 0, 165)
ReportDescriptionLabel.BackgroundTransparency = 1
ReportDescriptionLabel.Font = Enum.Font.SourceSans
ReportDescriptionLabel.FontSize = Enum.FontSize.Size18
ReportDescriptionLabel.TextColor3 = Color3.new(1, 1, 1)
ReportDescriptionLabel.TextXAlignment = Enum.TextXAlignment.Left
ReportDescriptionLabel.Parent = ReportAbuseFrame
local ReportSubmitButton = Instance.new('TextButton')
ReportSubmitButton.Name = "ReportSubmitButton"
ReportSubmitButton.Text = "Submit Report"
ReportSubmitButton.Size = UDim2.new(0.35, 0, 0, 40)
ReportSubmitButton.Position = UDim2.new(0.1, 0, 1, -50)
ReportSubmitButton.Font = Enum.Font.SourceSans
ReportSubmitButton.FontSize = Enum.FontSize.Size18
ReportSubmitButton.TextColor3 = Color3.new(163/255, 162/255, 165/255)
ReportSubmitButton.Active = false
ReportSubmitButton.AutoButtonColor = true
ReportSubmitButton.Modal = true
ReportSubmitButton.Style = Enum.ButtonStyle.RobloxRoundDefaultButton
ReportSubmitButton.Parent = ReportAbuseFrame
local ReportCanelButton = Instance.new('TextButton')
ReportCanelButton.Name = "ReportCanelButton"
ReportCanelButton.Text = "Cancel"
ReportCanelButton.Size = UDim2.new(0.35, 0, 0, 40)
ReportCanelButton.Position = UDim2.new(0.55, 0, 1, -50)
ReportCanelButton.Font = Enum.Font.SourceSans
ReportCanelButton.FontSize = Enum.FontSize.Size18
ReportCanelButton.TextColor3 = Color3.new(1, 1, 1)
ReportCanelButton.Style = Enum.ButtonStyle.RobloxRoundDefaultButton
ReportCanelButton.Parent = ReportAbuseFrame
local AbuseDropDown, updateAbuseSelection = RbxGui.CreateDropDownMenu(ABUSES,
function(abuseText)
AbuseReason = abuseText
if AbuseReason and AbusingPlayer then
ReportSubmitButton.Active = true
ReportSubmitButton.TextColor3 = Color3.new(1, 1, 1)
end
end, true, true, 1)
AbuseDropDown.Name = "AbuseDropDown"
AbuseDropDown.Size = UDim2.new(0.55, 0, 0, 32)
AbuseDropDown.Position = UDim2.new(0.425, 0, 0, 121)
AbuseDropDown.Parent = ReportAbuseFrame
local ReportDescriptionTextFrame = Instance.new('Frame')
ReportDescriptionTextFrame.Name = "ReportDescriptionTextFrame"
ReportDescriptionTextFrame.Size = UDim2.new(0.95, 0, 1, -250)
ReportDescriptionTextFrame.Position = UDim2.new(0.025, 0, 0, 195)
ReportDescriptionTextFrame.BackgroundColor3 = Color3.new(206/255, 206/255, 206/255)
ReportDescriptionTextFrame.BorderSizePixel = 0
ReportDescriptionTextFrame.Parent = ReportAbuseFrame
local ReportDescriptionBox = Instance.new('TextBox')
ReportDescriptionBox.Name = "ReportDescriptionBox"
ReportDescriptionBox.Text = ""
ReportDescriptionBox.Size = UDim2.new(1, -6, 1, -6)
ReportDescriptionBox.Position = UDim2.new(0, 3, 0, 3)
ReportDescriptionBox.Font = Enum.Font.SourceSans
ReportDescriptionBox.FontSize = Enum.FontSize.Size18
ReportDescriptionBox.TextColor3 = Color3.new(0, 0, 0)
ReportDescriptionBox.BackgroundColor3 = Color3.new(206/255, 206/255, 206/255)
ReportDescriptionBox.BorderColor3 = Color3.new(206/255, 206/255, 206/255)
ReportDescriptionBox.TextXAlignment = Enum.TextXAlignment.Left
ReportDescriptionBox.TextYAlignment = Enum.TextYAlignment.Top
ReportDescriptionBox.TextWrap = true
ReportDescriptionBox.ClearTextOnFocus = false
ReportDescriptionBox.Parent = ReportDescriptionTextFrame
-- Report Confirm Gui
local ReportConfirmFrame = Instance.new('Frame')
ReportConfirmFrame.Name = "ReportConfirmFrame"
ReportConfirmFrame.Size = UDim2.new(0, 400, 0, 160)
ReportConfirmFrame.Position = UDim2.new(0.5, -200, 0.5, -80)
ReportConfirmFrame.BackgroundTransparency = 0.7
ReportConfirmFrame.BackgroundColor3 = Color3.new(0, 0, 0)
ReportConfirmFrame.Style = Enum.FrameStyle.DropShadow
local ReportConfirmHeader = Instance.new('TextLabel')
ReportConfirmHeader.Name = "ReportConfirmHeader"
ReportConfirmHeader.Size = UDim2.new(0, 0, 0, 0)
ReportConfirmHeader.Position = UDim2.new(0.5, 0, 0, 14)
ReportConfirmHeader.BackgroundTransparency = 1
ReportConfirmHeader.Text = "Thank You For Your Report"
ReportConfirmHeader.Font = Enum.Font.SourceSans
ReportConfirmHeader.FontSize = Enum.FontSize.Size36
ReportConfirmHeader.TextColor3 = Color3.new(1, 1, 1)
ReportConfirmHeader.Parent = ReportConfirmFrame
local ReportConfirmText = Instance.new('TextLabel')
ReportConfirmText.Name = "ReportConfirmText"
ReportConfirmText.Text = "Our moderators will review your report and the chat log to determine what happened."
ReportConfirmText.Size = UDim2.new(1, -20, 0, 40)
ReportConfirmText.Position = UDim2.new(0, 10, 0, 46)
ReportConfirmText.BackgroundTransparency = 1
ReportConfirmText.Font = Enum.Font.SourceSans
ReportConfirmText.FontSize = Enum.FontSize.Size18
ReportConfirmText.TextColor3 = Color3.new(1, 1, 1)
ReportConfirmText.TextWrap = true
ReportConfirmText.TextXAlignment = Enum.TextXAlignment.Left
ReportConfirmText.TextYAlignment = Enum.TextYAlignment.Top
ReportConfirmText.Parent = ReportConfirmFrame
local ReportConfirmButton = Instance.new('TextButton')
ReportConfirmButton.Name = "ReportConfirmButton"
ReportConfirmButton.Text = "OK"
ReportConfirmButton.Size = UDim2.new(0, 162, 0, 40)
ReportConfirmButton.Position = UDim2.new(0.5, -81, 1, -50)
ReportConfirmButton.Font = Enum.Font.SourceSans
ReportConfirmButton.FontSize = Enum.FontSize.Size18
ReportConfirmButton.TextColor3 = Color3.new(1, 1, 1)
ReportConfirmButton.Style = Enum.ButtonStyle.RobloxRoundDefaultButton
ReportConfirmButton.Parent = ReportConfirmFrame
local function onReportConfirmPressed()
ReportConfirmFrame.Parent = nil
ReportAbuseShield.Parent = nil
ReportAbuseFrame.Parent = ReportAbuseShield
end
ReportConfirmButton.MouseButton1Click:connect(onReportConfirmPressed)
ReportConfirmButton.TouchTap:connect(onReportConfirmPressed)
--[[ Creation Helper Functions ]]--
local function createEntryFrame(name, sizeYOffset)
local containerFrame = Instance.new('Frame')
containerFrame.Name = name
containerFrame.Position = UDim2.new(0, 0, 0, 0)
containerFrame.Size = UDim2.new(1, 0, 0, sizeYOffset)
containerFrame.BackgroundTransparency = 1
containerFrame.Parent = ScrollList
local nameFrame = Instance.new('Frame')
nameFrame.Name = "BGFrame"
nameFrame.Position = UDim2.new(0, 0, 0, 0)
nameFrame.Size = UDim2.new(0, NameEntrySizeX * ScaleX, 0, sizeYOffset)
nameFrame.BackgroundTransparency = BG_TRANSPARENCY
nameFrame.BackgroundColor3 = Color3.new(0, 0, 0)
nameFrame.BorderSizePixel = 0
nameFrame.ClipsDescendants = true
nameFrame.Parent = containerFrame
return containerFrame, nameFrame
end
local function createEntryNameText(name, text, sizeXOffset, posXOffset)
local nameLabel = Instance.new('TextLabel')
nameLabel.Name = name
nameLabel.Size = UDim2.new(-0.01, sizeXOffset, 0.5, 0)
nameLabel.Position = UDim2.new(0.01, posXOffset, 0.245, 0)
nameLabel.BackgroundTransparency = 1
nameLabel.Font = Enum.Font.SourceSans
nameLabel.FontSize = Enum.FontSize.Size14
nameLabel.TextColor3 = TEXT_COLOR
nameLabel.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
nameLabel.TextStrokeColor3 = TEXT_STROKE_COLOR
nameLabel.TextXAlignment = Enum.TextXAlignment.Left
nameLabel.Text = text
return nameLabel
end
local function createStatFrame(offset, parent, name)
local statFrame = Instance.new('Frame')
statFrame.Name = name
statFrame.Size = UDim2.new(0, StatEntrySizeX * ScaleX, 1, 0)
statFrame.Position = UDim2.new(0, offset + 1, 0, 0)
statFrame.BackgroundTransparency = BG_TRANSPARENCY
statFrame.BackgroundColor3 = Color3.new(0, 0, 0)
statFrame.BorderSizePixel = 0
statFrame.Parent = parent
return statFrame
end
local function createStatText(parent, text)
local statText = Instance.new('TextLabel')
statText.Name = "StatText"
statText.Size = UDim2.new(1, 0, 1, 0)
statText.Position = UDim2.new(0, 0, 0, 0)
statText.BackgroundTransparency = 1
statText.Font = Enum.Font.SourceSans
statText.FontSize = Enum.FontSize.Size14
statText.TextColor3 = TEXT_COLOR
statText.TextStrokeColor3 = TEXT_STROKE_COLOR
statText.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
statText.Text = text
statText.Active = true
statText.Parent = parent
return statText
end
local function createImageIcon(image, name, xOffset, parent)
local imageLabel = Instance.new('ImageLabel')
imageLabel.Name = name
imageLabel.Size = UDim2.new(0, 16, 0, 16)
imageLabel.Position = UDim2.new(0.01, xOffset, 0.5, -imageLabel.Size.Y.Offset/2)
imageLabel.BackgroundTransparency = 1
imageLabel.Image = image
imageLabel.BorderSizePixel = 0
imageLabel.Parent = parent
return imageLabel
end
local function getScoreValue(statObject)
if statObject:IsA('DoubleConstrainedValue') or statObject:IsA('IntConstrainedValue') then
return statObject.ConstrainedValue
elseif statObject:IsA('BoolValue') then
if statObject.Value then return 1 else return 0 end
else
return statObject.Value
end
end
local THIN_CHARS = "[^%[iIl\%.,']"
local function strWidth(str)
return string.len(str) - math.floor(string.len(string.gsub(str, THIN_CHARS, "")) / 2)
end
local function formatStatString(text)
local maxLength = MAX_STR_LEN * ScaleX
if strWidth(text) <= maxLength then
return text
else
return string.sub(text, 1, maxLength - 3).."..."
end
end
--[[ Resize Functions ]]--
local LastExpandPosition = ScrollList.Size.Y.Offset
local function setExpandFramePosition()
local canvasOffset = ScrollList.AbsolutePosition.y + ScrollList.CanvasSize.Y.Offset
local scrollListOffset = ScrollList.AbsolutePosition.y + ScrollList.AbsoluteSize.y
local newPosition = math.min(canvasOffset, scrollListOffset)
ExpandFrame.Position = UDim2.new(0, 0, 0, newPosition - Container.AbsolutePosition.y + 2)
end
local LastMaxScrollSize = 0
local function setScrollListSize()
local teamSize = #TeamEntries * TeamEntrySizeY
local playerSize = #PlayerEntries * PlayerEntrySizeY
local spacing = #PlayerEntries * ENTRY_PAD + #TeamEntries * ENTRY_PAD
local canvasSize = teamSize + playerSize + spacing + (#GameStats > 0 and PlayerEntrySizeY or 0)
if #TeamEntries > 0 and NeutralTeam and IsShowingNeutralFrame then
canvasSize = canvasSize + TeamEntrySizeY + ENTRY_PAD
end
ScrollList.CanvasSize = UDim2.new(0, 0, 0, canvasSize)
local newScrollListSize = math.min(canvasSize, Container.AbsoluteSize.y - Header.AbsoluteSize.y)
if ScrollList.Size.Y.Offset == LastMaxScrollSize and not IsExpanding then
ScrollList.Size = UDim2.new(1, 0, 0, newScrollListSize)
end
LastMaxScrollSize = newScrollListSize
setExpandFramePosition()
LastExpandPosition = ScrollList.Size.Y.Offset
end
--[[ Re-position Functions ]]--
local function setPlayerEntryPositions()
local position = #GameStats > 0 and PlayerEntrySizeY + 1 or 0
for i = 1, #PlayerEntries do
PlayerEntries[i].Frame.Position = UDim2.new(0, 0, 0, position)
position = position + PlayerEntrySizeY + 1
end
end
local function setTeamEntryPositions()
local teams = {}
for _,teamEntry in ipairs(TeamEntries) do
local team = teamEntry.Team
teams[tostring(team.TeamColor)] = {}
end
if NeutralTeam then
teams.Neutral = {}
end
for _,playerEntry in ipairs(PlayerEntries) do
local player = playerEntry.Player
if player.Neutral then
table.insert(teams.Neutral, playerEntry)
elseif teams[tostring(player.TeamColor)] then
table.insert(teams[tostring(player.TeamColor)], playerEntry)
else
table.insert(teams.Neutral, playerEntry)
end
end
local position = #GameStats > 0 and PlayerEntrySizeY + 1 or 0
for _,teamEntry in ipairs(TeamEntries) do
local team = teamEntry.Team
teamEntry.Frame.Position = UDim2.new(0, 0, 0, position)
position = position + TeamEntrySizeY + 1
local players = teams[tostring(team.TeamColor)]
for _,playerEntry in ipairs(players) do
playerEntry.Frame.Position = UDim2.new(0, 0, 0, position)
position = position + PlayerEntrySizeY + 1
end
end
if NeutralTeam then
NeutralTeam.Frame.Position = UDim2.new(0, 0, 0, position)
position = position + TeamEntrySizeY + 1
if #teams.Neutral > 0 then
IsShowingNeutralFrame = true
local players = teams.Neutral
for _,playerEntry in ipairs(players) do
playerEntry.Frame.Position = UDim2.new(0, 0, 0, position)
position = position + PlayerEntrySizeY + 1
end
else
IsShowingNeutralFrame = false
end
end
end
local function setEntryPositions()
if #TeamEntries > 0 then
setTeamEntryPositions()
else
setPlayerEntryPositions()
end
end
--[[ Friend/Report Functions ]]--
local selectedEntryMovedCn = nil
local function createPopupFrame(buttons)
local frame = Instance.new('Frame')
frame.Name = "PopupFrame"
frame.Size = UDim2.new(1, 0, 0, (PlayerEntrySizeY * #buttons) + (#buttons - 1))
frame.Position = UDim2.new(1, 1, 0, 0)
frame.BackgroundTransparency = 1
frame.Parent = PopupClipFrame
for i,button in ipairs(buttons) do
local btn = Instance.new('TextButton')
btn.Name = button.Name
btn.Size = UDim2.new(1, 0, 0, PlayerEntrySizeY)
btn.Position = UDim2.new(0, 0, 0, PlayerEntrySizeY * (i - 1) + (i - 1))
btn.BackgroundTransparency = BG_TRANSPARENCY
btn.BackgroundColor3 = Color3.new(0, 0, 0)
btn.BorderSizePixel = 0
btn.Text = button.Text
btn.Font = Enum.Font.SourceSans
btn.FontSize = Enum.FontSize.Size14
btn.TextColor3 = TEXT_COLOR
btn.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
btn.TextStrokeColor3 = TEXT_STROKE_COLOR
btn.AutoButtonColor = true
btn.Parent = frame
btn.MouseButton1Click:connect(button.OnPress)
btn.TouchTap:connect(button.OnPress)
end
return frame
end
local function hideFriendReportPopup()
if PopupFrame then
PopupFrame:TweenPosition(UDim2.new(1, 1, 0, PopupFrame.Position.Y.Offset), Enum.EasingDirection.InOut,
Enum.EasingStyle.Quad, TWEEN_TIME, true, function()
PopupFrame:Destroy()
PopupFrame = nil
if selectedEntryMovedCn then
selectedEntryMovedCn:disconnect()
selectedEntryMovedCn = nil
end
end)
end
if LastSelectedFrame then
for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do
if childFrame:IsA('Frame') then
childFrame.BackgroundColor3 = Color3.new(0, 0, 0)
end
end
end
LastSelectedFrame = nil
LastSelectedPlayer = nil
end
local function onFriendButtonPressed()
if LastSelectedPlayer then
local status = getFriendStatus(LastSelectedPlayer)
if status == Enum.FriendStatus.Friend then
Player:RevokeFriendship(LastSelectedPlayer)
elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then
Player:RequestFriendship(LastSelectedPlayer)
elseif status == Enum.FriendStatus.FriendRequestSent then
Player:RevokeFriendship(LastSelectedPlayer)
elseif status == Enum.FriendStatus.FriendRequestReceived then
Player:RequestFriendship(LastSelectedPlayer)
end
hideFriendReportPopup()
end
end
local function onReportButtonPressed()
if LastSelectedPlayer then
AbusingPlayer = LastSelectedPlayer
ReportPlayerName.Text = AbusingPlayer.Name
ReportAbuseShield.Parent = RobloxGui
hideFriendReportPopup()
end
end
local function resetReportDialog()
AbuseReason = nil
AbusingPlayer = nil
updateAbuseSelection(nil)
ReportPlayerName.Text = ""
ReportDescriptionBox.Text = ""
ReportSubmitButton.Active = false
ReportSubmitButton.TextColor3 = Color3.new(163/255, 162/255, 165/255)
end
local function onAbuseDialogCanceled()
ReportAbuseShield.Parent = nil
resetReportDialog()
end
ReportCanelButton.MouseButton1Click:connect(onAbuseDialogCanceled)
ReportCanelButton.TouchTap:connect(onAbuseDialogCanceled)
local function onAbuseDialogSubmit()
if ReportSubmitButton.Active then
if AbuseReason and AbusingPlayer then
Players:ReportAbuse(AbusingPlayer, AbuseReason, ReportDescriptionBox.Text)
resetReportDialog()
ReportAbuseFrame.Parent = nil
ReportConfirmFrame.Parent = ReportAbuseShield
end
end
end
ReportSubmitButton.MouseButton1Click:connect(onAbuseDialogSubmit)
ReportSubmitButton.TouchTap:connect(onAbuseDialogSubmit)
local function onDeclineFriendButonPressed()
if LastSelectedPlayer then
Player:RevokeFriendship(LastSelectedPlayer)
hideFriendReportPopup()
end
end
local function onPrivilegeLevelSelect(player, rank)
while player.PersonalServerRank < rank do
PersonalServerService:Promote(player)
end
while player.PersonalServerRank > rank do
PersonalServerService:Demote(player)
end
end
local function createPersonalServerDialog(buttons, selectedPlayer)
local showPersonalServerRanks = IsPersonalServer and Player.PersonalServerRank >= PRIVILEGE_LEVEL.ADMIN and
Player.PersonalServerRank > selectedPlayer.PersonalServerRank
if showPersonalServerRanks then
table.insert(buttons, {
Name = "BanButton",
Text = "Ban",
OnPress = function()
hideFriendReportPopup()
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.BANNED)
end,
})
table.insert(buttons, {
Name = "VistorButton",
Text = "Visitor",
OnPress = function()
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.VISITOR)
end,
})
table.insert(buttons, {
Name = "MemberButton",
Text = "Member",
OnPress = function()
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.MEMBER)
end,
})
table.insert(buttons, {
Name = "AdminButton",
Text = "Admin",
OnPress = function()
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.ADMIN)
end,
})
end
end
local function showFriendReportPopup(selectedFrame, selectedPlayer)
local buttons = {}
local status = getFriendStatus(selectedPlayer)
local friendText = ""
local canDeclineFriend = false
if status == Enum.FriendStatus.Friend then
friendText = "Unfriend Player"
elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then
friendText = "Send Friend Request"
elseif status == Enum.FriendStatus.FriendRequestSent then
friendText = "Revoke Friend Request"
elseif status == Enum.FriendStatus.FriendRequestReceived then
friendText = "Accept Friend Request"
canDeclineFriend = true
end
table.insert(buttons, {
Name = "FriendButton",
Text = friendText,
OnPress = onFriendButtonPressed,
})
if canDeclineFriend then
table.insert(buttons, {
Name = "DeclineFriend",
Text = "Decline Friend Request",
OnPress = onDeclineFriendButonPressed,
})
end
table.insert(buttons, {
Name = "ReportButton",
Text = "Report Abuse",
OnPress = onReportButtonPressed,
})
createPersonalServerDialog(buttons, selectedPlayer)
if PopupFrame then
PopupFrame:Destroy()
if selectedEntryMovedCn then
selectedEntryMovedCn:disconnect()
selectedEntryMovedCn = nil
end
end
PopupFrame = createPopupFrame(buttons)
PopupFrame.Position = UDim2.new(1, 1, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y + 39)
PopupFrame:TweenPosition(UDim2.new(0, 0, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y + 39), Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, TWEEN_TIME, true)
selectedEntryMovedCn = selectedFrame.Changed:connect(function(property)
if property == "Position" then
PopupFrame.Position = UDim2.new(0, 0, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y + 39)
end
end)
end
local function onEntryFrameSelected(selectedFrame, selectedPlayer)
if selectedPlayer ~= Player and selectedPlayer.userId > 1 and Player.userId > 1 then
if LastSelectedFrame ~= selectedFrame then
if LastSelectedFrame then
for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do
if childFrame:IsA('Frame') then
childFrame.BackgroundColor3 = Color3.new(0, 0, 0)
end
end
end
LastSelectedFrame = selectedFrame
LastSelectedPlayer = selectedPlayer
for _,childFrame in pairs(selectedFrame:GetChildren()) do
if childFrame:IsA('Frame') then
childFrame.BackgroundColor3 = Color3.new(0, 1, 1)
end
end
-- NOTE: Core script only
ScrollList.ScrollingEnabled = false
showFriendReportPopup(selectedFrame, selectedPlayer)
else
hideFriendReportPopup()
ScrollList.ScrollingEnabled = true
LastSelectedFrame = nil
LastSelectedPlayer = nil
end
end
end
local function onFriendshipChanged(otherPlayer, newFriendStatus)
local entryToUpdate = nil
for _,entry in ipairs(PlayerEntries) do
if entry.Player == otherPlayer then
entryToUpdate = entry
break
end
end
if not entryToUpdate then
return
end
local newIcon = getFriendStatusIcon(newFriendStatus)
local frame = entryToUpdate.Frame
local bgFrame = frame:FindFirstChild('BGFrame')
local friendIcon = nil
local nameFrame = nil
if bgFrame then
friendIcon = bgFrame:FindFirstChild('FriendshipIcon')
nameFrame = bgFrame:FindFirstChild('PlayerName')
end
local offset = 19
if friendIcon then
if newIcon then
friendIcon.Image = newIcon
else
if nameFrame then
newSize = nameFrame.Size.X.Offset + friendIcon.Size.X.Offset + 2
nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0)
nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0)
end
friendIcon:Destroy()
end
elseif newIcon and bgFrame then
friendIcon = createImageIcon(newIcon, "FriendshipIcon", offset, bgFrame)
offset = offset + friendIcon.Size.X.Offset + 2
if nameFrame then
local newSize = bgFrame.Size.X.Offset - offset
nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0)
nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0)
end
end
end
-- NOTE: Core script only
Player.FriendStatusChanged:connect(onFriendshipChanged)
local function updateAllTeamScores()
local teamScores = {}
for _,playerEntry in ipairs(PlayerEntries) do
local player = playerEntry.Player
local leaderstats = player:FindFirstChild('leaderstats')
local team = player.Neutral and 'Neutral' or tostring(player.TeamColor)
local isInValidColor = true
if team ~= 'Neutral' then
for _,teamEntry in ipairs(TeamEntries) do
local color = teamEntry.Team.TeamColor
if team == tostring(color) then
isInValidColor = false
break
end
end
end
if isInValidColor then
team = 'Neutral'
end
if not teamScores[team] then
teamScores[team] = {}
end
if leaderstats then
for _,stat in ipairs(GameStats) do
local statObject = leaderstats:FindFirstChild(stat.Name)
if statObject and not statObject:IsA('StringValue') then
if not teamScores[team][stat.Name] then
teamScores[team][stat.Name] = 0
end
teamScores[team][stat.Name] = teamScores[team][stat.Name] + getScoreValue(statObject)
end
end
end
end
for _,teamEntry in ipairs(TeamEntries) do
local team = teamEntry.Team
local frame = teamEntry.Frame
local color = tostring(team.TeamColor)
local stats = teamScores[color]
if stats then
for statName,statValue in pairs(stats) do
local statFrame = frame:FindFirstChild(statName)
if statFrame then
local statText = statFrame:FindFirstChild('StatText')
if statText then
statText.Text = formatStatString(tostring(statValue))
end
end
end
else
for _,childFrame in pairs(frame:GetChildren()) do
local statText = childFrame:FindFirstChild('StatText')
if statText then
statText.Text = ''
end
end
end
end
if NeutralTeam then
local frame = NeutralTeam.Frame
local stats = teamScores['Neutral']
if stats then
for statName,statValue in pairs(stats) do
local statFrame = frame:FindFirstChild(statName)
if statFrame then
local statText = statFrame:FindFirstChild('StatText')
if statText then
statText.Text = formatStatString(tostring(statValue))
end
end
end
end
end
end
local function updateHeaderScore(statObject)
if #GameStats > 0 then
if statObject.Name == GameStats[1].Name then
if HeaderScore.Text == "" then
HeaderName.Position = UDim2.new(-0.02, 0, 0.005, 0)
end
local score = getScoreValue(statObject)
HeaderScore.Text = tostring(score)
end
end
end
local function updateTeamEntry(entry)
local frame = entry.Frame
local team = entry.Team
local color = team.TeamColor.Color
local offset = NameEntrySizeX * ScaleX
for _,stat in ipairs(GameStats) do
local statFrame = frame:FindFirstChild(stat.Name)
if not statFrame then
statFrame = createStatFrame(offset, frame, stat.Name)
statFrame.BackgroundColor3 = color
createStatText(statFrame, "")
end
statFrame.Position = UDim2.new(0, offset + 1, 0, 0)
offset = offset + statFrame.Size.X.Offset + 1
end
end
local function updateLeaderstatFrames()
if StatNameFrame then
local offset = NameEntrySizeX * ScaleX
for _,stat in ipairs(GameStats) do
local statFrame = StatNameFrame:FindFirstChild(stat.Name)
if not statFrame then
statFrame = createStatFrame(offset, StatNameFrame, stat.Name)
createStatText(statFrame, formatStatString(stat.Name))
end
statFrame.Position = UDim2.new(0, offset + 1, 0, 0)
offset = offset + statFrame.Size.X.Offset + 1
end
end
if #TeamEntries > 0 then
for _,entry in ipairs(TeamEntries) do
updateTeamEntry(entry)
end
if NeutralTeam then
updateTeamEntry(NeutralTeam)
end
end
for _,entry in ipairs(PlayerEntries) do
local player = entry.Player
local mainFrame = entry.Frame
local offset = NameEntrySizeX * ScaleX
local leaderstats = player:FindFirstChild('leaderstats')
if leaderstats then
for _,stat in ipairs(GameStats) do
local statObject = leaderstats:FindFirstChild(stat.Name)
local statFrame = mainFrame:FindFirstChild(stat.Name)
if not statFrame then
statFrame = createStatFrame(offset, mainFrame, stat.Name)
if statObject then
local statValue = getScoreValue(statObject)
local statText = createStatText(statFrame, formatStatString(tostring(statValue)))
statObject.Changed:connect(function(newValue)
statText.Text = formatStatString(tostring(getScoreValue(statObject)))
updateAllTeamScores()
end)
if player == Player then
updateHeaderScore(statObject)
statObject.Changed:connect(function(newValue)
updateHeaderScore(statObject)
end)
end
end
elseif statObject then
local statText = statFrame:FindFirstChild('StatText')
if not statText then
local statValue = getScoreValue(statObject)
statText = createStatText(statFrame, formatStatString(tostring(statValue)))
statObject.Changed:connect(function(newValue)
statText.Text = formatStatString(tostring(getScoreValue(statObject)))
updateAllTeamScores()
end)
if player == Player then
updateHeaderScore(statObject)
statObject.Changed:connect(function(newValue)
updateHeaderScore(statObject)
end)
end
end
end
statFrame.Position = UDim2.new(0, offset + 1, 0, 0)
offset = offset + statFrame.Size.X.Offset + 1
end
else
for _,stat in ipairs(GameStats) do
local statFrame = mainFrame:FindFirstChild(stat.Name)
if not statFrame then
statFrame = createStatFrame(offset, mainFrame, stat.Name)
end
offset = offset + statFrame.Size.X.Offset + 1
end
end
Container.Position = IsPlayerListExpanded and UDim2.new(0.5, -offset/2, 0.15, 0) or
UDim2.new(1, -offset - 2, 0, 2)
Container.Size = UDim2.new(0, offset, 0.5, 0)
local newMinContainerOffset = IsPlayerListExpanded and offset/2 or offset
MinContainerSize = UDim2.new(0, newMinContainerOffset, 0.5, 0)
end
updateAllTeamScores()
end
local function createStatNameFrame()
StatNameFrame = Instance.new('Frame')
StatNameFrame.Name = "StatNameFrame"
StatNameFrame.Position = UDim2.new(0, 0, 0, 0)
StatNameFrame.Size = UDim2.new(1, 0, 0, PlayerEntrySizeY)
StatNameFrame.BackgroundTransparency = 1
StatNameFrame.Parent = ScrollList
local blankFrame = Instance.new('Frame')
blankFrame.Name = "Players"
blankFrame.Position = UDim2.new(0, 0, 0, 0)
blankFrame.Size = UDim2.new(0, NameEntrySizeX * ScaleX, 0, PlayerEntrySizeY)
blankFrame.BackgroundTransparency = BG_TRANSPARENCY
blankFrame.BackgroundColor3 = Color3.new(0, 0, 0, 0)
blankFrame.BorderSizePixel = 0
blankFrame.Parent = StatNameFrame
local nameText = createEntryNameText("PlayerNames", "Players", blankFrame.Size.X.Offset - 2, 2)
nameText.Parent = blankFrame
end
local function addNewStats(leaderstats)
for i,stat in ipairs(leaderstats:GetChildren()) do
if isValidStat(stat) and #GameStats < MAX_LEADERSTATS then
local gameHasStat = false
for _,gStat in ipairs(GameStats) do
if stat.Name == gStat.Name then
gameHasStat = true
break
end
end
if not gameHasStat then
local newStat = {}
newStat.Name = stat.Name
newStat.Priority = 0
newStat.MaxLength = 0
local priority = stat:FindFirstChild('Priority')
if priority then newStat.Priority = priority end
newStat.IsPrimary = false
local isPrimary = stat:FindFirstChild('IsPrimary')
if isPrimary then
newStat.IsPrimary = true
else
stat.ChildAdded:connect(function(child)
if child.Name == "IsPrimary" then
newStat.IsPrimary = true
table.sort(GameStats, sortLeaderStats)
updateHeaderScore(stat)
updateLeaderstatFrames()
end
end)
end
newStat.AddId = StatAddId
StatAddId = StatAddId + 1
table.insert(GameStats, newStat)
table.sort(GameStats, sortLeaderStats)
if #GameStats == 1 then
createStatNameFrame()
setScrollListSize()
setEntryPositions()
end
end
end
end
end
local function removeStatFrameFromEntry(stat, frame)
local statFrame = frame:FindFirstChild(stat.Name)
if statFrame then
statFrame:Destroy()
end
end
local function doesStatExists(stat)
local doesExists = false
for _,entry in ipairs(PlayerEntries) do
local player = entry.Player
if player then
local leaderstats = player:FindFirstChild('leaderstats')
if leaderstats and leaderstats:FindFirstChild(stat.Name) then
doesExists = true
break
end
end
end
return doesExists
end
local function onStatAdded(newStat)
if isValidStat(newStat) then
addNewStats(newStat.Parent)
updateLeaderstatFrames()
end
end
local function onStatRemoved(oldStat, entry)
if isValidStat(oldStat) then
removeStatFrameFromEntry(oldStat, entry.Frame)
local statExists = doesStatExists(oldStat)
if not statExists then
-- remove from player entries
for _,playerEntry in ipairs(PlayerEntries) do
removeStatFrameFromEntry(oldStat, playerEntry.Frame)
end
-- remove from teams
for _,teamEntry in ipairs(TeamEntries) do
removeStatFrameFromEntry(oldStat, teamEntry.Frame)
end
-- remove from statName frame
removeStatFrameFromEntry(oldStat, StatNameFrame)
local toRemove = nil
for i,stat in ipairs(GameStats) do
if stat.Name == oldStat.Name then
toRemove = i
break
end
end
if toRemove then
table.remove(GameStats, toRemove)
table.sort(GameStats, sortLeaderStats)
end
end
if #GameStats == 0 then
StatNameFrame:Destroy()
setEntryPositions()
setScrollListSize()
else
local leaderstats = Player:FindFirstChild('leaderstats')
if leaderstats then
local newPrimaryStat = leaderstats:FindFirstChild(GameStats[1].Name)
if newPrimaryStat then
updateHeaderScore(newPrimaryStat)
else
HeaderScore.Text = ""
HeaderName.Position = UDim2.new(-0.02, 0, 0.245, 0)
end
end
end
updateLeaderstatFrames()
end
end
local function setLeaderStats(entry)
local player = entry.Player
local leaderstats = player:FindFirstChild('leaderstats')
if leaderstats then
addNewStats(leaderstats)
leaderstats.ChildAdded:connect(onStatAdded)
leaderstats.ChildRemoved:connect(function(child)
onStatRemoved(child, entry)
end)
end
updateLeaderstatFrames()
player.ChildAdded:connect(function(child)
if child.Name == 'leaderstats' then
addNewStats(child)
updateLeaderstatFrames()
end
child.ChildAdded:connect(onStatAdded)
child.ChildRemoved:connect(function(removedStat)
onStatRemoved(removedStat, entry)
end)
end)
player.ChildRemoved:connect(function(child)
if child.Name == 'leaderstats' then
for i,stat in ipairs(child:GetChildren()) do
onStatRemoved(stat, entry)
end
updateLeaderstatFrames()
if player == Player then
HeaderScore.Text = ""
HeaderName.Position = UDim2.new(-0.02, 0, 0.245, 0)
end
end
end)
end
local function createPlayerEntry(player)
local playerEntry = {}
local name = player.Name
local containerFrame, entryFrame = createEntryFrame(name, PlayerEntrySizeY)
entryFrame.Active = true
entryFrame.InputBegan:connect(function(inputObject)
local inputType = inputObject.UserInputType
if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then
onEntryFrameSelected(containerFrame, player)
end
end)
local currentXOffset = 1
-- check membership
local membershipIconImage = getMembershipIcon(player)
local membershipIcon = nil
if membershipIconImage then
membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", currentXOffset, entryFrame)
currentXOffset = currentXOffset + membershipIcon.Size.X.Offset + 2
else
currentXOffset = currentXOffset + 18
end
-- check friendship
local friendStatus = getFriendStatus(player)
local friendshipIconImage = getFriendStatusIcon(friendStatus)
local friendshipIcon = nil
if friendshipIconImage then
friendshipIcon = createImageIcon(friendshipIconImage, "FriendshipIcon", currentXOffset, entryFrame)
currentXOffset = currentXOffset + friendshipIcon.Size.X.Offset + 2
end
local playerNameXSize = entryFrame.Size.X.Offset - currentXOffset
local playerName = createEntryNameText("PlayerName", name, playerNameXSize, currentXOffset)
playerName.Parent = entryFrame
playerEntry.Player = player
playerEntry.Frame = containerFrame
return playerEntry
end
local function createTeamEntry(team)
local teamEntry = {}
teamEntry.Team = team
teamEntry.TeamScore = 0
local containerFrame, entryFrame = createEntryFrame(team.Name, TeamEntrySizeY)
entryFrame.BackgroundColor3 = team.TeamColor.Color
local teamName = createEntryNameText("TeamName", team.Name, entryFrame.AbsoluteSize.x, 1)
teamName.Parent = entryFrame
teamEntry.Frame = containerFrame
-- connections
team.Changed:connect(function(property)
if property == 'Name' then
teamName.Text = team.Name
elseif property == 'TeamColor' then
for _,childFrame in pairs(containerFrame:GetChildren()) do
if childFrame:IsA('Frame') then
childFrame.BackgroundColor3 = team.TeamColor.Color
end
end
end
end)
return teamEntry
end
local function createNeutralTeam()
if not NeutralTeam then
local team = Instance.new('Team')
team.Name = 'Neutral'
team.TeamColor = BrickColor.new('White')
NeutralTeam = createTeamEntry(team)
end
end
--[[ Insert/Remove Player Functions ]]--
local function insertPlayerEntry(player)
local entry = createPlayerEntry(player)
if player == Player then
MyPlayerEntry = entry.Frame
end
table.insert(PlayerEntries, entry)
table.sort(PlayerEntries, sortPlayerEntries)
setEntryPositions()
setLeaderStats(entry)
setScrollListSize()
player.Changed:connect(function(property)
if #TeamEntries > 0 and (property == 'Neutral' or property == 'TeamColor') then
setTeamEntryPositions()
updateAllTeamScores()
setScrollListSize()
end
end)
end
local function removePlayerEntry(player)
for i = 1, #PlayerEntries do
if PlayerEntries[i].Player == player then
PlayerEntries[i].Frame:Destroy()
table.remove(PlayerEntries, i)
break
end
end
setEntryPositions()
setScrollListSize()
end
--[[ Team Functions ]]--
local function onTeamAdded(team)
local entry = createTeamEntry(team)
entry.Id = TeamAddId
TeamAddId = TeamAddId + 1
if not NeutralTeam then
createNeutralTeam()
end
table.insert(TeamEntries, entry)
table.sort(TeamEntries, sortTeams)
setTeamEntryPositions()
updateLeaderstatFrames()
setScrollListSize()
end
local function onTeamRemoved(removedTeam)
for i = 1, #TeamEntries do
local team = TeamEntries[i].Team
if team.Name == removedTeam.Name then
TeamEntries[i].Frame:Destroy()
table.remove(TeamEntries, i)
end
end
setEntryPositions()
updateLeaderstatFrames()
setScrollListSize()
end
--[[ Resize/Position Functions ]]--
local function clampCanvasPosition()
local maxCanvasPosition = ScrollList.CanvasSize.Y.Offset - ScrollList.Size.Y.Offset
if maxCanvasPosition >= 0 and ScrollList.CanvasPosition.y > maxCanvasPosition then
ScrollList.CanvasPosition = Vector2.new(0, maxCanvasPosition)
end
end
local function resizeScrollList()
local desiredSize = Container.AbsoluteSize.y - Header.AbsoluteSize.y
if ScrollList.Size.Y.Offset > desiredSize then
ScrollList.Size = UDim2.new(1, 0, 0, desiredSize)
else
local newSize = math.min(desiredSize, LastExpandPosition)
ScrollList.Size = UDim2.new(1, 0, 0, newSize)
end
ScrollList.Position = UDim2.new(0, 0, 0, Header.AbsoluteSize.y + 1)
clampCanvasPosition()
setExpandFramePosition()
end
local function resizeExpandedFrame(containerFrame, scale, name, func)
local offset = 0
local nameFrame = containerFrame:FindFirstChild(name)
if nameFrame then
nameFrame.Size = UDim2.new(0, nameFrame.Size.X.Offset * scale, 1, 0)
nameFrame.Position = UDim2.new(0, offset, 0, 0)
offset = offset + nameFrame.Size.X.Offset + 1
end
for _,stat in ipairs(GameStats) do
local subFrame = containerFrame:FindFirstChild(stat.Name)
if subFrame then
subFrame.Size = UDim2.new(0, subFrame.Size.X.Offset * scale, 1, 0)
subFrame.Position = UDim2.new(0, offset, 0, 0)
offset = offset + subFrame.Size.X.Offset + 1
if func then
func(subFrame, stat.Name)
end
end
end
end
local function expandPlayerList(endPosition, subFrameScale)
local containerOffset = 5 * (ScaleX - 1)
Container:TweenSizeAndPosition(
UDim2.new(0, MinContainerSize.X.Offset * ScaleX - containerOffset, 0.5, 0),
endPosition, Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, TWEEN_TIME, true)
if StatNameFrame then
resizeExpandedFrame(StatNameFrame, subFrameScale, 'Players')
for _,stat in pairs(GameStats) do
local subFrame = StatNameFrame:FindFirstChild(stat.Name)
if subFrame then
local statText = subFrame:FindFirstChild('StatText')
if statText then
statText.Text = formatStatString(stat.Name)
end
end
end
end
for _,entry in ipairs(PlayerEntries) do
local player = entry.Player
local leaderstats = player:FindFirstChild('leaderstats')
local function setScore(subFrame, statName)
if leaderstats then
local statObject = leaderstats:FindFirstChild(statName)
local statText = subFrame:FindFirstChild('StatText')
if statObject and statText then
local score = getScoreValue(statObject)
statText.Text = formatStatString(tostring(score))
end
end
end
resizeExpandedFrame(entry.Frame, subFrameScale, 'BGFrame', setScore)
end
for _,entry in ipairs(TeamEntries) do
resizeExpandedFrame(entry.Frame, subFrameScale, 'BGFrame')
end
if NeutralTeam then
resizeExpandedFrame(NeutralTeam.Frame, subFrameScale, 'BGFrame')
end
updateAllTeamScores()
end
local function resizePlayerList()
resizeScrollList()
end
RobloxGui.Changed:connect(function(property)
if property == 'AbsoluteSize' then
spawn(function() -- must spawn because F11 delays when abs size is set
resizePlayerList()
end)
end
end)
--[[ Input Connections ]]--
local ExpandInputObject = nil
local LastExpandInputPosition = nil
local ExpandOffset = nil
ExpandFrame.InputBegan:connect(function(inputObject)
if LastSelectedFrame then return end
local inputType = inputObject.UserInputType
local inputState = inputObject.UserInputState
if (inputType == Enum.UserInputType.Touch and inputState == Enum.UserInputState.Begin) or inputType == Enum.UserInputType.MouseButton1 then
IsExpanding = true
ExpandInputObject = inputObject
LastExpandInputPosition = inputObject.Position.y
ExpandOffset = inputObject.Position.y - (ScrollList.AbsolutePosition.y + ScrollList.AbsoluteSize.y)
end
end)
UserInputService.InputChanged:connect(function(inputObject)
if inputObject == ExpandInputObject or (ExpandInputObject and inputObject.UserInputType == Enum.UserInputType.MouseMovement) then
local minExpand = ScrollList.AbsolutePosition.y + ExpandOffset
local maxExpand = minExpand + LastMaxScrollSize
local currentPosition = clamp(inputObject.Position.y, minExpand, maxExpand)
local delta = LastExpandInputPosition - currentPosition
local newPosition = clamp(ScrollList.Size.Y.Offset - delta, 0, Container.AbsoluteSize.y - Header.AbsoluteSize.y)
ScrollList.Size = UDim2.new(1, 0, 0, newPosition)
clampCanvasPosition()
setExpandFramePosition()
LastExpandInputPosition = currentPosition
end
end)
UserInputService.InputEnded:connect(function(inputObject)
if inputObject == ExpandInputObject then
ExpandInputObject = nil
LastExpandInputPosition = nil
LastExpandPosition = ScrollList.Size.Y.Offset
IsExpanding = false
elseif ReportAbuseShield.Parent == RobloxGui then
if inputObject.KeyCode == Enum.KeyCode.Escape then
onAbuseDialogCanceled()
end
end
end)
UserInputService.InputBegan:connect(function(inputObject, isProcessed)
if isProcessed then return end
local inputType = inputObject.UserInputType
if (inputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin) or
inputType == Enum.UserInputType.MouseButton1 then
if LastSelectedFrame then
hideFriendReportPopup()
end
end
end)
local function doListExpand()
if not IsPlayerListExpanded then
ScaleX = 2
expandPlayerList(UDim2.new(0.5, -MinContainerSize.X.Offset, 0.15, 0), 2)
else
ScaleX = 1
expandPlayerList(UDim2.new(1, -MinContainerSize.X.Offset - 2, 0, 2), 0.5)
end
IsPlayerListExpanded = not IsPlayerListExpanded
end
Header.InputBegan:connect(function(inputObject)
if LastSelectedFrame then return end
local inputType = inputObject.UserInputType
local inputState = inputObject.UserInputState
if inputObject == ExpandInputObject then return end
if (inputType == Enum.UserInputType.Touch and inputState == Enum.UserInputState.Begin) or inputType == Enum.UserInputType.MouseButton1 then
doListExpand()
end
end)
-- NOTE: Core script only
if GuiService then
GuiService.KeyPressed:connect(function(key)
if key == "\t" then
doListExpand()
end
end)
end
--[[ Player Add/Remove Connections ]]--
Players.ChildAdded:connect(function(child)
if child:IsA('Player') then
insertPlayerEntry(child)
end
end)
for _,player in pairs(Players:GetPlayers()) do
insertPlayerEntry(player)
end
Players.ChildRemoved:connect(function(child)
if child:IsA('Player') then
if LastSelectedPlayer and child == LastSelectedPlayer then
hideFriendReportPopup()
end
removePlayerEntry(child)
end
end)
--[[ Teams ]]--
local function initializeTeams(teams)
for _,team in pairs(teams:GetTeams()) do
onTeamAdded(team)
end
teams.ChildAdded:connect(function(team)
if team:IsA('Team') then
onTeamAdded(team)
end
end)
teams.ChildRemoved:connect(function(team)
if team:IsA('Team') then
onTeamRemoved(team)
end
end)
end
TeamsService = game:FindService('Teams')
if TeamsService then
initializeTeams(TeamsService)
end
game.ChildAdded:connect(function(child)
if child:IsA('Teams') then
initializeTeams(child)
end
end)
--[[ Core Gui Changed events ]]--
-- NOTE: Core script only
local function onCoreGuiChanged(coreGuiType, enabled)
if coreGuiType == Enum.CoreGuiType.All or coreGuiType == Enum.CoreGuiType.PlayerList then
Container.Visible = enabled
GuiService[enabled and "AddKey" or "RemoveKey"](GuiService, "\t")
end
end
pcall(function()
onCoreGuiChanged(Enum.CoreGuiType.PlayerList, game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList))
game:GetService("StarterGui").CoreGuiChangedSignal:connect(onCoreGuiChanged)
end)
resizePlayerList()
Container.Visible = true