Help with updating player character rigs for global leaderboard

What do you want to achieve?

I want to create a global leaderboard for my game, where the top three players are shown along with their player character models dancing in a separate rig. The leaderboard should update as players progress in the game. The leaderboard are working fine, but for some reason, the character part isn’t.

What is the issue?

I have created two scripts, one for the leaderboard and another to update the player character rigs, but the rigs are not updating even though the leaderboard is changing. I have tried a few solutions, such as looking for solutions on the DevForum, but nothing seems to be working.

What solutions have you tried so far?

I have tried the following solutions:

  • Looking for solutions on the DevForum
  • Checking if the scripts are named correctly, if there’s any typos, and attached to the right objects
  • I also tried reading some docs about CreateHumanoidModelFromDescription

But none of these solutions seem to be working. Here’s the code for the script to update the rigs:

local Players = game:GetService("Players")

local plrName1 = script.Parent["#1"].Nickname.Text
local plrName2 = script.Parent["#2"].Nickname.Text
local plrName3 = script.Parent["#3"].Nickname.Text

local leaderboard = script.Parent.Parent.Parent.Parent
local top1 = leaderboard.Statues.Top1
local top2 = leaderboard.Statues.Top2
local top3 = leaderboard.Statues.Top3

local firstPlayerRig = top1.NumberOne
local secondPlayerRig = top2.NumberTwo
local thirdPlayerRig = top3.NumberThree

-- function to change the rig of a player's character
local function changeRig(player, newRig)
	local character = player.Character
	if character then
		character:Destroy()
	end
	local newCharacter = Players:CreateHumanoidModelFromDescription(newRig)
	newCharacter.Parent = player
end

while true do
	task.wait(5)

	-- get the appearance model for each player
	local player1 = Players:FindFirstChild(plrName1)
	local appearanceModel1 = player1 and Players:GetCharacterAppearanceAsync(player1.UserId)

	local player2 = Players:FindFirstChild(plrName2)
	local appearanceModel2 = player2 and Players:GetCharacterAppearanceAsync(player2.UserId)

	local player3 = Players:FindFirstChild(plrName3)
	local appearanceModel3 = player3 and Players:GetCharacterAppearanceAsync(player3.UserId)

	-- change the rig for each player
	if appearanceModel1 then
		changeRig(player1, firstPlayerRig)
	end

	if appearanceModel2 then
		changeRig(player2, secondPlayerRig)
	end

	if appearanceModel3 then
		changeRig(player3, thirdPlayerRig)
	end
end

And here’s the code for the leaderboard script:

local DataStoreService = game:GetService("DataStoreService")
local GlobalLeaderboard = DataStoreService:GetDataStore("GlobalLeaderboard")

local ScrollingFrame = script.Parent

function UpdateLeaderboard()
	local SortedPlayers = {}

	-- get all players in the game
	for _, player in ipairs(game.Players:GetPlayers()) do
		-- get the player's clicks
		local Clicks = player.leaderstats.Clicks.Value

		-- insert the player's data into the leaderboard table
		table.insert(SortedPlayers, {Player = player, Clicks = Clicks})
	end

	-- sort the leaderboard table by the player's clicks
	table.sort(SortedPlayers, function(a, b)
		return a.Clicks > b.Clicks
	end)

	-- update the leaderboard UI
	for i = 1, 10 do
		local Frame = ScrollingFrame["#" .. i]
		local NicknameLabel = Frame.Nickname

		-- clear the frame if there's no player data for that rank
		if not SortedPlayers[i] then
			NicknameLabel.Text = ""
		else
			-- Update the frame with the player's data
			local PlayerData = SortedPlayers[i]
			NicknameLabel.Text = PlayerData.Player.Name .. " - " .. PlayerData.Clicks
		end
	end
end

-- call UpdateLeaderboard every 5 seconds
while true do
	UpdateLeaderboard()
	wait(5)
end

-- save the leaderboard data to the global datastore when the game is closed
game:BindToClose(function()
	local LeaderboardData = {}

	-- build the leaderboard data table
	for i = 1, 10 do
		local Frame = ScrollingFrame["#" .. i]
		local NicknameLabel = Frame.Nickname

		if NicknameLabel.Text ~= "" then
			local PlayerName, Clicks = string.match(NicknameLabel.Text, "^(.-) %- (%d+)$")
			LeaderboardData[i] = {PlayerName = PlayerName, Clicks = tonumber(Clicks)}
		end
	end

	-- save the leaderboard data to the global datastore
	local success, err = pcall(function()
		GlobalLeaderboard:SetAsync("LeaderboardData", LeaderboardData)
	end)

	if not success then
		warn("Error saving leaderboard data: " .. err)
	end
end)

