Optional user: GetPlayerDataReqHow many players are present. Deliberately not getPlayers().length: it reads the
tracked size directly instead of building a payload per player, so it stays cheap for
per-frame checks like capacity gates. Counts the local player on a client, same as
getPlayers.
Because of that it reflects the last settled tick, while getPlayers validates
against live components — so for one frame after an entity disappears this can read one
higher than getPlayers().length. Use getPlayers().length when you need the two to
agree exactly.
Every player currently present, on the same "identity is here" threshold as getPlayer, and with the same element shape.
On a client this includes the local player, whose identity is one of the tracked
entities. Filter when you mean "everyone else":
getPlayers().filter((p) => p.entity !== engine.PlayerEntity). A headless server has
no local avatar, so there it is always just the remote peers.
Called once per player when they arrive.
By default this waits for the avatar profile component, so avatar is set. Pass
{ requireProfile: false } to be told as soon as the player's identity exists — see
PlayerEventOptions for what each threshold guarantees about the name.
By default this also fires once for each player who already satisfies the threshold —
see replayPresent in PlayerEventOptions.
Do not cache player.entity past the callback: the entity backing an address can be
replaced without an event (see GetPlayerDataRes.entity).
async handlers are supported; a rejection is logged and isolated, never left
unhandled, and never stops the other handlers.
an unsubscribe function
// rendering: wait for the profile, and render displayName (name may be unresolved)
onEnterScene((player) => addNameplate(player.userId, player.displayName))
// server presence: react as soon as the player exists
onEnterScene(async (player) => {
const profile = await store.load(player.userId)
room.send('profile', profile, { to: [player.userId] })
}, { requireProfile: false })
Optional options: PlayerEventOptionsCalled once per player when they arrive.
By default this waits for the avatar profile component, so avatar is set. Pass
{ requireProfile: false } to be told as soon as the player's identity exists — see
PlayerEventOptions for what each threshold guarantees about the name.
By default this also fires once for each player who already satisfies the threshold —
see replayPresent in PlayerEventOptions.
Do not cache player.entity past the callback: the entity backing an address can be
replaced without an event (see GetPlayerDataRes.entity).
async handlers are supported; a rejection is logged and isolated, never left
unhandled, and never stops the other handlers.
an unsubscribe function
// rendering: wait for the profile, and render displayName (name may be unresolved)
onEnterScene((player) => addNameplate(player.userId, player.displayName))
// server presence: react as soon as the player exists
onEnterScene(async (player) => {
const profile = await store.load(player.userId)
room.send('profile', profile, { to: [player.userId] })
}, { requireProfile: false })
Called once per player when they go away — mirroring the threshold of the matching
onEnterScene. With the default requireProfile, that means either the player
left or their avatar profile went away; with { requireProfile: false }, only when
their identity is gone.
Do not rely on getPlayer(userId) here — what it returns depends on which threshold
fired. On the identity threshold the entity is gone and it returns null; on the default
threshold it can still return a live player, because only the avatar profile went away
while the identity is still present. The last known state therefore arrives as the second
argument, and is the only reading that is correct in both cases.
an unsubscribe function
Optional options: PlayerEventOptionsCalled once per player when they go away — mirroring the threshold of the matching
onEnterScene. With the default requireProfile, that means either the player
left or their avatar profile went away; with { requireProfile: false }, only when
their identity is gone.
Do not rely on getPlayer(userId) here — what it returns depends on which threshold
fired. On the identity threshold the entity is gone and it returns null; on the default
threshold it can still return a live player, because only the avatar profile went away
while the identity is still present. The last known state therefore arrives as the second
argument, and is the only reading that is correct in both cases.
an unsubscribe function
Called when a player's real profile name first becomes available, and on any later
change. Subscribe to this instead of polling AvatarBase on a timer.
Not called for a name that was already resolved when the player was first seen — that
value is already on the arrival payload. It can, however, fire on the same tick as a
default-threshold onEnterScene: a late-arriving profile is both what resolves the name
and what satisfies that threshold, so a subscriber to both will be told twice. Identity
threshold subscribers need this event, since their arrival payload predates the name.
an unsubscribe function
Called when a player's real profile name first becomes available, and on any later
change. Subscribe to this instead of polling AvatarBase on a timer.
Not called for a name that was already resolved when the player was first seen — that
value is already on the arrival payload. It can, however, fire on the same tick as a
default-threshold onEnterScene: a late-arriving profile is both what resolves the name
and what satisfies that threshold, so a subscriber to both will be told twice. Identity
threshold subscribers need this event, since their arrival payload predates the name.
an unsubscribe function
Live data for a player, or null when they are not present. Omit
userfor the local player. Matching is case-insensitive.Present means "identity is here" — a player whose profile has not replicated is still returned, with an empty
nameandnameResolved: false, but a usableuserIdanddisplayName. An entity carrying only avatar or wearable data and no identity is not a player and yields null.