Player API¶
Find players, read where they are and what they're doing, and (carefully) move them. These APIs work from any NexusScript — the object does not have to be an NPC.
Everything keys off a player id (a string). Get one, then pass it to the other calls.
Getting a player id¶
Enumerate everyone:
string[] ids = Networking.GetPlayers(); // every player in the world
for (int i = 0; i < ids.Length; i++) { string id = ids[i]; /* ... */ }
Networking.GetPlayerCount(), Networking.GetPlayer(index), Networking.GetPlayerById(id).
Resolve one from an object or collider (e.g. in a trigger):
string id = Player.IdOf(other.gameObject); // "" if it isn't a player
React to join / leave (these methods are called automatically — no wiring):
public void OnPlayerJoined(string playerId) { /* greet, add a UI row, assign a team... */ }
public void OnPlayerLeft(string playerId) { /* remove their row, free a slot... */ }
Capture identity at join, not leave
OnPlayerLeft fires after the player is despawned, so GetUsername/GetUserId/GetPosition return blank there — only the playerId argument is reliable. If you need a leaving player's name or account id, read it in OnPlayerJoined and remember it (e.g. in Storage).
Identity¶
There are two ids, on purpose:
| Call | What it is | Use for |
|---|---|---|
Player.IdOf(obj) |
per‑session id (changes when they reconnect) | "right now" lookups |
Player.GetUserId(id) |
stable account id (same across sessions) | tracking identity — rewards, visit logs, allow‑lists |
Player.GetUsername(id) |
their account username (display/spoken) | when you want the name shown |
Player.GetName(id) |
the name an NPC knows them by | NPC dialogue |
string userId = Player.GetUserId(id); // stable — track by this, never speak it
string name = Player.GetUsername(id); // safe to show/speak
This split is what lets an NPC greet generically while still knowing who you are — see World Events.
Who's talking to the NPC right now¶
Inside an NPC action or chat callback, you often need the id of whoever is asking — without it you can't look up "my score" or "my save". Two zero‑arg calls give you the current speaker:
| Call | What it is |
|---|---|
Player.GetSpeakerId() |
the current speaker's per‑session id ("" if the NPC isn't handling a message) |
Player.GetSpeakerUserId() |
their stable account id — same as GetUserId(GetSpeakerId()) |
// Custom action "look up the player's score"
void OnGetScore()
{
string uid = Player.GetSpeakerUserId(); // who asked — server-verified
if (uid == "") return;
// key the lookup to THEM (see the HTTP / Supabase page)
HTTP.GetVia("scores-db", "/rest/v1/scores?select=score&user_id=eq." + uid);
}
The speaker id is set by the server from the validated login — the AI never supplies it, so a player can't say "tell me Bob's score" and have the NPC fetch someone else's row. See Custom actions and HTTP / Supabase.
Reading a player¶
Vector3 pos = Player.GetPosition(id);
Vector3 head = Player.GetHeadPosition(id);
bool grounded = Player.IsGrounded(id);
Vector3 vel = Player.GetVelocity(id);
GetRotation, GetHeadRotation, GetBonePosition/GetBoneRotation, GetAvatarHeight, IsValid, IsLocal.
Spatial helpers:
float d = Player.GetDistanceTo(a, b); // between two players
bool near = Player.IsInRange(a, b, 5f);
bool front = Player.IsInFrontOf(viewer, target); // is target in viewer's view?
bool seen = Player.IsVisible(a, b); // clear line of sight?
Server‑side reads are best‑effort
Reads come from the synced transform on the server. Position, facing (IsInFrontOf/IsBehind), and line‑of‑sight (IsVisible) are accurate; velocity and head/avatar height are approximate (the server doesn't simulate the full avatar rig).
Controlling a player¶
You can move players from a script — the command is sent to that player's client and applied there, then synced to everyone:
Player.Teleport(id, new Vector3(0, 1, 10));
Player.SetWalkSpeed(id, 6f);
Player.SetJumpHeight(id, 2.5f);
Player.Immobilize(id); // freeze input
Player.RestoreMobility(id);
SetVelocity/AddVelocity, SetRunSpeed, SetJumpImpulse, SetGravityStrength, EnableFlying/DisableFlying.
Movement control is experimental
Teleport and the movement setters are new and still being hardened in‑world. They're eventually consistent (a GetPosition right after Teleport may read the old spot until the client's update round‑trips), and EnableFlying is currently hover‑only. Test before relying on them in a published world. Reading and identity are solid.
Quick reference¶
| Group | Calls |
|---|---|
| Enumerate | Networking.GetPlayers / GetPlayerCount / GetPlayer / GetPlayerById |
| Resolve | Player.IdOf(obj) · OnPlayerJoined(id) / OnPlayerLeft(id) |
| Identity | GetUserId · GetUsername · GetName |
| Current speaker | GetSpeakerId · GetSpeakerUserId (who's talking to the NPC right now) |
| Read | GetPosition / GetRotation / GetVelocity / IsGrounded / GetHeadPosition / GetBonePosition / IsValid / IsLocal |
| Spatial | GetDistanceTo · IsInRange · GetNearby · IsInFrontOf · IsBehind · IsVisible |
| Control (experimental) | Teleport · SetVelocity · AddVelocity · SetWalkSpeed · SetRunSpeed · SetJumpHeight · SetGravityStrength · Immobilize · RestoreMobility · EnableFlying · DisableFlying |
→ See PlayerRoster.cs for a copy‑pasteable list/read/join‑leave example.