Changing a player's character using DataStores

Good afternoon! I am trying to create a system that works with DataStores to overwrite a Player’s avatar at the start of a round in a project I’m working on.

However, I’m having some trouble with the InvokeServer aspect of it. When I attempt to overwrite the player’s character with the Character saved into their respective DataStore, I receive an error in the output that the player’s character value has been indexed with nil, as if the player’s properties are outside of the scope.

The rest of the block seems to run fine. Removing all reference to the player’s character after the ServerInvoke will result in the code working, and I am able to place a copy of the DataStore character into workspace. It’s simply a matter of accessing the player’s avatar properties that I am struggling with.

–ServerSide function receiving Invoke:

RepoSto.getData.OnServerInvoke = function(player)

return Data[player.UserId]

end

–ClientSide function receiving the data and setting the player’s character to the DataStore Character:

local RepoSto = game:GetService(“ReplicatedStorage”)
local getDataFunction = RepoSto:WaitForChild(“getData”)
local SelectableChara = RepoSto.Characters

local function setupChara(player)

local playerData = getDataFunction:InvokeServer(player)
print("Invoke Active!")
for i, MyChara in pairs (playerData.SelectedCharacter) do
	local MyChara = SelectableChara:FindFirstChild(MyChara)
	if MyChara then
		local oldChar = player.Character
		local newChara = MyChara:Clone()
		newChara.Parent = workspace
		newChara.Name = player.Name
		player.Character = newChara
		print("This is Working")
	end
end

end

wait(5)
setupChara()

RBLXoutput

You aren’t calling setupChara with a player argument. Because of this, the “player” argument of setupChara is nil. Since this is a LocalScript, you should be using Players.LocalPlayer to get the player of the connected client.

For the server invoke, Player does not need to be passed as Player is always passed as the first argument to OnServerInvoke and OnServerEvent. Your code would need to look something like this to work as written.

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

local LocalPlayer = Players.LocalPlayer
local getDataFunction = RepoSto:WaitForChild("getData")
local SelectableChara = RepoSto.Characters

local function setupChara()
	local playerData = getDataFunction:InvokeServer()
	
	print("Invoke Active!")
	for i, MyChara in pairs (playerData.SelectedCharacter) do
		local MyChara = SelectableChara:FindFirstChild(MyChara)
		if MyChara then
			local oldChar = LocalPlayer.Character
			local newChara = MyChara:Clone()
			newChara.Parent = workspace
			newChara.Name = LocalPlayer.Name
			LocalPlayer.Character = newChara
			print("This is Working")
		end
	end

end

wait(5)
setupChara()

However, there are a few problems with this. Firstly, cloning the character on the client and then attempting to set .Character will result in it not replicating and therefore the changes won’t be seen by any other player. See this: Roblox Client-Server Model

I will leave it as an exercise to you to learn this and solve it. Happy programming!

1 Like

Thank you for your feedback! I looked over your solution and it works on the client side.
I am now trying replicate this onto the server.

I’m now trying to use a remote event inside of the client code to change the avatar’s appearance on to the server side.

–Client Side:

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

local LocalPlayer = Players.LocalPlayer
local getDataFunction = RepoSto:WaitForChild("getData")
local SelectableChara = RepoSto.Characters
local changeCharacter = RepoSto:WaitForChild("changeCharacter")

local function setupChara()
	local playerData = getDataFunction:InvokeServer()

print("Invoke Active!")
for i, MyChara in pairs (playerData.SelectedCharacter) do
	local MyChara = SelectableChara:FindFirstChild(MyChara)
	if MyChara then
		changeCharacter:FireServer(MyChara)
		print("This is Working")
	end
end

end

wait(5)
setupChara()

–Server Remote Function:

RepoSto.changeCharacter.OnServerEvent:Connect(function(player, myChara)
		local	char = Characters[myChara]:Clone()
		char.Name = player.Name
		player:LoadCharacter()
		player.Character = char
		player.Character.Parent = workspace
	end)

However, I am now receiving an error for the server side of the remote function as the local char value is being read as an instance instead of a string.

[EDIT] Silly me, I forgot to pass the Name parameter from the client side to the server side.
Now it appears to be working. Thank you again for helping me through this!