:LoadCharacter() on a specific position

Hi all,

I’m looking for a way to refresh the player’s character while keeping his exact position. This is what I did:

local currentCFrame = Player.Character.HumanoidRootPart.CFrame
Player:LoadCharacter()
Player.CharacterAdded:Wait()
Player.Character:WaitForChild("HumanoidRootPart").CFrame = currentCFrame

However, this makes my character spawn on a spawn location instead of the current position.

Why does this not work? How can I fix this?

Thanks in advance!

1 Like

From what I understand, that happens because of Roblox’s default loading order for Character models:

Source: Player:LoadCharacter - Creator Hub Documentation Page

Character Loading Event order

Calling the Player:LoadCharacter() with an R15 Avatar fires events in the following order (Note: R6 ordering is different):

  1. Player.Character sets

  2. Player.CharacterAdded fires

  3. Player.Changed fires with a value of “Character”

  4. Character appearance initializes

  5. Player.CharacterAppearanceLoaded fires

  6. Character.Parent sets to the DataModel

  7. The Character rig builds, and the Character scales

  8. Character moves to the spawn location

  9. LoadCharacter returns


Even though you’re updating the CFrame of the HumanoidRootPart after the Character has been added to the Workspace, the Character hasn’t been moved to the SpawnLocation yet. As a result, there needs to be some sort of additional delay before you teleport the Character. Here are some examples:

Example / Comparison Video

Note:

(I had tried this initially with one setup that used CharacterRemoving which wasn’t functioning properly, however, thanks to @MagmaBurnsV’s post in this thread showing that it would work fine, I realized the error I made and swapped it out with Humanoid.Died. Their inclusion of :PivotTo instead of updating the PrimaryPartCFrame was also a good reminder, as I had forgotten about that! :smiley: )

Example codeblock #1 Using task.defer (recommended over CharacterAppearanceLoaded):

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(Character)
		local Humanoid = Character:WaitForChild("Humanoid")

		Humanoid.Died:Connect(function()
			local currentCFrame = Character.HumanoidRootPart.CFrame
			player:LoadCharacter()
			task.defer(function()
				player.Character:PivotTo(currentCFrame)
				warn("Updated position")
			end)
		end)
	end)
end)

  1. At least in an empty baseplate, swapping out Player.CharacterAdded:Wait() with Player.CharacterAppearanceLoaded:Wait() teleports the player’s Character after all of those steps have already happened (even though CharacterAppearanceLoaded still fires even before the Character is moved to a SpawnLocation). However, based on my testing, it happens with a more noticeable delay than the first option (the comparison video can be found above, or by clicking here).

Example codeblock #2 (works, but not recommended)

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(Character)
		local Humanoid = Character:WaitForChild("Humanoid")
		
		Humanoid.Died:Connect(function()
			local currentCFrame = Character.HumanoidRootPart.CFrame
			player:LoadCharacter()
			player.CharacterAppearanceLoaded:Wait()
			player.Character:PivotTo(currentCFrame)
			warn("Updated position")
		end)
	end)
end)

Apologies for taking a while to edit the post! I wanted to make sure that it would still provide educational value even after my initial suggestion didn’t turn out to be the ideal solution :smiley:

1 Like

Weird, i tried it without the wait and it worked

local currentCFrame = Player.Character.HumanoidRootPart.CFrame
Player:LoadCharacter()
Player.Character:SetPrimaryPartCFrame(currentCFrame)
--Its a better practice using SetPrimaryPartCFrame when it comes to changing the player's position
2 Likes

You would have to defer pivoting the character, so the changes aren’t overrided by the engine. For example, you could do:

task.defer(function()
	Character:PivotTo(CFrame)
end)

Or if you don’t want to waste creating a new function everytime you could compact it to:

task.defer(workspace.PivotTo, Character, CFrame)
2 Likes

That made no difference until I put a task.wait() after Player.CharacterAppearanceLoaded:Wait(). But that still didn’t work as intended.

I’m assuming this is because CharacterAppearanceLoaded doesn’t always work on Studio Play testing

1 Like

That’s odd – at least when I tested it in an empty baseplate, swapping it out with Player.CharacterAppearanceLoaded:Wait() appeared to work every time, as shown in the following example:

Edit: Here’s the example / comparison video


But even with that in mind, I would recommend referencing @MagmaBurnsV’s usage of task.defer for this use case, instead. After doing some additional testing in Studio, that seems to be more consistent and teleports the Character with essentially no visual delay in comparison to the method I initially suggested (as shown by the comparison in the video).

I’ve since revised my original post to include a refined example that makes usage of task.defer instead of only suggesting Player.CharacterAppearanceLoaded:Wait().

1 Like

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