Passer au contenu principal
Version: latest - a1.156.0 ⚖️

Player Lifecycle

The events triggered from when a player connects until they leave, and the right moment to do each thing.

Overview

When someone joins your server, these are the main events triggered, in order:

#EventSideWhat happened
1PlayerConnect (Server)ServerSomeone is attempting to connect. The Player doesn't exist yet
2Spawn on PlayerServerThe Player entity was created. The client is still loading the map and downloading files
3SpawnLocalPlayer (Client)ClientThe client finished loading and its own Player is available with Client.GetLocalPlayer()
4ReadyServerThe client fully loaded the map and all entities, and is ready to play
5PossessBothThe Player started controlling a Pawn (e.g. a Character)
-UnPossessBothThe Player stopped controlling a Pawn
6Destroy on PlayerBothThe Player left the server
7PlayerDisconnect (Server)ServerThe connection was closed, with the disconnect reason
info

A Player represents the connected person, and a Character represents a body in the world. A Player can exist without a Character (flying as a spectator), and a Character can exist without a Player (as a NPC). See Players vs Characters vs Pawn.

Refusing a Connection

PlayerConnect (Server) is triggered before the Player entity exists, so it's the place to refuse someone, for example if they are not in a whitelist:

Server/Index.lua
local whitelist = {
["123456789"] = true,
}

Server.Subscribe("PlayerConnect", function(ip, player_account_id, player_name, player_steam_id)
if (not whitelist[player_account_id]) then
Server.KickByAccountID(player_account_id, "You are not in the whitelist!")
end
end)
tip

You can call Server.KickByAccountID() or Server.BanByAccountID() to kick or ban players while not having the full Player entity spawned.

Giving the Player a Character

You can spawn and possess a Character as soon as the Player spawns, the client will see it once it finishes loading:

Server/Index.lua
function SpawnCharacterForPlayer(player)
-- Picks a random spawn point of the map, if any
local spawn_points = Server.GetMapSpawnPoints()
local spawn = spawn_points[math.random(#spawn_points)] or { location = Vector(0, 0, 100), rotation = Rotator() }

local character = Character(spawn.location, spawn.rotation, "nanos-world::SK_Male")
player:Possess(character)
end

Player.Subscribe("Spawn", SpawnCharacterForPlayer)

-- Also gives Characters to Players already connected when the Package (re)loads
Package.Subscribe("Load", function()
for _, player in pairs(Player.GetPairs()) do
if (not player:GetControlledCharacter()) then
SpawnCharacterForPlayer(player)
end
end
end)
tip

Use the Ready event instead when you need the client to be fully loaded, for example to send it Remote Events, show a welcome message or start a countdown only when the player can actually see it.

Respawning

When a Character dies it's not destroyed, it stays in ragdoll. You can respawn it after some time with :Respawn(), which restores its health and moves it to a location:

Server/Index.lua
Character.Subscribe("Death", function(character, last_damage_taken, last_bone_damaged, damage_type_reason, hit_from_direction, instigator)
-- Only respawns Characters controlled by Players
if (not character:GetPlayer()) then return end

Timer.SetTimeout(function()
-- The Character (or the Player) may have been destroyed in the meantime
if (not character:IsValid()) then return end

character:Respawn(Vector(0, 0, 100), Rotator())
end, 5000)
end)

Cleaning Up when the Player Leaves

The Character is not destroyed automatically when the Player leaves, so you usually want to destroy it yourself:

Server/Index.lua
Player.Subscribe("Destroy", function(player)
local character = player:GetControlledCharacter()
if (character) then
character:Destroy()
end
end)

On the Client Side

On the client, the local Player is only available after SpawnLocalPlayer. To track the Character the local player is controlling (e.g. to update a HUD), subscribe to its Possess event:

Client/Index.lua
Client.Subscribe("SpawnLocalPlayer", function(local_player)
local_player:Subscribe("Possess", function(player, character)
Console.Log("I'm now controlling %s", tostring(character))
end)
end)

See the Basic HUD (Canvas) tutorial for a complete example.