syntaxwebsite/app/files/CoreGui/48488236

2425 lines
71 KiB
Plaintext

local RbxGui
local localTesting = true
local screen = script.Parent
local screenResizeCon = nil
local friendWord = "Friend"
local friendWordLowercase = "friend"
local elementNames = {}
local elementNameToElement = {}
local privilegeOwner = 255
local privilegeAdmin = 240
local privilegeMember = 128
local privilegeVisitor = 10
local privilegeBanned = 0
local inContextMenu = false
local contextMenu3d = true
local bigEasingStyle = Enum.EasingStyle.Back
local smallEasingStyle = Enum.EasingStyle.Quart
local personalServerContextAdded = false
local personalServerPlace = false
local success = pcall(function() personalServerPlace = game.IsPersonalServer end)
if not success then
personalServerPlace = false
end
local friendRequestBlacklist = {}
local otherPlayerBlacklist = {}
local currentSortName = ""
local function waitForChild(instance, name)
while not instance:FindFirstChild(name) do
instance.ChildAdded:wait()
end
end
local function waitForProperty(instance, prop)
while not instance[prop] do
instance.Changed:wait()
end
end
local function Color3I(r,g,b)
return Color3.new(r/255,g/255,b/255)
end
function robloxLock(instance)
instance.RobloxLocked = true
children = instance:GetChildren()
if children then
for i, child in ipairs(children) do
robloxLock(child)
end
end
end
function ArrayRemove(t, obj)
for i, obj2 in ipairs(t) do
if obj == obj2 then
table.remove(t, i)
return true
end
end
return false
end
local function getPlayers()
local result = {}
local players = game:GetService("Players"):GetChildren()
if players then
for i, player in ipairs(players) do
if player:IsA("Player") then
table.insert(result, player)
end
end
end
return result
end
local brickColorTable = {}
for i = 0, 63 do
brickColorTable[BrickColor.palette(i).Name] = BrickColor.palette(i).Color
end
local function remapColor(i, j)
brickColorTable[BrickColor.palette(i).Name] = BrickColor.palette(j).Color
end
remapColor(13, 12)
remapColor(14, 12)
remapColor(15, 12)
remapColor(61, 29)
remapColor(63, 62)
remapColor(56, 50)
remapColor(45, 53)
remapColor(51, 20)
remapColor(4, 20)
remapColor(59, 35)
remapColor(60, 29)
local function getColor(brickColor)
if brickColorTable[brickColor.Name] then
return brickColorTable[brickColor.Name]
else
return brickColor.Color;
end
end
local function getTeams()
local result = {}
local teams = game:GetService("Teams"):GetChildren()
for i, team in ipairs(teams) do
if team:IsA("Team") then
table.insert(result, team)
end
end
return result
end
local supportFriends = true
local currentBoardType = "PlayerList"
local currentStatCount = 0
local createBoardsFunction = nil
local playerTable = {}
local teamTable = {}
local teamColorTable = {}
local removePlayerFunction = nil
local recreatePlayerFunction = nil
local addPlayerFunction = function(player)
if recreatePlayerFunction then
recreatePlayerFunction(player)
end
end
local sortPlayerListsFunction = nil
local minimizedState = nil
local bigWindowImposter = nil
local smallWindowPosition = UDim2.new(0, -20, 0,5)
local smallWindowSize = UDim2.new(1,0,1,0)
local bigWindowSize = UDim2.new(0.6,0,0.6,0)
local bigWindowPosition = UDim2.new(.2, 0, .2,0)
local smallWindowHeaderYSize = 32
local debounceTeamsChanged = false
local currentWindowState = "Small"
local previousWindowState = nil
local transitionWindowsFunction = nil
local container = nil
local topRightTrayContainer = nil
local playerContextMenu = nil
local contextMenuElements = {}
local updateContextMenuItems = nil
local function addContextMenuLabel(getText1, getText2, isVisible)
local t = {}
t.Type = "Label"
t.GetText1 = getText1
t.GetText2 = getText2
t.IsVisible = isVisible
table.insert(contextMenuElements, t)
end
local function addContextMenuButton(text, isVisible, isActive, doIt)
local t = {}
t.Text = text
t.Type = "Button"
t.IsVisible = isVisible
t.IsActive = isActive
t.DoIt = doIt
table.insert(contextMenuElements, t)
end
local function getFriendStatus(player)
if player == game.Players.LocalPlayer then
return Enum.FriendStatus.NotFriend
else
local success, result = pcall(function() return game.Players.LocalPlayer:GetFriendStatus(player) end)
if success then
return result
else
return Enum.FriendStatus.NotFriend
end
end
end
local function getPrivilegeType(player)
local rank = player.PersonalServerRank
if rank >= privilegeOwner then
return privilegeOwner
elseif rank < privilegeOwner and rank >= privilegeAdmin then
return privilegeAdmin
elseif rank < privilegeAdmin and rank >= privilegeMember then
return privilegeMember
elseif rank < privilegeMember and rank >= privilegeVisitor then
return privilegeVisitor
else
return privilegeBanned
end
end
--Populate the ContextMenus
addContextMenuLabel(
--GetText1
function(player)
return "Loading..."
end,
--GetText2
nil,
--IsVisible
function(player)
return getFriendStatus(player) == Enum.FriendStatus.Unknown
end)
addContextMenuButton("Send " .. friendWord .. " Request",
--IsVisible
function(player)
return (not otherPlayerBlacklist[player]) and (getFriendStatus(player) == Enum.FriendStatus.NotFriend)
end,
--IsActive
function(player)
return true
end,
--DoIt?
function(player)
otherPlayerBlacklist[player] = true
return game.Players.LocalPlayer:RequestFriendship(player)
end
)
addContextMenuButton("Un" .. friendWordLowercase,
--IsVisible
function(player)
return getFriendStatus(player) == Enum.FriendStatus.Friend
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
return game.Players.LocalPlayer:RevokeFriendship(player)
end
)
addContextMenuButton("Accept " .. friendWord .. " Request",
--IsVisible
function(player)
return (not friendRequestBlacklist[player]) and (getFriendStatus(player) == Enum.FriendStatus.FriendRequestReceived)
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
return game.Players.LocalPlayer:RequestFriendship(player)
end
)
addContextMenuButton("Deny " .. friendWord .. " Request",
--IsVisible
function(player)
return getFriendStatus(player) == Enum.FriendStatus.FriendRequestReceived
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
friendRequestBlacklist[player] = true
return game.Players.LocalPlayer:RevokeFriendship(player)
end
)
addContextMenuButton("Cancel " .. friendWord .. " Request",
--IsVisible
function(player)
return false -- disable cancel request for now (can lead to griefing)
--return getFriendStatus(player) == Enum.FriendStatus.FriendRequestSent
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
otherPlayerBlacklist[player] = false
return game.Players.LocalPlayer:RevokeFriendship(player)
end
)
function addPersonalServerContext()
if personalServerContextAdded then return end
personalServerContextAdded = true
addContextMenuButton("Ban",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin and (getPrivilegeType(player) < privilegeAdmin) )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
player.PersonalServerRank = privilegeBanned
return true
end
)
addContextMenuButton("Promote to Visitor",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeBanned )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
game:GetService("PersonalServerService"):Promote(player)
return true
end
)
addContextMenuButton("Promote to Member",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeVisitor )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
game:GetService("PersonalServerService"):Promote(player)
return true
end
)
addContextMenuButton("Promote to Admin",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) == privilegeOwner ) and ( getPrivilegeType(player) == privilegeMember )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
game:GetService("PersonalServerService"):Promote(player)
return true
end
)
addContextMenuButton("Demote to Member",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) == privilegeOwner ) and ( getPrivilegeType(player) == privilegeAdmin )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
game:GetService("PersonalServerService"):Demote(player)
return true
end
)
addContextMenuButton("Demote to Visitor",
--IsVisible
function(player)
return ( getPrivilegeType(game.Players.LocalPlayer) >= privilegeAdmin ) and ( getPrivilegeType(player) == privilegeMember )
end,
--IsActive
function(player)
return true
end,
--DoIt
function(player)
game:GetService("PersonalServerService"):Demote(player)
return true
end
)
end
local function setupBuildToolManagement()
local buildToolManagerAssetId = 64164692
game:GetService("ScriptContext"):AddCoreScript(buildToolManagerAssetId,game.Players.LocalPlayer,"BuildToolManager")
end
local function getStatColumns(players)
for i, player in ipairs(players) do
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local stats = {}
local children = leaderstats:GetChildren()
if children then
for i, stat in ipairs(children) do
if stat:IsA("IntValue") then
table.insert(stats, stat)
else
--TODO: This should check for IntValue only but current ScoreHud does not
table.insert(stats, stat)
end
end
end
return stats
end
end
return nil
end
local function determineBoardType()
local players = getPlayers()
local foundLeaderstats = false
local numStats = 0
local foundTeam = false
local stats = getStatColumns(players)
if stats then
foundLeaderstats = true
numStats = #stats
end
for i, player in ipairs(players) do
if not foundTeam then
if not player.Neutral then
foundTeam = true
break
end
end
end
if foundLeaderstats and foundTeam then
return "TeamScore", numStats
elseif foundLeaderstats then
return "PlayerScore", numStats
elseif foundTeam then
return "TeamList", numStats
else
return "PlayerList", numStats
end
end
local function toggleBigWindow()
if container == nil then
return
end
if currentWindowState == "Big" then
--Hide it
if previousWindowState == nil or previousWindowState == "Big" or previousWindowState == "None" then
transitionWindowsFunction("None")
else
transitionWindowsFunction("Small")
end
else
previousWindowState = currentWindowState
transitionWindowsFunction("Big")
end
end
local previousBigPlayerList = nil
local function rebuildBoard(owner, boardType, numStats)
if topRightTrayContainer == nil then
topRightTrayContainer = owner:FindFirstChild("PlayerListTopRightFrame")
if topRightTrayContainer == nil then
topRightTrayContainer = Instance.new("Frame")
topRightTrayContainer.Name = "PlayerListTopRightFrame"
topRightTrayContainer.BackgroundTransparency = 1
topRightTrayContainer.Size = UDim2.new(0.2, 16, 0.42, 16)
topRightTrayContainer.Position = UDim2.new(0.8, 0, 0, 0)
topRightTrayContainer.Parent = container
end
end
if minimizedState == nil then
minimizedState = Instance.new("Frame")
minimizedState.Name = "MinimizedPlayerlist"
minimizedState.BackgroundTransparency = 1
minimizedState.Position = UDim2.new(1, -166, 0,0)
minimizedState.Size = UDim2.new(0, 151, 0, 30)
playerListButton = Instance.new("ImageButton")
playerListButton.Name = "GoSmallButton"
playerListButton.Image = "rbxasset://textures/ui/playerlist_hidden_small.png"
playerListButton.BackgroundTransparency = 1
playerListButton.Size = UDim2.new(0.0, 35, 0, 30)
playerListButton.Position = UDim2.new(1, -35, 0, 0)
playerListButton.MouseButton1Click:connect(
function()
transitionWindowsFunction("Small")
end)
playerListButton.Parent = minimizedState
minimizedState.Visible = false
robloxLock(minimizedState)
minimizedState.Parent = topRightTrayContainer
end
if bigWindowImposter == nil then
bigWindowImposter = owner:FindFirstChild("BigPlayerListWindowImposter")
if bigWindowImposter == nil then
bigWindowImposter = Instance.new("Frame")
bigWindowImposter.Name = "BigPlayerListWindowImposter"
bigWindowImposter.Visible = false
bigWindowImposter.BackgroundColor3 = Color3.new(0,0,0)
bigWindowImposter.BackgroundTransparency = 0.7
bigWindowImposter.BorderSizePixel = 0
bigWindowImposter.Size = UDim2.new(0.4, 7, 0.4, 7)
bigWindowImposter.Position = UDim2.new(0.3, 0, 0.3, 0)
robloxLock(bigWindowImposter)
bigWindowImposter.Parent = container
end
end
if container == nil or container ~= owner then
container = owner
topRightTrayContainer.Parent = container
bigWindowImposter.Parent = container
end
local smallVisible = true
local bigVisible = false
if container then
if topRightTrayContainer then
--Delete the old boards
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
smallVisible = topRightTrayContainer.SmallPlayerlist.Visible
topRightTrayContainer.SmallPlayerlist.Parent = nil
end
end
if container:FindFirstChild("BigPlayerlist") then
bigVisible = container.BigPlayerlist.Visible or (previousBigPlayerList ~= nil)
container.BigPlayerlist.Parent = nil
if previousBigPlayerList ~= nil then
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
previousBigPlayerList = nil
end
end
end
local smallBoard, bigBoard = createBoardsFunction(boardType, numStats)
if smallBoard then
smallBoard.Visible = smallVisible
smallBoard.Parent = topRightTrayContainer
recalculateSmallPlayerListSize(smallBoard)
end
if bigBoard then
if bigVisible then
previousBigPlayerList = bigBoard
local centerDialogSupported, msg = pcall(function() game.GuiService:AddCenterDialog(previousBigPlayerList, Enum.CenterDialogType.PlayerInitiatedDialog,
function()
previousBigPlayerList.Visible = true
end,
function()
previousBigPlayerList.Visible = false
end)
end)
bigBoard.Visible = bigVisible
else
bigBoard.Visible = false
end
bigBoard.Parent = container
end
return container
end
function recalculateSmallPlayerListSize(smallPlayerList)
waitForChild(smallPlayerList,"ScrollingArea")
waitForChild(smallPlayerList.ScrollingArea, "ScrollingFrame")
local scrollingFrame = smallPlayerList.ScrollingArea.ScrollingFrame
local playerLines = scrollingFrame:GetChildren()
local totalPlayerListSize = 0
for i = 1, #playerLines do
totalPlayerListSize = totalPlayerListSize + playerLines[i].AbsoluteSize.Y
end
if not smallPlayerList.Parent then return end
local yOffset = math.max(0,(smallPlayerList.Size.Y.Scale * smallPlayerList.Parent.AbsoluteSize.Y) - totalPlayerListSize - smallWindowHeaderYSize)
smallPlayerList.Size = UDim2.new(smallPlayerList.Size.X.Scale,smallPlayerList.Size.X.Offset,smallPlayerList.Size.Y.Scale,-yOffset)
end
local function showBigPlayerWindow()
if container:FindFirstChild("BigPlayerlist") then
if container.BigPlayerlist.Visible then
return
end
end
bigWindowImposter.Visible = true
bigWindowImposter:TweenSizeAndPosition(bigWindowSize, bigWindowPosition, Enum.EasingDirection.Out, bigEasingStyle, 0.3, true,
function(state)
if state == Enum.TweenStatus.Completed then
bigWindowImposter.Visible = false
if container:FindFirstChild("BigPlayerlist") then
container.BigPlayerlist.Visible = true
end
end
end)
end
local function hideBigPlayerWindow(completed)
if playerContextMenu then
playerContextMenu.Visible = false
end
if container:FindFirstChild("BigPlayerlist") then
if container.BigPlayerlist.Visible == false and bigWindowImposter.Visible == false then
if completed then
completed()
end
--Already completely hidden
return
end
container.BigPlayerlist.Visible = false
end
local completedFunction = completed
bigWindowImposter.Visible = true
bigWindowImposter:TweenSizeAndPosition(UDim2.new(0.4, 0, 0.4, 0), UDim2.new(0.3, 0, 0.3, 0), Enum.EasingDirection.In, Enum.EasingStyle.Quart, 0.15, true,
function(state)
if state == Enum.TweenStatus.Completed then
bigWindowImposter.Visible = false
if completedFunction then
completedFunction()
end
end
end)
end
local function hideSmallPlayerWindow(completed)
if playerContextMenu then
playerContextMenu.Visible = false
end
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
local completedFunction = completed
if topRightTrayContainer.SmallPlayerlist.Visible then
topRightTrayContainer.SmallPlayerlist:TweenPosition(UDim2.new(1,0,smallWindowPosition.Y.Scale, smallWindowPosition.Y.Offset), Enum.EasingDirection.Out, smallEasingStyle, 0.3, true,
function(state)
if state == Enum.TweenStatus.Completed then
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
topRightTrayContainer.SmallPlayerlist.Visible = false
end
if completedFunction then
completedFunction()
end
end
end)
return
end
end
if completed then
completed()
end
end
transitionWindowsFunction = function(desiredState)
if desiredState == "Big" then
minimizedState.Visible = false
hideSmallPlayerWindow()
if previousBigPlayerList ~= nil then
if previousBigPlayerList ~= container:FindFirstChild("BigPlayerlist") then
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
previousBigPlayerList = nil
previousBigPlayerList = container:FindFirstChild("BigPlayerlist")
end
else
previousBigPlayerList = container:FindFirstChild("BigPlayerlist")
end
if previousBigPlayerList then
local firstShow = false
local centerDialogSupported, msg = pcall(function() game.GuiService:AddCenterDialog(previousBigPlayerList, Enum.CenterDialogType.PlayerInitiatedDialog,
function()
if not firstShow then
showBigPlayerWindow()
firstShow = true
else
previousBigPlayerList.Visible = true
end
end,
function()
if previousBigPlayerList then
previousBigPlayerList.Visible = false
end
end)
end)
if centerDialogSupported == false then
print("Exception", msg)
showBigPlayerWindow()
end
else
showBigPlayerWindow()
end
currentWindowState = "Big"
elseif desiredState == "Small" then
minimizedState.Visible = false
if previousBigPlayerList ~= nil then
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
previousBigPlayerList = nil
end
hideBigPlayerWindow()
if topRightTrayContainer:FindFirstChild("SmallPlayerlist") then
if not topRightTrayContainer.SmallPlayerlist.Visible or topRightTrayContainer.SmallPlayerlist.Position ~= smallWindowPosition then
topRightTrayContainer.SmallPlayerlist.Visible = true
topRightTrayContainer.SmallPlayerlist:TweenPosition(smallWindowPosition, Enum.EasingDirection.Out, smallEasingStyle, 0.3, true)
end
end
currentWindowState = "Small"
elseif desiredState == "None" then
if previousBigPlayerList ~= nil then
pcall(function() game.GuiService:RemoveCenterDialog(previousBigPlayerList) end)
previousBigPlayerList = nil
end
local smallDone = false
local bigDone = false
hideSmallPlayerWindow(
function()
smallDone = true
if bigDone and smallDone then
minimizedState.Visible = true
end
end)
hideBigPlayerWindow(
function()
bigDone = true
if bigDone and smallDone then
minimizedState.Visible = true
end
end)
currentWindowState = "None"
end
end
local function getStatValuesForPlayer(player)
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local children = leaderstats:GetChildren()
if children then
local result = {}
--Just go based on position
for i, stat in ipairs(children) do
if stat:IsA("IntValue") then
table.insert(result, stat)
else
table.insert(result, 0)
end
end
return result, leaderstats
end
end
return nil
end
--ChildAdded on Player (if it's name is "leaderstats")
if UserSettings and LoadLibrary then
RbxGui,msg = LoadLibrary("RbxGui")
local function createTeamName(name, color)
local fontHeight = 20
local frame = Instance.new("Frame")
frame.Name = "Team-" .. name
frame.BorderSizePixel = 0
frame.BackgroundTransparency = 0.5
frame.BackgroundColor3 = Color3.new(1,1,1)
frame.Size = UDim2.new(1, 0, 0, fontHeight)
frame.Position = UDim2.new(0,0,0,0)
local label = Instance.new("TextLabel")
label.Name = "NameLabel"
label.Text = " " .. name
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size18
label.Position = UDim2.new(0,0,0,0)
label.Size = UDim2.new(1,0,1,0)
label.TextColor3 = Color3.new(1,1,1)
label.BackgroundTransparency = 0.5
label.BackgroundColor3 = getColor(color)
label.BorderSizePixel = 0
label.TextXAlignment = Enum.TextXAlignment.Left
local changeFunc = nil
label, changeFunc = RbxGui.AutoTruncateTextObject(label)
label.Parent = frame
return frame, changeFunc
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 "rbxasset://textures/ui/PlayerlistFriendIcon.png"
elseif friendStatus == Enum.FriendStatus.FriendRequestSent then
return "rbxasset://textures/ui/PlayerlistFriendRequestSentIcon.png"
elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then
return "rbxasset://textures/ui/PlayerlistFriendRequestReceivedIcon.png"
else
error("Unknown FriendStatus: " .. friendStatus)
end
end
local function getMembershipTypeIcon(membershipType)
if membershipType == Enum.MembershipType.None then
return ""
elseif membershipType == Enum.MembershipType.BuildersClub then
return "rbxasset://textures/ui/TinyBcIcon.png"
elseif membershipType == Enum.MembershipType.TurboBuildersClub then
return "rbxasset://textures/ui/TinyTbcIcon.png"
elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then
return "rbxasset://textures/ui/TinyObcIcon.png"
else
error("Uknown membershipType" .. membershipType)
end
end
local function updatePlayerFriendStatus(nameObject, friendStatus)
local fontHeight = 20
local friendIconImage = getFriendStatusIcon(friendStatus)
nameObject.MembershipTypeLabel.FriendStatusLabel.Visible = (friendIconImage ~= nil)
if friendIconImage ~= nil then
--Show friend icon
nameObject.MembershipTypeLabel.FriendStatusLabel.Image = friendIconImage
nameObject.NameLabel.Position =UDim2.new(0,2*fontHeight,0,1)
nameObject.NameLabel.Size = UDim2.new(1,-2*fontHeight,1,-2)
else
--Hide the friend icon
nameObject.NameLabel.Position = UDim2.new(0,fontHeight+1,0,1)
nameObject.NameLabel.Size = UDim2.new(1,-(fontHeight+1),1,-2)
end
end
local function updatePlayerName(nameObject, membershipStatus, teamColor)
local fontHeight = 20
nameObject.Size = UDim2.new(1,0,0,fontHeight)
nameObject.MembershipTypeLabel.Image = getMembershipTypeIcon(membershipStatus)
end
local function updatePlayerNameColor(player, teamColor)
local function updatePlayerNameColorHelper(nameObject)
if teamColor ~= nil then
nameObject.NameLabel.TextColor3 = getColor(teamColor)
nameObject.NameLabel.FullNameLabel.TextColor3 = getColor(teamColor)
else
nameObject.NameLabel.TextColor3 = Color3.new(1,1,1)
nameObject.NameLabel.FullNameLabel.TextColor3 = Color3.new(1,1,1)
end
end
updatePlayerNameColorHelper(playerTable[player].NameObjectSmall)
updatePlayerNameColorHelper(playerTable[player].NameObjectBig)
end
local function createPlayerName(name, membershipStatus, teamColor, friendStatus)
local frame = Instance.new("Frame")
frame.Name = "Player_" .. name
frame.BackgroundColor3 = Color3.new(1,1,1)
frame.BackgroundTransparency = 0.5
frame.BorderSizePixel = 0
local membershipStatusLabel = Instance.new("ImageLabel")
membershipStatusLabel.Name = "MembershipTypeLabel"
membershipStatusLabel.BackgroundTransparency = 1
membershipStatusLabel.Size = UDim2.new(1,0,1,0)
membershipStatusLabel.Position = UDim2.new(0,0,0,0)
membershipStatusLabel.SizeConstraint = Enum.SizeConstraint.RelativeYY
membershipStatusLabel.Parent = frame
local friendStatusLabel = Instance.new("ImageLabel")
friendStatusLabel.Name = "FriendStatusLabel"
friendStatusLabel.Visible = false
friendStatusLabel.BackgroundTransparency = 1
friendStatusLabel.Size = UDim2.new(1,0,1,0)
friendStatusLabel.Position = UDim2.new(1,0,0,0)
friendStatusLabel.Parent = membershipStatusLabel
local changeNameFunction
local nameLabel = Instance.new("TextLabel")
nameLabel.Name = "NameLabel"
nameLabel.Text = name
nameLabel.Font = Enum.Font.ArialBold
nameLabel.FontSize = Enum.FontSize.Size14
nameLabel.TextColor3 = Color3.new(1,1,1)
nameLabel.BackgroundTransparency = 1
nameLabel.BackgroundColor3 = Color3.new(0,0,0)
nameLabel.TextXAlignment = Enum.TextXAlignment.Left
nameLabel, changeNameFunction = RbxGui.AutoTruncateTextObject(nameLabel)
nameLabel.Parent = frame
updatePlayerName(frame, membershipStatus, teamColor)
if supportFriends and not friendRequestBlacklist[game.Players:FindFirstChild(name)] then
updatePlayerFriendStatus(frame, friendStatus)
else
updatePlayerFriendStatus(frame, Enum.FriendStatus.NotFriend)
end
return frame, changeNameFunction
end
local function createStatColumn(i, numColumns, isTeam, color3, isHeader, stat)
local textLabel = Instance.new("TextButton")
textLabel.Name = "Stat" .. i
textLabel.AutoButtonColor = false
textLabel.TextColor3 = Color3.new(1,1,1)
textLabel.TextXAlignment = Enum.TextXAlignment.Right
textLabel.TextYAlignment = Enum.TextYAlignment.Center
textLabel.FontSize = Enum.FontSize.Size14
if isHeader then
textLabel.FontSize = Enum.FontSize.Size18
else
textLabel.FontSize = Enum.FontSize.Size14
end
if isHeader or isTeam then
textLabel.Font = Enum.Font.ArialBold
else
textLabel.Font = Enum.Font.Arial
end
if isTeam then
textLabel.BackgroundColor3 = color3
textLabel.Text = 0
else
textLabel.BackgroundColor3 = Color3.new(0,0,0)
textLabel.Text = ""
end
textLabel.BackgroundTransparency = 1
if i == numColumns then
textLabel.Size = UDim2.new(1/numColumns, -6, 1, 0)
else
textLabel.Size = UDim2.new(1/numColumns, -4, 1, 0)
end
textLabel.Position = UDim2.new((i-1) * (1/numColumns), 0, 0, 0)
local truncLabel, changer = RbxGui.AutoTruncateTextObject(textLabel)
if isHeader then
local mouseCon = {}
mouseCon[1] = truncLabel.MouseEnter:connect(function()
truncLabel.BackgroundTransparency = 0.2
end)
mouseCon[2] = truncLabel.MouseLeave:connect(function()
truncLabel.BackgroundTransparency = 1
end)
mouseCon[3] = truncLabel.MouseButton1Click:connect(function()
sortPlayerListsFunction(truncLabel:GetChildren()[1].Name, (currentSortName == truncLabel:GetChildren()[1].Name) )
truncLabel.BackgroundTransparency = 1
end)
mouseCon[4] = truncLabel:GetChildren()[1].MouseButton1Click:connect(function()
sortPlayerListsFunction(textLabel.Name, (currentSortName == truncLabel.Name) )
truncLabel.BackgroundTransparency = 1
end)
mouseCon[5] = nil
mouseCon[5] = truncLabel.AncestryChanged:connect(function(child,parent)
if parent == nil then
for i,connection in pairs(mouseCon) do
connection:disconnect()
end
end
end)
end
return truncLabel, changer
end
local function createStatHeaders(stats, numColumns, isBig)
local frame = Instance.new("Frame")
frame.Name = "Headers"
frame.BorderSizePixel = 0
frame.BackgroundColor3 = Color3.new(0,0,0)
frame.BackgroundTransparency = 1
local nameSize
if isBig then
nameSize = 0.5
elseif numColumns == 1 then
nameSize = 0.7
elseif numColumns == 2 then
nameSize = 0.6
else
nameSize = 0.45
end
frame.Size = UDim2.new(1-nameSize, 0, 1,0)
if isBig then
frame.Position = UDim2.new(nameSize,-25, 0,0)
else
frame.Position = UDim2.new(nameSize,0, 0,0)
end
local i = 1
while i <= numColumns do
local headerColumn, changeText = createStatColumn(i, numColumns, false, nil, true,stats[i])
changeText(stats[i].Name)
headerColumn.Parent = frame
i = i + 1
end
return frame, textChangers
end
local function createStatColumns(nameObject, numColumns, isTeam, isBig)
local frame = Instance.new("Frame")
frame.Name = nameObject.Name .. "_WithStats"
frame.BorderSizePixel = 0
frame.BackgroundColor3 = nameObject.BackgroundColor3
frame.BackgroundTransparency = nameObject.BackgroundTransparency
frame.Size = nameObject.Size
frame.Position = nameObject.Position
nameObject.BackgroundTransparency = 1
if numColumns == 0 then
nameObject.Size = UDim2.new(1,0,1,0)
nameObject.Position = UDim2.new(0,0,0,0)
nameObject.Parent = frame
return frame
end
local statFrame = Instance.new("Frame")
statFrame.Name = "Stats"
if isTeam then
statFrame.BorderSizePixel = 0
statFrame.BackgroundColor3 = nameObject.NameLabel.BackgroundColor3
statFrame.BackgroundTransparency = nameObject.NameLabel.BackgroundTransparency
else
statFrame.BackgroundTransparency = 1
end
local nameSize
if isBig then
nameSize = 0.5
elseif numColumns == 1 then
nameSize = 0.7
elseif numColumns == 2 then
nameSize = 0.6
else
nameSize = 0.45
end
nameObject.Size = UDim2.new(nameSize, 0, 1, 0)
nameObject.Position = UDim2.new(0, 0, 0, 0)
statFrame.Size = UDim2.new(1-nameSize,0, 1,0)
statFrame.Position = UDim2.new(nameSize,0, 0,0)
nameObject.Parent = frame
statFrame.Parent = frame
local textChangers = {}
local i = 1
while i <= numColumns do
local statColumn, changeText = createStatColumn(i, numColumns, isTeam, statFrame.BackgroundColor3)
statColumn.Parent = statFrame
table.insert(textChangers, changeText)
i = i + 1
end
return frame, statFrame, textChangers
end
local function createAlternatingRows(objects)
for i, line in ipairs(objects) do
if i % 2 == 0 then
line.BackgroundTransparency = 1
else
line.BackgroundTransparency = 0.95
end
end
end
local removeFromTeam = nil
local function clearTableEntry(obj, tableInfo)
if tableInfo.MainObjectSmall then
tableInfo.MainObjectSmall.Parent = nil
tableInfo.MainObjectSmall = nil
end
if tableInfo.MainObjectBig then
tableInfo.MainObjectBig.Parent = nil
tableInfo.MainObjectBig = nil
end
if tableInfo.Connections then
for i, connection in ipairs(tableInfo.Connections) do
connection:disconnect()
end
tableInfo.Connections = nil
end
if tableInfo.LeaderStatConnections then
for i, connection in ipairs(tableInfo.LeaderStatConnections) do
connection:disconnect()
end
tableInfo.LeaderStatConnections = nil
end
if tableInfo.CurrentTeam then
removeFromTeam(obj)
tableInfo.CurrentTeam = nil
end
if tableInfo.Players then
for i, player in ipairs(tableInfo.Players) do
playerTable[player].CurrentTeam = nil
end
tableInfo.Players = {}
end
if tableInfo.StatValues then
tableInfo.StatValues = nil
end
end
local function resetPlayerTable()
for player, info in pairs(playerTable) do
clearTableEntry(player, info)
playerTable[player] = nil
end
playerTable = {}
end
local function resetTeamTable()
for team, info in pairs(teamTable) do
clearTableEntry(team, info)
teamTable[team] = nil
end
teamTable = {}
teamColorTable = {}
end
local function getBoardTypeInfo()
local isTeam = (currentBoardType == "TeamScore" or currentBoardType == "TeamList")
local isScore = (currentBoardType == "TeamScore" or currentBoardType == "PlayerScore")
return isTeam, isScore
end
local function recomputeTeamScore(team, column)
if not team or team == "Neutral" then
return
end
local function recomputeScoreHelper(statChangers)
if statChangers and column <= #statChangers then
local sum = 0
for i, p in ipairs(teamTable[team].Players) do
if playerTable[p].StatValues and column <= #playerTable[p].StatValues then
sum = sum + playerTable[p].StatValues[column].Value
end
end
statChangers[column](sum)
end
end
recomputeScoreHelper(teamTable[team].StatChangersSmall)
recomputeScoreHelper(teamTable[team].StatChangersBig)
end
local function recomputeCompleteTeamScore(team)
local col = 1
while col <= currentStatCount do
recomputeTeamScore(team, col)
col = col + 1
end
end
removeFromTeam = function(player)
if playerTable[player].CurrentTeam ~= nil and teamTable[playerTable[player].CurrentTeam] ~= nil then
ArrayRemove(teamTable[playerTable[player].CurrentTeam].Players, player)
recomputeCompleteTeamScore(playerTable[player].CurrentTeam)
playerTable[player].CurrentTeam = nil
end
end
local function assignToTeam(player)
local isTeam, isScore = getBoardTypeInfo()
if isTeam then
local newTeam = nil
if player.Neutral or teamColorTable[player.TeamColor.Name] == nil then
newTeam = "Neutral"
else
newTeam = teamColorTable[player.TeamColor.Name]
end
if playerTable[player].CurrentTeam == newTeam then
return
end
local oldTeam = playerTable[player].LastTeam
removeFromTeam(player)
playerTable[player].CurrentTeam = newTeam
if teamTable[oldTeam] and teamTable[oldTeam]["NameChangeFuncBig"] then
if #teamTable[oldTeam].Players < 1 then
teamTable[oldTeam]["NameChangeFuncBig"](" " .. oldTeam.Name)
else
teamTable[oldTeam]["NameChangeFuncBig"](" " .. oldTeam.Name .. " (" .. tostring(#teamTable[oldTeam].Players) ..")")
end
end
if teamTable[newTeam] then
table.insert(teamTable[newTeam].Players, player)
if newTeam["Name"] then
if teamTable[newTeam]["NameChangeFuncBig"] then
if #teamTable[newTeam].Players < 1 then
teamTable[newTeam]["NameChangeFuncBig"](" " .. newTeam.Name)
else
teamTable[newTeam]["NameChangeFuncBig"](" " .. newTeam.Name .. " (" .. tostring(#teamTable[newTeam].Players) ..")")
end
end
end
end
if newTeam == "Neutral" then
updatePlayerNameColor(player, nil)
else
updatePlayerNameColor(player, player.TeamColor)
end
playerTable[player].LastTeam = newTeam
recomputeCompleteTeamScore(newTeam)
--Relayout
if sortPlayerListsFunction then
sortPlayerListsFunction()
end
end
end
local function buildTeamObject(team, numStatColumns, suffix)
local isTeam, isScore = getBoardTypeInfo()
local teamObject, changeFunc = createTeamName(team.Name, team.TeamColor)
teamObject.NameLabel.Text = " " .. team.Name .. " (0)"
if not teamTable[team] then
teamTable[team] = {}
end
teamTable[team]["NameObject" .. suffix] = teamObject
teamTable[team]["NameChangeFunc" .. suffix] = changeFunc
if isScore then
local statObject
local textChangers
teamObject, statObject, textChangers = createStatColumns(teamObject, numStatColumns, true, suffix == "Big")
teamTable[team]["StatObject" .. suffix] = statObject
teamTable[team]["StatChangers" .. suffix] = textChangers
end
teamTable[team]["MainObject" .. suffix] = teamObject
changeFunc(" " .. team.Name)
if not teamTable[team].Players then
teamTable[team].Players = {}
else
if suffix ~= "Small" and #teamTable[team].Players > 0 then
changeFunc(" " .. team.Name .. " (" .. tostring(#teamTable[team].Players) ..")")
end
end
return teamObject
end
local currentContextMenuPlayer = nil
local function updatePlayerContextMenu(player,x,y)
currentContextMenuPlayer = player
local elementHeight = 18
local function highlight(button)
button.TextColor3 = Color3.new(0,0,0)
button.BackgroundColor3 = Color3.new(0.8,0.8,0.8)
end
local function clearHighlight(button)
button.TextColor3 = Color3.new(1,1,1)
button.BackgroundColor3 = Color3.new(0,0,0)
end
if playerContextMenu == nil then
elementNames = {}
elementNameToElement = {}
for i, contextElement in ipairs(contextMenuElements) do
table.insert(elementNames, contextElement.Text)
elementNameToElement[tostring(contextElement.Text)] = contextElement
end
playerContextMenu = Instance.new("TextButton")
playerContextMenu.Name = "PlayerListContextMenu"
playerContextMenu.Style = Enum.ButtonStyle.RobloxButton
playerContextMenu.Text = ""
playerContextMenu.Visible = false
playerContextMenu.ZIndex = 4
playerContextMenu.MouseLeave:connect(function()
local menuChildren = playerContextMenu:GetChildren()
for i = 1, #menuChildren do
if menuChildren[i].Name == "ChoiceButton" then
menuChildren[i].TextColor3 = Color3.new(1,1,1)
menuChildren[i].BackgroundTransparency = 1
end
end
playerContextMenu.Visible = false
inContextMenu = false
end)
playerContextMenu.MouseEnter:connect(function()
inContextMenu = true
end)
for i = 1, #elementNames do
local newElementButton = Instance.new("TextButton")
newElementButton.Name = "ChoiceButton"
newElementButton.Text = elementNames[i]
newElementButton.TextColor3 = Color3.new(1,1,1)
newElementButton.Font = Enum.Font.Arial
newElementButton.FontSize = Enum.FontSize.Size14
newElementButton.BackgroundTransparency = 1
newElementButton.TextWrap = true
newElementButton.Size = UDim2.new(1,0,0,elementHeight)
newElementButton.Position = UDim2.new(0,0,0,elementHeight * (i - 1))
newElementButton.ZIndex = playerContextMenu.ZIndex + 1
newElementButton.MouseEnter:connect(function()
newElementButton.TextColor3 = Color3.new(0,0,0)
newElementButton.BackgroundTransparency = 0
end)
newElementButton.MouseLeave:connect(function()
newElementButton.TextColor3 = Color3.new(1,1,1)
newElementButton.BackgroundTransparency = 1
end)
newElementButton.MouseButton1Click:connect(function()
local element = elementNameToElement[newElementButton.Text]
pcall(function() element.DoIt(currentContextMenuPlayer) end)
playerContextMenu.Visible = false
newElementButton.TextColor3 = Color3.new(1,1,1)
newElementButton.BackgroundTransparency = 1
end)
newElementButton.Parent = playerContextMenu
end
robloxLock(playerContextMenu)
playerContextMenu.Parent = script.Parent
end
local visibleElements = 0
for i, contextElement in ipairs(contextMenuElements) do
local isVisible = false
if contextElement.IsVisible then
local success, visible = pcall(function() return contextElement.IsVisible(currentContextMenuPlayer) end)
if success then
isVisible = visible
else
print("Error in IsVisible call: " .. visible)
end
end
if isVisible then
local foundElement = false
for i = 1, #elementNames do
if elementNames[i] == contextElement.Text then
foundElement = true
break
end
end
if not foundElement then
table.insert(elementNames,contextElement.Text)
end
visibleElements = visibleElements + 1
else
for i = 1, #elementNames do
if elementNames[i] == contextElement.Text then
table.remove(elementNames,i)
break
end
end
end
end
playerContextMenu.Size = UDim2.new(0, 150, 0, elementHeight + (elementHeight * visibleElements) )
if x and y then
x = x - (playerContextMenu.AbsoluteSize.X/2)
if x + playerContextMenu.AbsoluteSize.X >= script.Parent.AbsoluteSize.X then
x = script.Parent.AbsoluteSize.X - playerContextMenu.AbsoluteSize.X
end
playerContextMenu.Position = UDim2.new(0, x, 0, y - 3)
end
local elementPos = 0
local contextChildren = playerContextMenu:GetChildren()
for i = 1, #contextChildren do
if contextChildren[i]:IsA("GuiObject") and contextChildren[i].Name == "ChoiceButton" then
contextChildren[i].Visible = false
for j = 1, #elementNames do
if elementNames[j] == contextChildren[i].Text then
contextChildren[i].Visible = true
contextChildren[i].Position = UDim2.new(0,0,0,elementPos * elementHeight)
elementPos = elementPos + 1
break
end
end
end
end
end
local function playerContextMenuHasItems()
if playerContextMenu then
local children = playerContextMenu:GetChildren()
for i = 1, #children do
if children[i]:IsA("GuiObject") and children[i].Name == "ChoiceButton" and children[i].Visible then
return true
end
end
end
return false
end
local function showPlayerMenu(player, x, y)
updatePlayerContextMenu(player,x,y)
if not playerContextMenuHasItems() then return end -- don't show if we have nothing to show
playerContextMenu.Visible = true
end
local function buildPlayerObject(player, numStatColumns, suffix)
if not player then return nil end
local isTeam, isScore = getBoardTypeInfo()
local playerObject = nil
local changePlayerNameFunction = nil
local currentColor = nil
if isTeam and not player.Neutral then
currentColor = player.TeamColor.Color
else
currentColor = Color3.new(1,1,1)
end
playerObject, changePlayerNameFunction = createPlayerName(player.Name, player.MembershipType, currentColor, getFriendStatus(player))
if not playerTable[player] then
playerTable[player] = {}
end
if not playerTable[player].Connections then
playerTable[player].Connections = {}
end
if not playerTable[player].CurrentTeam then
playerTable[player].CurrentTeam = nil
end
if not playerTable[player].LastTeam then
playerTable[player].LastTeam = nil
end
playerTable[player]["NameObject" .. suffix] = playerObject
playerTable[player]["ChangeName" .. suffix] = changePlayerNameFunction
if isScore then
local statObject = nil
local textChangers = nil
playerObject, statObject, textChangers = createStatColumns(playerObject, numStatColumns, false, suffix == "Big")
playerTable[player]["StatObject" .. suffix]= statObject
playerTable[player]["StatChangers" .. suffix] = textChangers
local statValues, leaderstats = getStatValuesForPlayer(player)
if not statValues or #statValues < numStatColumns then
if not playerTable[player].LeaderStatConnections then
playerTable[player].LeaderStatConnections = {}
end
--Setup a listener to see when this data gets filled in
if not leaderstats then
--We don't even have a leaderstats child, wait for one
table.insert(playerTable[player].LeaderStatConnections,
player.ChildAdded:connect(
function(child)
if child.Name == "leaderstats" then
--Connections will be torn down
recreatePlayerFunction(player)
else
table.insert(playerTable[player].LeaderStatConnections,
child.Changed:connect(
function(prop)
if prop == "Name" and child.Name == "leaderstats" then
--Connections will be torn down
recreatePlayerFunction(player)
end
end))
end
end))
else
--We have a leaderstats, but not enough children, recreate if we get them
table.insert(playerTable[player].LeaderStatConnections,
leaderstats.ChildAdded:connect(
function(child)
--TODO only look for IntValue
recreatePlayerFunction(player)
end)
)
table.insert(playerTable[player].LeaderStatConnections,
leaderstats.AncestryChanged:connect(
function(child)
--We got deleted, try again
recreatePlayerFunction(player)
end)
)
end
end
if statValues then
if not playerTable[player].StatValues then
playerTable[player].StatValues = {}
end
local pos = 1
while pos <= numStatColumns and pos <= #statValues do
local currentColumn = pos
local statValue = statValues[pos]
local statChanger = textChangers[pos]
local updateStat = function(val)
statChanger(val)
if playerTable[player] ~= nil then recomputeTeamScore(playerTable[player].CurrentTeam, currentColumn) end
end
if pos > #playerTable[player].StatValues then
table.insert(playerTable[player].StatValues, statValue)
end
if type(statValue) ~= "number" and statValue["Changed"] then
table.insert(playerTable[player].Connections,
statValue.Changed:connect(updateStat)
)
end
table.insert(playerTable[player].Connections,
statValue.AncestryChanged:connect(
function()
recreatePlayerFunction(player)
end)
)
updateStat(statValue.Value)
pos = pos + 1
end
end
end
if supportFriends and player ~= game.Players.LocalPlayer and player.userId > 0 and game.Players.LocalPlayer.userId > 0 then
local button = Instance.new("TextButton")
button.Name = playerObject.Name .. "Button"
button.Text = ""
button.Active = false
button.Size = playerObject.Size
button.Position = playerObject.Position
button.BackgroundColor3 = playerObject.BackgroundColor3
local secondButton = Instance.new("TextButton")
secondButton.Name = playerObject.Name .. "RealButton"
secondButton.Text = ""
secondButton.BackgroundTransparency = 1
secondButton.BackgroundColor3 = playerObject.BackgroundColor3
local theNameLabel = playerObject:findFirstChild("NameLabel",true)
if theNameLabel then
theNameLabel.TextColor3 = Color3.new(1,1,1)
secondButton.Parent = theNameLabel
end
secondButton.Parent.BackgroundTransparency = 1
secondButton.Parent.Visible = true
secondButton.ZIndex = 2
secondButton.Size = UDim2.new(1,0,1,0)
local previousTransparency = nil
table.insert(playerTable[player].Connections,
secondButton.MouseEnter:connect(
function(x,y)
if playerContextMenu and playerContextMenu.Visible then
return
end -- don't update if we currently see it
updatePlayerContextMenu(player,x,y)
if not playerContextMenuHasItems() then return end -- don't show if we have nothing to show
if previousTransparency == nil then
previousTransparency = secondButton.BackgroundTransparency
end
secondButton.Parent.BackgroundTransparency = 0
end))
table.insert(playerTable[player].Connections,
secondButton.MouseLeave:connect(
function()
if previousTransparency ~= nil then
previousTransparency = nil
end
delay(0.01,function()
if playerContextMenu and not inContextMenu then
playerContextMenu.Visible = false
end
end)
secondButton.Parent.BackgroundTransparency = 1
end))
local mouseDownX, mouseDownY
table.insert(playerTable[player].Connections,
secondButton.MouseButton1Down:connect(function(x,y)
mouseDownX = x
mouseDownY = y
end))
table.insert(playerTable[player].Connections,
secondButton.MouseButton1Click:connect(function()
showPlayerMenu(player, mouseDownX, secondButton.AbsolutePosition.Y + secondButton.AbsoluteSize.Y )
end))
playerObject.BackgroundTransparency = 1
playerObject.Size = UDim2.new(1,0,1,0)
playerObject.Position = UDim2.new(0,0,0,0)
playerObject.Parent = button
playerTable[player]["MainObject" .. suffix] = button
playerObject = button
else
playerTable[player]["MainObject" .. suffix] = playerObject
if player == game.Players.LocalPlayer and supportFriends then
table.insert(playerTable[player].Connections,
player.FriendStatusChanged:connect(
function(otherPlayer, friendStatus)
if friendRequestBlacklist[otherPlayer] then
updatePlayerFriendStatus(playerTable[otherPlayer]["NameObject" .. suffix], Enum.FriendStatus.NotFriend)
elseif playerTable[otherPlayer] then
updatePlayerFriendStatus(playerTable[otherPlayer]["NameObject" .. suffix], friendStatus)
end
end)
)
end
end
table.insert(playerTable[player].Connections,
player.Changed:connect(
function(prop)
if prop == "MembershipType" then
updatePlayerName(playerTable[player]["NameObject" .. suffix], player.MembershipType, currentColor)
elseif prop == "Name" then
playerTable[player]["ChangeName" .. suffix](player.Name)
elseif prop == "Neutral" or prop == "TeamColor" then
assignToTeam(player)
end
end)
)
return playerObject
end
local function doSort(tableToSort, objectName, order, startPos, sortType, ascending)
local orderedPlayerTable = {}
getLocalPlayer = false
for i, player in ipairs(tableToSort) do
if playerTable[player] then
if playerTable[player][objectName] ~= nil then
if player ~= game.Players.LocalPlayer then
table.insert(orderedPlayerTable,playerTable[player][objectName])
else
getLocalPlayer = true
end
end
end
end
if sortType == nil then -- default back to alphabetical sort
table.sort(orderedPlayerTable,function(a,b)
return string.lower(a:FindFirstChild("FullNameLabel",true).Text) < string.lower(b:FindFirstChild("FullNameLabel",true).Text)
end)
else -- we are sorting by a value
table.sort(orderedPlayerTable,function(a,b)
if ascending then
currentSortName = ""
return tonumber(a:FindFirstChild(sortType,true).Text) > tonumber(b:FindFirstChild(sortType,true).Text)
else
currentSortName = sortType
return tonumber(a:FindFirstChild(sortType,true).Text) < tonumber(b:FindFirstChild(sortType,true).Text)
end
end)
end
if getLocalPlayer and playerTable[game.Players.LocalPlayer] and playerTable[game.Players.LocalPlayer][objectName] then
table.insert(orderedPlayerTable,1,playerTable[game.Players.LocalPlayer][objectName])
end
for i = 1, #orderedPlayerTable do
order[orderedPlayerTable[i]] = startPos
startPos = startPos + 1
end
return startPos
end
local function orderScrollList(scrollOrder, objectName, scrollFrame, sortType, ascending)
local pos = 0
local order = {}
local isTeam, isScore = getBoardTypeInfo()
for i, obj in ipairs(scrollOrder) do
order[obj] = 0
end
if isTeam then
local teams = getTeams()
for i, team in ipairs(teams) do
if teamTable[team][objectName] then
order[teamTable[team][objectName]] = pos
pos = pos + 1
end
pos = doSort(teamTable[team].Players, objectName, order, pos, sortType, ascending)
end
if #teamTable["Neutral"].Players > 0 then
teamTable["Neutral"][objectName].Parent = scrollFrame
order[teamTable["Neutral"][objectName]] = pos
pos = pos + 1
doSort(teamTable["Neutral"].Players, objectName, order, pos, sortType, ascending)
else
teamTable["Neutral"][objectName].Parent = nil
end
else
local players = getPlayers()
doSort(players, objectName, order, pos, sortType, ascending)
end
table.sort(scrollOrder,
function(a,b)
return order[a] < order[b]
end)
end
local function createPlayerListBasics(frame, isBig)
local headerFrame = Instance.new("Frame")
headerFrame.Name = "Header"
headerFrame.BackgroundTransparency = 1
headerFrame.Size = UDim2.new(1,-13,0,26)
headerFrame.Position = UDim2.new(0,0,0,0)
headerFrame.Parent = frame
local lowerPaneFrame = Instance.new("Frame")
lowerPaneFrame.Name = "ScrollingArea"
lowerPaneFrame.BackgroundTransparency = 1
lowerPaneFrame.Size = UDim2.new(1,-3,1,-26)
if not isBig then lowerPaneFrame.Size = UDim2.new(1,-3,1,-30) end
lowerPaneFrame.Position = UDim2.new(0,0,0,26)
lowerPaneFrame.Parent = frame
local scrollOrder = {}
local scrollFrame, scrollUp, scrollDown, recalculateScroll, scrollBar = RbxGui.CreateScrollingFrame(scrollOrder)
scrollBar.Size = UDim2.new(0, 17, 1, -36)
if isBig then scrollBar.Size = UDim2.new(0, 17, 1, -61) end
scrollBar.Parent = lowerPaneFrame
scrollFrame.Parent = lowerPaneFrame
scrollUp.Parent = lowerPaneFrame
scrollDown.Parent = lowerPaneFrame
if isBig then
scrollFrame.Position = UDim2.new(0,0,0,0)
scrollUp.Position = UDim2.new(1,-41,0,5)
scrollDown.Position = UDim2.new(1,-41,1,-35)
scrollBar.Position = UDim2.new(1, -41, 0, 24)
scrollFrame.Size = UDim2.new(1,-48,1,-16)
headerFrame.Size = UDim2.new(1,-20,0,26)
else
scrollBar.Position = UDim2.new(1, -15, 0, 14)
scrollBar.Size = UDim2.new(0,17,1,-36)
scrollFrame.Position = UDim2.new(0,1,0,0)
scrollUp.Position = UDim2.new(1,-15,0,-5)
scrollDown.Position = UDim2.new(1,-15,1,-20)
lowerPaneFrame.Position = UDim2.new(0,0,0,30)
local toggleScrollBar = function(visible)
if visible then
scrollFrame.Size = UDim2.new(1,-16,1,0)
headerFrame.Size = UDim2.new(1,-16,0,smallWindowHeaderYSize)
else
scrollFrame.Size = UDim2.new(1,0,1,0)
headerFrame.Size = UDim2.new(1,0,0,smallWindowHeaderYSize)
end
scrollUp.Visible = visible
scrollDown.Visible = visible
scrollBar.Visible = visible
end
scrollUp.Changed:connect(function(prop)
if prop == "Active" then
toggleScrollBar(scrollUp.Active or scrollDown.Active)
end
end)
scrollDown.Changed:connect(function(prop)
if prop == "Active" then
toggleScrollBar(scrollUp.Active or scrollDown.Active)
end
end)
toggleScrollBar(scrollUp.Active or scrollDown.Active)
end
return headerFrame, scrollFrame, recalculateScroll, scrollOrder
end
createBoardsFunction = function (boardType, numStatColumns)
local updatePlayerCount = function()
return #getPlayers()
end
local smallFrame = Instance.new("Frame")
smallFrame.Name = "SmallPlayerlist"
smallFrame.Position = smallWindowPosition
smallFrame.Active = false
smallFrame.Size = smallWindowSize
smallFrame.BackgroundColor3 = Color3.new(0,0,0)
smallFrame.BackgroundTransparency = 0.7
smallFrame.BorderSizePixel = 0
local bigFrame = Instance.new("Frame")
bigFrame.Name = "BigPlayerlist"
bigFrame.Size = bigWindowSize
bigFrame.Position = bigWindowPosition
bigFrame.BackgroundColor3 = Color3.new(0,0,0)
bigFrame.BackgroundTransparency = 0.7
bigFrame.BorderSizePixel = 0
bigFrame.Visible = false
local bigFrameWrapper = Instance.new("Frame")
bigFrameWrapper.Name = "Expander"
bigFrameWrapper.Size = UDim2.new(1,21,1,16)
bigFrameWrapper.Position = UDim2.new(0, 0, 0,0)
bigFrameWrapper.BackgroundTransparency = 1
bigFrameWrapper.Parent = bigFrame
local smallHeaderFrame, scrollFrameSmall, recalculateScrollSmall, scrollOrderSmall = createPlayerListBasics(smallFrame, false)
local bigHeaderFrame, scrollFrameBig, recalculateScrollBig, scrollOrderBig = createPlayerListBasics(bigFrameWrapper, true)
local playerListButton = Instance.new("ImageButton")
playerListButton.Name = "GoBigButton"
playerListButton.BackgroundTransparency = 1
playerListButton.Image = "rbxasset://textures/ui/playerlist_small_maximize.png"
playerListButton.Size = UDim2.new(0.0, 35, 0, 29)
playerListButton.Position = UDim2.new(0, 0, 0, 0)
playerListButton.MouseButton1Click:connect(
function()
toggleBigWindow()
end)
playerListButton.Parent = smallHeaderFrame
playerListButton = Instance.new("ImageButton")
playerListButton.Name = "CloseButton"
playerListButton.BackgroundTransparency = 1
playerListButton.Image = "rbxasset://textures/ui/playerlist_small_hide.png"
playerListButton.Size = UDim2.new(0.0, 38, 0, 29)
playerListButton.Position = UDim2.new(0, 35, 0, 0)
playerListButton.MouseButton1Click:connect(
function()
transitionWindowsFunction("None")
end)
playerListButton.Parent = smallHeaderFrame
playerListButton = Instance.new("ImageButton")
playerListButton.Name = "CloseButton"
playerListButton.Image = "rbxasset://textures/ui/playerlist_big_hide.png"
playerListButton.BackgroundTransparency = 1
playerListButton.Size = UDim2.new(0.0, 29, 0, 29)
playerListButton.Position = UDim2.new(1, -30, 0.5, -13)
playerListButton.MouseButton1Click:connect(
function()
toggleBigWindow()
end)
playerListButton.Parent = bigHeaderFrame
local placeName = Instance.new("TextButton")
placeName.Name = "PlaceName"
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
placeName.AutoButtonColor = false
placeName.FontSize = Enum.FontSize.Size24
placeName.TextXAlignment = Enum.TextXAlignment.Left
placeName.Font = Enum.Font.ArialBold
placeName.BorderSizePixel = 0
placeName.BackgroundColor3 = Color3.new(0,0,0)
placeName.BackgroundTransparency = 1
placeName.TextColor3 = Color3.new(1,1,1)
placeName.Size = UDim2.new(0.4, 0, 1, 0)
placeName.Position = UDim2.new(0, 0, 0.0, 0)
placeName = RbxGui.AutoTruncateTextObject(placeName)
placeName.Parent = bigHeaderFrame
placeName.MouseEnter:connect(function()
placeName.BackgroundTransparency = 0.2
end)
placeName.MouseLeave:connect(function()
placeName.BackgroundTransparency = 1
end)
placeName.MouseButton1Click:connect(function()
sortPlayerListsFunction()
end)
currentBoardType = boardType
currentStatCount = numStatColumns
local isTeam, isScore = getBoardTypeInfo()
local players = getPlayers()
if isScore then
local statColumns = getStatColumns(players)
numStatColumns = #statColumns
if numStatColumns > 3 then
numStatColumns = 3
end
createStatHeaders(statColumns, numStatColumns, false).Parent = smallHeaderFrame
createStatHeaders(statColumns, currentStatCount, true).Parent = bigHeaderFrame
end
--Clean up all old stuff
resetPlayerTable()
updatePlayerCount()
for i, player in ipairs(players) do
local playerObject = buildPlayerObject(player, numStatColumns, "Small")
table.insert(scrollOrderSmall, playerObject)
playerObject.Parent = scrollFrameSmall
playerObject = buildPlayerObject(player, currentStatCount, "Big")
table.insert(scrollOrderBig, playerObject)
playerObject.Parent = scrollFrameBig
end
--Clean up old stuff
resetTeamTable()
local teamStatObjects = {}
if isTeam then
local teams = getTeams()
local i = #teams
while i >= 1 do
--We go backwards so the "first" team color gets the team
local team = teams[i]
teamColorTable[team.TeamColor.Name] = team
i = i - 1
end
--Adding/Removing a Team causes a full invalidation of the board
for i, team in ipairs(teams) do
local teamObject = buildTeamObject(team, numStatColumns, "Small")
table.insert(scrollOrderSmall, teamObject)
teamObject.Parent = scrollFrameSmall
teamObject = buildTeamObject(team, currentStatCount, "Big")
table.insert(scrollOrderBig, teamObject)
teamObject.Parent = scrollFrameBig
end
teamTable["Neutral"] = {}
teamTable["Neutral"].Players = {}
local neutralTeamObject = createTeamName("Neutral", BrickColor.palette(8))
teamTable["Neutral"].NameObjectSmall = neutralTeamObject
teamTable["Neutral"].StatObjectSmall = nil
teamTable["Neutral"].MainObjectSmall = neutralTeamObject
table.insert(scrollOrderSmall, neutralTeamObject)
neutralTeamObject = createTeamName("Neutral", BrickColor.palette(8))
teamTable["Neutral"].NameObjectBig = neutralTeamObject
teamTable["Neutral"].StatObjectBig = nil
teamTable["Neutral"].MainObjectBig = neutralTeamObject
table.insert(scrollOrderBig, neutralTeamObject)
local neutralPlayers = {}
for i, player in ipairs(players) do
assignToTeam(player)
end
end
removePlayerFunction = function(player)
if playerTable[player] then
clearTableEntry(player, playerTable[player])
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
ArrayRemove(scrollOrderSmall, playerTable[player].MainObjectSmall)
ArrayRemove(scrollOrderBig, playerTable[player].MainObjectBig)
playerTable[player] = nil
recalculateSmallPlayerListSize(smallFrame)
end
end
recreatePlayerFunction = function(player)
placeName.Text = " Players (" .. tostring(updatePlayerCount()) .. ")"
removePlayerFunction(player)
local playerObject = buildPlayerObject(player, numStatColumns, "Small")
table.insert(scrollOrderSmall, playerObject)
robloxLock(playerObject)
playerObject.Parent = scrollFrameSmall
playerObject = buildPlayerObject(player, currentStatCount, "Big")
table.insert(scrollOrderBig, playerObject)
robloxLock(playerObject)
playerObject.Parent = scrollFrameBig
local isTeam, isScore = getBoardTypeInfo()
if isTeam then
assignToTeam(player)
end
sortPlayerListsFunction()
recalculateSmallPlayerListSize(smallFrame)
end
if screenResizeCon then screenResizeCon:disconnect() end
screenResizeCon = screen.Changed:connect(
function(prop)
if prop == "AbsoluteSize" then
wait()
recalculateSmallPlayerListSize(smallFrame)
end
end)
sortPlayerListsFunction = function(sortType, ascending)
orderScrollList(scrollOrderSmall, "MainObjectSmall", scrollFrameSmall, sortType, ascending)
recalculateScrollSmall()
createAlternatingRows(scrollOrderSmall)
orderScrollList(scrollOrderBig, "MainObjectBig", scrollFrameBig, sortType, ascending)
recalculateScrollBig()
createAlternatingRows(scrollOrderBig)
end
sortPlayerListsFunction()
robloxLock(smallFrame)
robloxLock(bigFrame)
return smallFrame, bigFrame
end
--Teams changing invalidates the whole board
local function teamsChanged()
if debounceTeamsChanged then
return
end
debounceTeamsChanged = true
wait()
rebuildBoard(script.Parent, determineBoardType())
debounceTeamsChanged = false
end
local checkIfBoardChanged = function()
local newBoardType, numStats = determineBoardType()
if newBoardType ~= currentBoardType or numStats ~= currentStatCount then
rebuildBoard(script.Parent, newBoardType, numStats)
end
end
local function buildPlayerList()
waitForChild(game, "Players")
waitForProperty(game.Players, "LocalPlayer")
local teams = game:GetService("Teams")
if teams then
local teamConnections = {}
teams.ChildAdded:connect(
function(child)
if child:IsA("Team") then
teamsChanged()
teamConnections[child] = child.Changed:connect(
function(prop)
if prop == "TeamColor" or prop == "Name" then
--Rebuild when things change
teamsChanged()
end
end)
end
end)
teams.ChildRemoved:connect(
function(child)
if child:IsA("Team") then
if teamConnections[child] then
teamConnections[child]:disconnect()
teamConnections[child] = nil
end
teamsChanged()
end
end)
end
game.Players.ChildAdded:connect(
function(player)
if player:IsA("Player") then
addPlayerFunction(player)
end
end)
game.Players.ChildRemoved:connect(
function(player)
if player:IsA("Player") then
if removePlayerFunction then
removePlayerFunction(player)
end
end
end)
rebuildBoard(script.Parent, determineBoardType())
game.GuiService.ShowLegacyPlayerList = false
game.GuiService:AddKey("\t")
local lastTime = nil
game.GuiService.KeyPressed:connect(
function(key)
if key == "\t" then
local modalCheck, isModal = pcall(function() return game.GuiService.IsModalDialog end)
if modalCheck == false or (modalCheck and isModal == false) then
local currentTime = time()
if lastTime == nil or currentTime - lastTime > 0.4 then
lastTime = currentTime
toggleBigWindow()
end
end
end
end)
delay(0,
function()
while true do
wait(5)
checkIfBoardChanged()
end
end)
end
if game.CoreGui.Version >= 2 then
buildPlayerList()
end
end
if not personalServerPlace then -- one more backup check
local theBool = game.Workspace:FindFirstChild("PSVariable")
if theBool and theBool:IsA("BoolValue") then
personalServerPlace = true
end
end
if personalServerPlace then
addPersonalServerContext()
setupBuildToolManagement()
else
local psVarCon = nil
psVarCon = game.Workspace.ChildAdded:connect(function(child)
if child:IsA("BoolValue") and child.Name == "PSVariable" then
psVarCon:disconnect()
personalServerPlace = true
addPersonalServerContext()
setupBuildToolManagement()
end
end)
end
---------------------------------- Start Player Hover Code ----------------------------------------
if contextMenu3d then
local inMenu = false
function waitForProperty(instance, name)
while not instance[name] do
instance.Changed:wait()
end
end
function makeNewActionButton()
local button = Instance.new("TextButton")
button.Name = "ActionButton"
button.Style = Enum.ButtonStyle.RobloxButtonDefault
button.BackgroundColor3 = Color3.new(0,0,0)
button.BorderColor3 = Color3.new(1,0,0)
button.BackgroundTransparency = 0.5
button.Size = UDim2.new(1,0,0,50)
button.Text = ""
button.Font = Enum.Font.ArialBold
button.FontSize = Enum.FontSize.Size18
button.TextColor3 = Color3.new(1,1,1)
button.ZIndex = 4
return button
end
function getContextElements(currentContextMenuPlayer)
local elements = {}
for i, contextElement in ipairs(contextMenuElements) do
local element = contextElement
local isVisible = false
if contextElement.IsVisible then
local success, visible = pcall(function() return contextElement.IsVisible(currentContextMenuPlayer) end)
if success then
isVisible = visible
else
print("Error in IsVisible call: " .. visible)
end
end
if element.Type == "Button" then
local button = makeNewActionButton()
button.Name = "ContextButton" .. i
button.Visible = isVisible
button.Text = contextElement.Text
button.MouseButton1Click:connect(function()
if button.Active then
local success, result = pcall(function() element.DoIt(currentContextMenuPlayer) end)
end
end)
contextElement.Button = button
contextElement.Element = button
table.insert(elements,contextElement)
end
end
return elements
end
function findContextElement(contextElements, button)
for i = 1, #contextElements do
if contextElements[i].Button == button then
return contextElements[i]
end
end
end
function populateActions(scrollFrame, nullFrame, recalcFunction, otherPlayer)
local elements = getContextElements(otherPlayer)
for i = 1, #elements do
if elements[i].Button.Visible then
elements[i].Button.Parent = scrollFrame
else
elements[i].Button.Parent = nullFrame
end
local actionButtonCon
actionButtonCon = elements[i].Button.MouseButton1Click:connect(function()
actionButtonCon:disconnect()
local nullFrameChildren = nullFrame:GetChildren()
for j = 1, #nullFrameChildren do
local contextElement = findContextElement(elements, nullFrameChildren[j])
pcall(function() nullFrameChildren[j].Visible = contextElement.IsVisible(otherPlayer) end)
if nullFrameChildren[j].Visible then
nullFrameChildren[j].Parent = scrollFrame
end
end
local scrollFrameChildren = scrollFrame:GetChildren()
for j = 1, #scrollFrameChildren do
local contextElement = findContextElement(elements, scrollFrameChildren[j])
pcall(function() scrollFrameChildren[j].Visible = contextElement.IsVisible(otherPlayer) end)
if not scrollFrameChildren[j].Visible then
scrollFrameChildren[j].Parent = nullFrame
end
end
elements[i].Button.Parent = nullFrame
recalcFunction()
end)
end
end
function createContextMenu(otherPlayer)
local frame = Instance.new("Frame")
frame.Name = "ContextMenuFrame"
frame.Style = Enum.FrameStyle.RobloxRound
frame.Size = UDim2.new(0,300,0,400)
frame.Position = UDim2.new(0.5,-150,0.5,-200)
frame.ZIndex = 2
local scrollFrame, scrollUpButton, scrollDownButton, recalc, scrollBar = RbxGui.CreateScrollingFrame()
scrollFrame.Name = "Actions"
scrollFrame.BackgroundTransparency = 1
scrollFrame.Position = UDim2.new(0,0,0,25)
scrollFrame.Size = UDim2.new(1,-20,1,-80)
scrollFrame.ZIndex = 3
scrollFrame.Parent = frame
local nullFrame = Instance.new("Frame")
nullFrame.Name = "NullFrame"
nullFrame.BackgroundTransparency = 1
nullFrame.Visible = false
nullFrame.Parent = frame
local scrollButtons = Instance.new("Frame")
scrollButtons.Name = "ScrollButtons"
scrollButtons.BackgroundTransparency = 1
scrollButtons.Position = UDim2.new(1,-17,0,25)
scrollButtons.Size = UDim2.new(0,17,1,-80)
scrollButtons.ZIndex = 3
scrollButtons.Parent = frame
scrollUpButton.ZIndex = 3
scrollUpButton.Parent = scrollButtons
scrollDownButton.Position = UDim2.new(0,0,1,-17)
scrollDownButton.ZIndex = 3
scrollDownButton.Parent = scrollButtons
scrollBar.Size = UDim2.new(1,0,1,-34)
scrollBar.Position = UDim2.new(0,0,0,17)
scrollBar.Parent = scrollButtons
local playerImage = Instance.new("ImageLabel")
playerImage.Name = "PlayerImage"
playerImage.BackgroundTransparency = 1
playerImage.Image = "http://www.roblox.com/thumbs/avatar.ashx?userId=" .. tostring(otherPlayer.userId) .. "&x=352&y=352"
playerImage.Position = UDim2.new(0.5,-150,0.5,-150)
playerImage.Size = UDim2.new(0,300,0,300)
playerImage.Parent = frame
local playerName = Instance.new("TextLabel")
playerName.Name = "PlayerName"
playerName.BackgroundTransparency = 1
playerName.Font = Enum.Font.ArialBold
playerName.FontSize = Enum.FontSize.Size24
playerName.Position = UDim2.new(0,-8,0,-6)
playerName.Size = UDim2.new(1,16,0,24)
playerName.Text = otherPlayer["Name"]
playerName.TextColor3 = Color3.new(1,1,1)
playerName.TextWrap = true
playerName.ZIndex = 3
playerName.Parent = frame
local doneButtonCon
local doneButton = Instance.new("TextButton")
doneButton.Name = "DoneButton"
doneButton.Style = Enum.ButtonStyle.RobloxButton
doneButton.Font = Enum.Font.ArialBold
doneButton.FontSize = Enum.FontSize.Size36
doneButton.Position = UDim2.new(0.25,0,1,-50)
doneButton.Size = UDim2.new(0.5,0,0,50)
doneButton.Text = "Done"
doneButton.TextColor3 = Color3.new(1,1,1)
doneButton.ZIndex = 3
doneButton.Parent = frame
doneButton.Modal = true
doneButtonCon = doneButton.MouseButton1Click:connect(function()
doneButtonCon:disconnect()
inMenu = false
game.GuiService:RemoveCenterDialog(frame)
frame:remove()
end)
populateActions(scrollFrame, nullFrame, recalc, otherPlayer)
recalc()
return frame
end
function makeContextInvisible(menu)
menu.Visible = false
end
function goToContextMenu(otherPlayer)
local menu = createContextMenu(otherPlayer)
game.GuiService:AddCenterDialog(menu, Enum.CenterDialogType.PlayerInitiatedDialog,
--ShowFunction
function()
menu.Visible = true
menu:TweenSize(UDim2.new(0,300,0,400),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.5,true)
end,
--HideFunction
function()
menu:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.5,true,function() makeContextInvisible(menu) end)
end)
menu.Parent = game.CoreGui.RobloxGui
inMenu = true
end
waitForProperty(game.Players, "LocalPlayer")
local currSelectedPlayer = nil
if game.Players.LocalPlayer["HoverOnPlayerChanged"] then
game.Players.LocalPlayer.HoverOnPlayerChanged:connect(function(otherPlayer)
if not inMenu then
if otherPlayer and otherPlayer.userId < 0 then return end -- we don't want this for guests
end
wait(0.5)
currSelectedPlayer = otherPlayer
end)
end
if game.Players.LocalPlayer["MouseDownOnPlayer"] then
game.Players.LocalPlayer.MouseDownOnPlayer:connect(function(otherPlayer)
if currSelectedPlayer ~= otherPlayer then return end
if not inMenu and otherPlayer.userId > 0 then
goToContextMenu(otherPlayer)
end
end)
end
end
---------------------------------- End Player Hover Code ----------------------------------------