-- load the leaderboard data from the global datastore when the game starts
local success, LeaderboardData = pcall(function()
	return GlobalLeaderboard:GetAsync("LeaderboardData")
end)

if success and LeaderboardData then
	for i = 1, 10 do
		local Frame = ScrollingFrame["#" .. i]
		local NicknameLabel = Frame.Nickname

		-- update the frame with the loaded leaderboard data
		if LeaderboardData[i] then
			local PlayerData = LeaderboardData[i]
			NicknameLabel.Text = PlayerData.PlayerName .. " - " .. PlayerData.Clicks
		else
			NicknameLabel.Text = ""
		end
	end
else
	warn("Error loading leaderboard data")
end

If anyone has any suggestions or advice on what I should do, I would greatly appreciate it. Also, if you need more details or information, please let me know and I’ll be happy to provide it.

Thank you for your help!

Are you trying to change the players’ characters, or the dummies to have the players’ characters’ appearances? If the second, maybe this recent post will help you: Player Dancing on Podium.

1 Like

I’m trying to change a dummy appearance to have the player’s character appearance, you’re right. I tried looking at your solution, however, I didn’t managed to make it work.

This is the script I made:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local plrName1 = script.Parent["#1"].Nickname.Text
local plrName2 = script.Parent["#2"].Nickname.Text
local plrName3 = script.Parent["#3"].Nickname.Text

local leaderboard = script.Parent.Parent.Parent.Parent
local top1 = leaderboard.Statues.Top1
local top2 = leaderboard.Statues.Top2
local top3 = leaderboard.Statues.Top3

local playertop1 = top1.NumberOne -- dummy for player number one in the leaderboard
local playertop2 = top2.NumberTwo -- dummy for player number two one in the leaderboard
local playertop3 = top3.NumberThree -- dummy for player number three one in the leaderboard

-- create the BindableEvent and set it's parent to ReplicatedStorage
local myEvent = Instance.new("BindableEvent", ReplicatedStorage)

-- function to change the rig of a player's character
local function changeRig(player, newRig)
	local character = player.Character
	if character then
		character:Destroy()
	end
	local newCharacter = Players:CreateHumanoidModelFromDescription(newRig)
	newCharacter.Parent = player
end

while true do
	task.wait(5)

	-- get the appearance model for each player
	local player1 = Players:FindFirstChild(plrName1)
	local appearanceModel1 = player1 and Players:GetCharacterAppearanceAsync(player1.UserId)

	local player2 = Players:FindFirstChild(plrName2)
	local appearanceModel2 = player2 and Players:GetCharacterAppearanceAsync(player2.UserId)

	local player3 = Players:FindFirstChild(plrName3)
	local appearanceModel3 = player3 and Players:GetCharacterAppearanceAsync(player3.UserId)

	-- change the rig for each player
	if appearanceModel1 then
		changeRig(playertop1, appearanceModel1)
	end

	if appearanceModel2 then
		changeRig(playertop2, appearanceModel2)
	end

	if appearanceModel3 then
		changeRig(playertop3, appearanceModel3)
	end
end

I don’t know what variable represents the dummy that the HumanoidDescription will be applied to, but on that dummy’s Humanoid, call Humanoid:ApplyDescription(--[[ HumanoidDescription here]]).

From the looks of the code, you’re trying to change the player’s character, but that’s not what you want. Since you just want to change the dummy’s appearance, your function would look like this:

local function changeAppearance(player : Player, dummyRig : model)
    local description = Players:GetHumanoidDescriptionFromUserId(player.UserId)
    dummyRig.Humanoid:ApplyDescription(description)
end)
1 Like

I made some changes to the script to improve it’s clarity and functionality and added your suggestions. However, despite making modifications specific to my script, I’m still experiencing issues with it. I haven’t received any error messages though. Here’s the current version of the script:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- variables to set up player name (that are going to be used later on the script, to change dummies appearance)
local plrName1 = script.Parent["#1"].Nickname.Text
local plrName2 = script.Parent["#2"].Nickname.Text
local plrName3 = script.Parent["#3"].Nickname.Text

-- variables to set up leaderboard
local leaderboard = script.Parent.Parent.Parent.Parent

-- variables of statues of where the dummies are standing on
local top1 = leaderboard.Statues.Top1
local top2 = leaderboard.Statues.Top2
local top3 = leaderboard.Statues.Top3

