Allow us to hook into the respawn engine with callbacks

As a Roblox devloper it is currently too hard to manipulate respawn logic, especially with position and character appearance

The issue around positioning is that if I use CharacterLoaded, and move the character using MoveTo, nothing happens. I have to wait an arbitrary amount of time before moving the character for it to correctly place itself. (You cant just use RespawnLocation, especially if you want an arbitrary CFrame)

The issue with character appearance is CharacterAppearanceLoaded can take a long time to fire and it would be easier if we could just set the HumanoidDescription beforehand if the player is respawning (not LoadCharacterWithDescription, this is for when we cant call it explicity)

A basic solution I have is to have two callbacks that are invoked to modify this logic

  • Respawning - return SpawnLocation/CFrame/Position of where to drop the character in
  • LoadingCharacterAppearance - return a HumanoidDescription of appearance to override default

If Roblox were to address this issue it would improve my development experience because I would be able to directly hook into the respawn engine instead of having to rely on events.


CharacterAdded fires very very bit before the character loads. I use this as a workaround, its janky but better something than nothing

   repeat task.wait() until plr.Character
   --// i assume characters loaded

but i need this so much


CC: @commitblue
I think a callback for Respawning would be way too overkill for something simple as setting the position since you can easily use task.defer to efficiently override that.

task.defer(workspace.PivotTo, Character,, 10, 0))

However, I do agree that a callback for CharacterAppearance would be desireable, since that’s a more obscure thing for developers to tamper with.


I absolutely hate the lack of documentation and behaviour to the point where I need to make my own CharacterAdded callback

function characterUtil.handleCharacterAdded(player: Player, callback: (character: Model) -> ())
	TypeChecks.Strict.PlayerWithCallback(player, callback)
	table.insert(Characters[player].CharacterAdded, callback)

	if player.Character then
		if characterUtil.isPlayerCharacter(player, player.Character) then
			instanceUtil.waitUntilAncestorIs(player.Character, workspace):andThen(function(character: Model)
					instanceUtil.waitForChild(character, "Head"),
					instanceUtil.waitForChild(character, "Humanoid"),
					instanceUtil.waitForChild(character, "HumanoidRootPart"),
				}):andThenCall(callback, character)

and you’d expect this out of the box but nope, the character isn’t in workspace, bodyparts and humanoid doesn’t exist yet during which doesn’t make any sense


Honestly writing your own logic is better, this way you can also choose how your character respawns and whatnot


can you elaborate why this would avoid the issue of character not being fully loaded? Doesn’t defer only wait a single frame?

When you’re using Immediate SignalBehavior, most events interwoven with the DataModel get fired prior to the tied instance’s initialization (That’s why you can’t just change an instance’s parent on DescendantAdded without it erroring).

If you use task.defer or have workspace.SignalBehavior set to Deferred, then your callback will fire on the next resumption cycle which guarantees you can safely change the properties without it erroring or doing nothing.