Super-Nostalgia-Zone/UI/PlayerList/PlayerList.client.lua

666 lines
16 KiB
Lua

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Teams = game:GetService("Teams")
spawn(function ()
local StarterGui = game:GetService("StarterGui")
StarterGui:SetCoreGuiEnabled("PlayerList", false)
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
playerGui:SetTopbarTransparency(1)
end)
--------------------------------------------------------------------------------------------------------------------------------------
-- Setup
--------------------------------------------------------------------------------------------------------------------------------------
local playerStates = {}
local teamGroups = {}
local statLookup = {}
local statNames = {}
local inTeamMode = false
local playerList = script.Parent
local templates = playerList:WaitForChild("Templates")
local basePlayerLbl = templates:WaitForChild("BasePlayerLbl")
local baseGroup = templates:WaitForChild("BaseGroup")
local baseStat = templates:WaitForChild("BaseStat")
local backdrop = playerList:WaitForChild("Backdrop")
local container = playerList:WaitForChild("Container")
local coreGroup = baseGroup:Clone()
coreGroup.Name = "Default"
coreGroup.Parent = container
local coreFooter = coreGroup.Footer
local coreHeader = coreGroup.Header
local eUpdateStatLayout = Instance.new("BindableEvent")
local updateStatLayout = eUpdateStatLayout.Event
local eUpdateTeamTotal = Instance.new("BindableEvent")
local updateTeamTotal = eUpdateTeamTotal.Event
local ePlayerTeamChanged = Instance.new("BindableEvent")
local playerTeamChanged = ePlayerTeamChanged.Event
--------------------------------------------------------------------------------------------------------------------------------------
-- Player Colors
--------------------------------------------------------------------------------------------------------------------------------------
local PLAYER_COLORS =
{
[0] = Color3.fromRGB(173, 35, 35); -- red
[1] = Color3.fromRGB( 42, 75, 215); -- blue
[2] = Color3.fromRGB( 29, 105, 20); -- green
[3] = Color3.fromRGB(129, 38, 192); -- purple
[4] = Color3.fromRGB(255, 146, 51); -- orange
[5] = Color3.fromRGB(255, 238, 51); -- yellow
[6] = Color3.fromRGB(255, 205, 243); -- pink
[7] = Color3.fromRGB(233, 222, 187); -- tan
}
local function computePlayerColor(player)
local pName = player.Name
local length = #pName
local oddShift = (1 - (length % 2))
local value = 0
for i = 1,length do
local char = pName:sub(i,i):byte()
local rev = (length - i) + oddShift
if (rev % 4) >= 2 then
value = value - char
else
value = value + char
end
end
return PLAYER_COLORS[value % 8]
end
--------------------------------------------------------------------------------------------------------------------------------------
-- Backdrop Handler
--------------------------------------------------------------------------------------------------------------------------------------
local isTeamMode = false
local hasStats = false
local size1x1 = Vector2.new(1,1)
local rawGroups = {}
local function onContainerChildAdded(child)
if child:IsA("Frame") then
local listLayout = child:WaitForChild("ListLayout",2)
if listLayout then
rawGroups[child] = listLayout
end
end
end
local function onContainerChildRemoved(child)
if rawGroups[child] then
rawGroups[child] = nil
end
end
local function sortGroups(a,b)
if a == coreGroup then
return true
elseif b == coreGroup then
return false
else
local orderA,orderB = a.LayoutOrder,b.LayoutOrder
if orderA == orderB then
return a.Name < b.Name
else
return orderA < orderB
end
end
end
local function updateBackdrop()
local groups = {}
local at = 1
for group in pairs(rawGroups) do
if group.Visible then
groups[at] = group
at = at + 1
end
end
local height = 0
table.sort(groups,sortGroups)
for i = 1,#groups do
local group = groups[i]
local layout = rawGroups[group]
group.Position = UDim2.new(0,0,0,height)
height = height + layout.AbsoluteContentSize.Y
end
if #statNames > 0 and not hasStats then
hasStats = true
container.AnchorPoint = Vector2.new(1,0)
for _,group in pairs(groups) do
group.Header.TeamUnderline.Size = UDim2.new(2,-4,0,1)
end
eUpdateStatLayout:Fire()
elseif #statNames == 0 and hasStats then
hasStats = false
container.AnchorPoint = Vector2.new(0,0)
for _,group in pairs(groups) do
group.Header.TeamUnderline.Size = UDim2.new(1,-4,0,1)
end
eUpdateStatLayout:Fire()
end
if isTeamMode then
height = height + coreHeader.AbsoluteSize.Y
end
local width = container.AbsoluteSize.X * (container.AnchorPoint.X+1)
backdrop.Size = UDim2.new(0,width,0,height)
end
for _,child in pairs(container:GetChildren()) do
onContainerChildAdded(child)
end
container.ChildAdded:Connect(onContainerChildAdded)
container.ChildRemoved:Connect(onContainerChildRemoved)
RunService.Heartbeat:Connect(updateBackdrop)
--------------------------------------------------------------------------------------------------------------------------------------
-- Header Size Stuff
--------------------------------------------------------------------------------------------------------------------------------------
local function switchHeaderMode(isTeamMode)
if isTeamMode then
coreHeader.Size = UDim2.new(1,0,1/3,0)
coreHeader.Stats.Size = UDim2.new(0.75,0,1,0)
coreHeader.Title.Size = UDim2.new(1,0,1,0)
else
coreHeader.Size = UDim2.new(1,0,0.4,0)
coreHeader.Stats.Size = UDim2.new(0.75,0,0.85,0)
coreHeader.Title.Size = UDim2.new(1,0,0.85,0)
end
end
switchHeaderMode(false)
--------------------------------------------------------------------------------------------------------------------------------------
-- Player Stats
--------------------------------------------------------------------------------------------------------------------------------------
local function incrementStat(statName)
if not statLookup[statName] then
statLookup[statName] = 1
table.insert(statNames,statName)
else
statLookup[statName] = statLookup[statName] + 1
end
eUpdateStatLayout:Fire()
end
local function decrementStat(statName)
if statLookup[statName] then
statLookup[statName] = statLookup[statName] - 1
if statLookup[statName] == 0 then
statLookup[statName] = nil
for i,name in ipairs(statNames) do
if name == statName then
table.remove(statNames,i)
break
end
end
end
eUpdateStatLayout:Fire()
end
end
local function getPlayerStateFromStat(stat)
local leaderstats = stat.Parent
if leaderstats then
local player = leaderstats.Parent
if player then
return playerStates[player]
end
end
end
local function refreshTeamStats()
for _,team in pairs(Teams:GetTeams()) do
eUpdateTeamTotal:Fire(team)
end
end
local function onStatRemoved(stat,statName)
if stat.ClassName == "IntValue" then
local statName = statName or stat.Name
local playerState = getPlayerStateFromStat(stat)
if playerState and playerState.Stats[statName] then
playerState.Stats[statName]:Destroy()
playerState.Stats[statName] = nil
end
decrementStat(statName)
refreshTeamStats()
end
end
local function onStatAdded(stat)
if stat.ClassName == "IntValue" then
local statName = stat.Name
local playerState = getPlayerStateFromStat(stat)
if playerState then
local changeSignal
if not playerState.Stats[statName] then
local statLbl = baseStat:Clone()
statLbl.Name = statName
local function updateStat()
statLbl.Text = stat.Value
if isTeamMode then
local team = playerState.Player.Team
if team then
eUpdateTeamTotal:Fire(team)
end
end
end
updateStat()
changeSignal = stat.Changed:Connect(updateStat)
statLbl.Parent = playerState.Label.Stats
playerState.Stats[statName] = statLbl
end
local nameSignal do
local function onNameChanged()
if changeSignal then
changeSignal:Disconnect()
changeSignal = nil
end
nameSignal:Disconnect()
nameSignal = nil
-- Rebuild the stat
onStatRemoved(stat,statName)
onStatAdded(stat)
end
nameSignal = stat:GetPropertyChangedSignal("Name"):Connect(onNameChanged)
end
end
incrementStat(statName)
refreshTeamStats()
end
end
local function onPlayerChildAdded(leaderstats)
if leaderstats.Name == "leaderstats" then
local player = leaderstats.Parent
local playerState = playerStates[player]
if playerState and not playerState.leaderstats then
playerState.leaderstats = leaderstats
for _,stat in pairs(leaderstats:GetChildren()) do
onStatAdded(stat)
end
leaderstats.ChildAdded:Connect(onStatAdded)
leaderstats.ChildRemoved:Connect(onStatRemoved)
end
end
end
local function onPlayerChildRemoved(child)
if child.Name == "leaderstats" then
for _,stat in pairs(child:GetChildren()) do
onStatRemoved(stat)
end
for player,playerState in pairs(playerStates) do
if playerState.leaderstats == child then
playerState.leaderstats = nil
break
end
end
end
end
local function updateStatLbl(statLbl,index)
statLbl.Size = UDim2.new(1/#statNames,0,1,0)
statLbl.Position = UDim2.new((index-1)/#statNames)
end
local function onUpdateStatLayout()
local statBin = coreHeader.Stats
for _,statLbl in pairs(statBin:GetChildren()) do
if statLbl:IsA("TextLabel") and not statLookup[statLbl.Name] then
statLbl:Destroy()
end
end
for i,statName in pairs(statNames) do
local statLbl = statBin:FindFirstChild(statName)
if not statLbl then
statLbl = baseStat:Clone()
statLbl.Name = statName
statLbl.Text = statName
statLbl.Parent = statBin
end
updateStatLbl(statLbl,i)
end
for player,playerState in pairs(playerStates) do
for statName,statLbl in pairs(playerState.Stats) do
if not statLookup[statName] then
statLbl:Destroy()
playerState.Stats[statName] = nil
end
end
for i,statName in pairs(statNames) do
local statLbl = playerState.Stats[statName]
if statLbl then
if player.Team then
statLbl.TextColor = player.Team.TeamColor
else
statLbl.TextColor3 = Color3.new(1,1,1)
end
updateStatLbl(statLbl,i)
end
end
end
isTeamMode = (#Teams:GetTeams() > 0)
if isTeamMode then
coreHeader.Visible = hasStats
coreHeader.Title.Text = "Team"
else
coreHeader.Visible = true
if hasStats then
coreHeader.Title.Text = "Players"
else
coreHeader.Title.Text = "Player List"
end
end
switchHeaderMode(isTeamMode)
end
updateStatLayout:Connect(onUpdateStatLayout)
--------------------------------------------------------------------------------------------------------------------------------------
-- Player States
--------------------------------------------------------------------------------------------------------------------------------------
local function onPlayerAdded(player)
local playerState = {}
local name = player.Name
local lbl = basePlayerLbl:Clone()
lbl.Name = name
lbl.PlayerName.Text = name
lbl.PlayerName.TextColor3 = computePlayerColor(player)
lbl.Parent = coreGroup
playerState.Player = player
playerState.Label = lbl
playerState.Stats = {}
playerStates[player] = playerState
for _,child in pairs(player:GetChildren()) do
onPlayerChildAdded(child)
end
player.ChildAdded:Connect(onPlayerChildAdded)
player.ChildRemoved:Connect(onPlayerChildRemoved)
player.Changed:Connect(function (property)
if property == "Team" then
ePlayerTeamChanged:Fire(player)
end
end)
ePlayerTeamChanged:Fire(player)
end
local function onPlayerRemoved(player)
local state = playerStates[player]
playerStates[player] = nil
if state and state.Label then
state.Label:Destroy()
end
end
for _,player in pairs(Players:GetPlayers()) do
onPlayerAdded(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoved)
--------------------------------------------------------------------------------------------------------------------------------------
-- Teams
--------------------------------------------------------------------------------------------------------------------------------------
local function neutralizePlayer(player)
local playerState = playerStates[player]
if playerState then
local playerLbl = playerState.Label
playerLbl.PlayerName.Text = player.Name
playerLbl.PlayerName.TextColor3 = computePlayerColor(player)
playerLbl.PlayerName.Position = UDim2.new(0, 0, 0, 0)
for stat,statLbl in pairs(playerState.Stats) do
statLbl.TextColor3 = Color3.new(1,1,1)
end
playerLbl.Visible = (not isTeamMode)
playerLbl.Parent = coreGroup
end
end
local function onPlayerAddedToTeam(player)
local team = player.Team
local group = teamGroups[team]
if group then
local playerState = playerStates[player]
if playerState then
local playerLbl = playerState.Label
playerLbl.PlayerName.TextColor = team.TeamColor
playerLbl.PlayerName.Position = UDim2.new(0, 4, 0, 0)
for stat, statLbl in pairs(playerState.Stats) do
statLbl.TextColor = team.TeamColor
end
playerLbl.Parent = group
playerLbl.Visible = true
eUpdateStatLayout:Fire()
refreshTeamStats()
end
end
end
local function onPlayerRemovedFromTeam(player)
if not player.Team then
neutralizePlayer(player)
refreshTeamStats()
end
end
local function onUpdateTeamTotal(team)
local teamGroup = teamGroups[team]
if teamGroup then
local teamStats = teamGroup.Header.Stats
local totals = {}
for i,statName in ipairs(statNames) do
local total = totals[i]
if not total then
total = { Name = statName, Value = 0 }
totals[i] = total
end
for _,player in pairs(team:GetPlayers()) do
local playerState = playerStates[player]
if playerState then
local leaderstats = playerState.leaderstats
if leaderstats then
local stat = leaderstats:FindFirstChild(statName)
if stat then
total.Value = total.Value + stat.Value
end
end
end
end
end
local numStats = #statNames
for i,statRecord in ipairs(totals) do
local statName = statRecord.Name
local statLbl = teamStats:FindFirstChild(statName)
if not statLbl then
statLbl = baseStat:Clone()
statLbl.Name = statName
statLbl.TextColor = team.TeamColor
statLbl.TextStrokeTransparency = 0.5
statLbl.Parent = teamStats
end
statLbl.Text = statRecord.Value
updateStatLbl(statLbl,i)
end
for _,statLbl in pairs(teamStats:GetChildren()) do
if not statLookup[statLbl.Name] then
statLbl:Destroy()
end
end
end
end
local function onTeamAdded(team)
if team.ClassName == "Team" then
local teamGroup = baseGroup:Clone()
teamGroup.Name = team.Name
teamGroup.Footer.Visible = true
local teamHeader = teamGroup.Header
local teamUnderline = teamHeader.TeamUnderline
teamUnderline.Visible = true
teamUnderline.BackgroundColor = team.TeamColor
if hasStats then
teamUnderline.Size = teamUnderline.Size + UDim2.new(1,0,0,0)
end
local teamTitle = teamHeader.Title
teamTitle.Text = team.Name
teamTitle.TextColor = team.TeamColor
teamTitle.TextStrokeTransparency = 0.5
teamGroup.Parent = container
teamGroups[team] = teamGroup
for _,player in pairs(team:GetPlayers()) do
onPlayerAddedToTeam(player)
end
eUpdateTeamTotal:Fire(team)
eUpdateStatLayout:Fire()
end
if #Teams:GetTeams() > 0 and not isTeamMode then
isTeamMode = true
for _,player in pairs(Players:GetPlayers()) do
if not player.Team then
neutralizePlayer(player)
end
end
end
end
local function onTeamRemoved(team)
if teamGroups[team] then
for _,player in pairs(Players:GetPlayers()) do
if player.TeamColor == team.TeamColor then
neutralizePlayer(player)
end
end
teamGroups[team]:Destroy()
teamGroups[team] = nil
eUpdateStatLayout:Fire()
end
if #Teams:GetTeams() == 0 then
isTeamMode = false
for _,player in pairs(Players:GetPlayers()) do
neutralizePlayer(player)
end
end
end
local function onPlayerTeamChange(player)
local team = player.Team
if team then
onPlayerAddedToTeam(player)
else
onPlayerRemovedFromTeam(player)
end
end
for _,team in pairs(Teams:GetTeams()) do
onTeamAdded(team)
end
for _,player in pairs(Players:GetPlayers()) do
onPlayerTeamChange(player)
end
Teams.ChildAdded:Connect(onTeamAdded)
Teams.ChildRemoved:Connect(onTeamRemoved)
updateTeamTotal:Connect(onUpdateTeamTotal)
playerTeamChanged:Connect(onPlayerTeamChange)
--------------------------------------------------------------------------------------------------------------------------------------