-- dummies
local playertop1 = top1.NumberOne
local playertop2 = top2.NumberTwo
local playertop3 = top3.NumberThree

-- create the BindableEvent and set it's parent to ReplicatedStorage
local myEvent = Instance.new("BindableEvent", ReplicatedStorage)

-- function to change the rig of a player's character
local function changeRig(dummyRig, appearanceModel)
	local description = Players:GetHumanoidDescriptionFromUserId(appearanceModel.userId)
	dummyRig.Humanoid:ApplyDescription(description)
end

while true do
	task.wait(5)

	-- get the appearance model for each player
	local player1 = Players:FindFirstChild(plrName1)
	local appearanceModel1 = player1 and Players:GetCharacterAppearanceAsync(player1.UserId)

	local player2 = Players:FindFirstChild(plrName2)
	local appearanceModel2 = player2 and Players:GetCharacterAppearanceAsync(player2.UserId)

	local player3 = Players:FindFirstChild(plrName3)
	local appearanceModel3 = player3 and Players:GetCharacterAppearanceAsync(player3.UserId)

	-- change the rig for each player
	if appearanceModel1 then
		changeRig(playertop1, appearanceModel1)
	end

	if appearanceModel2 then
		changeRig(playertop2, appearanceModel2)
	end

	if appearanceModel3 then
		changeRig(playertop3, appearanceModel3)
	end
end

I see that you are using Players:GetCharacterAppearanceAsync(), which is deprecated.

You don’t need to use this function because you have a dummy Model and Players:GetHumanoidDescriptionFromUserId() will get the “appearance” of a player. You just need to apply the HumanoidDescription created by Players:GetHumanoidDescriptionFromUserId() using a player’s UserId to the dummy’s Humanoid.

Also, it seems that the variables that store the players’ names will never be changed. Is this on purpose?
You’re setting the variables to the current text at that time held by an object, not the object. If you set the variables to the objects, you can access its current text (not its old text).

You’re correct that it’s deprecated, and although I managed to fix it, it’s still not working. Strangely, there are still no errors in the script. Additionally, I realize that I forgot to include a ‘changed’ event listener in the script, as you pointed out. Here’s what the updated script looks like now:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- variables to set up player name (that are going to be used later on the script, to change dummies appearance)
local plrName1 = script.Parent["#1"].Nickname.Text
local plrName2 = script.Parent["#2"].Nickname.Text
local plrName3 = script.Parent["#3"].Nickname.Text

-- variables to set up leaderboard
local leaderboard = script.Parent.Parent.Parent.Parent

-- variables of statues of where the dummies are standing on
local top1 = leaderboard.Statues.Top1
local top2 = leaderboard.Statues.Top2
local top3 = leaderboard.Statues.Top3

-- dummies
local playertop1 = top1.NumberOne
local playertop2 = top2.NumberTwo
local playertop3 = top3.NumberThree

-- create the BindableEvent and set it's parent to ReplicatedStorage
local myEvent = Instance.new("BindableEvent", ReplicatedStorage)

-- function to change the rig of a player's character
local function changeRig(dummyRig, player)
	local description = Players:GetHumanoidDescriptionFromUserId(player.UserId)
	dummyRig.Humanoid:ApplyDescription(description)
end

-- update the dummies when the player names change
local function updateDummies()
	-- update player names
	plrName1 = script.Parent["#1"].Nickname.Text
	plrName2 = script.Parent["#2"].Nickname.Text
	plrName3 = script.Parent["#3"].Nickname.Text

	-- update the dummies
	local player1 = Players:FindFirstChild(plrName1)
	local player2 = Players:FindFirstChild(plrName2)
	local player3 = Players:FindFirstChild(plrName3)

	if player1 then
		changeRig(playertop1, player1)
	end

	if player2 then
		changeRig(playertop2, player2)
	end

	if player3 then
		changeRig(playertop3, player3)
	end
end

-- set up event listeners for player name changes
script.Parent["#1"].Nickname.Changed:Connect(updateDummies)
script.Parent["#2"].Nickname.Changed:Connect(updateDummies)
script.Parent["#3"].Nickname.Changed:Connect(updateDummies)

while true do
	task.wait(5)
	updateDummies()
end

OK, nice. Now, may I ask if, for example, script.Parent["#1"].Nickname.Text is a player’s Name? Have you tried adding print()s inside of those if statements to check if those Players do exist? For example,

if player1 then
    print("Player1 does exist")
    -- Other code here.
end

I managed to make it work. After some debugging, I found that the issue was that it was getting the username + the clicks, but it was supposed to get only the username, thank you!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.