Character Added Exists On Server But Not Client

So I have a remote event that gets fired from the server once my character gets added, sending that character as a parameter. However, once it reaches the client, the character is nil.

Server Code:

local PLAYERS = game:GetService("Players")
local CHAR_ADDED = game.ReplicatedStorage.CharAdded

PLAYERS.PlayerAdded:Connect(function(player)
	player.CharacterAdded:connect(function(character)
		print(player, character)
		CHAR_ADDED:FireAllClients(player, character)
	end)
end)

Client Code:

local CHAR_ADDED = game.ReplicatedStorage.CharAdded

CHAR_ADDED.OnClientEvent:Connect(function(player, character)
	print(player, character)
end)

Here’s the output:
image

Repro file:
character added issue.rbxl (29.2 KB)

Any idea how to fix this?

Instances are passed by reference through remotes. If the client sees an instance variable as nil that means it doesn’t exist on the client yet. The current internal instructions for character loading does not guarantee an existing character when CharacterAdded fires.

Characters are created by the server so they will not immediately exist on the client until they’re attached to the DataModel. If you add an additional print to check the parent of the character from the server you’ll see that when CharacterAdded fires the parent is nil. There are three ways to resolve this, in order from most ideal to less ideal:

  • Question when Avatar Loading Event Ordering Improvements is coming.

  • Defer FireAllClients. This will need a bit of testing but it should defer until LoadCharacter returns whether called internally or by developer code. Not particularly sure where it gets slotted.

  • Use AncestryChanged to check if the character has been attached to the DataModel.

From the server using the second method:

local PLAYERS = game:GetService("Players")
local CHAR_ADDED = game.ReplicatedStorage.CharAdded

PLAYERS.PlayerAdded:Connect(function(player)
	player.CharacterAdded:connect(function(character)
		task.defer(CHAR_ADDED.FireAllClients, CHAR_ADDED, player, character)
	end)
end)

place the local script in character scripts and then print

I don’t suggest using a method like this. It would be much better if you handle CharacterAdded on each client separately.

i.e.

local function HandleCharacter(Character)
    -- do whatever
end

local function HandlePlayer(Player)
    if Player.Character then HandleCharacter(Player.Character) end 
    Player.CharacterAdded:Connect(HandleCharacter)
end

for _, Player in ipairs(game.Players:GetPlayers()) do
    HandlePlayer(Player)
end
game.Players.PlayerAdded:Connect(HandlePlayer)
local player = game.Players.LocalPlayer

print(player.Name)