Characters
The Characters module manages custom player characters across server and client.
It handles registration, cloning, storage, and replication of player models,
as well as signals for character lifecycle events.
When required, Characters automatically:
- Creates a container (
PlayerCharacterStorage) in parented to theCameraso it doesn't replicate. - Creates or waits for a
PLAYER_MODEL_CACHEfolder inReplicatedStorageto hold replicated player models. - Connects to:
- Server:
Players.PlayerRemovingto clean up models. - Client:
ChildAddedonPLAYER_MODEL_CACHEto sync characters.
- Server:
Shared API
Characters.GetCharacter(player: Player) → Model?
Returns the current character model registered for the given player,
or nil if no character is set.
Characters.SetCharacter(player: Player, model: Model | string, data: any?)
Assigns a character model to the given player.
| Parameter | Type | Description |
|---|---|---|
player | Player | The player whose character is being set. |
model | Model/string | The character model instance, or a key referencing a cached model in Config.PLAYER_MODELS. |
data | any? | Optional initialization data. Serialized via HttpService:JSONEncode when replicated. |
- If a string key is passed, the model is looked up in
Config.PLAYER_MODELS. - The model is cloned and parented to
PlayerCharacterStorage. - If the player already had a character, it is cleaned up and
CharacterRemovedis fired. - On the server, a clone is inserted into
ReplicatedStorage.PLAYER_MODEL_CACHEto sync with the clients. - On the client, incoming clones from the cache are registered automatically.
DANGER
If data is provided, ensure it is JSON-serializable.
Signals
These fire on both the server and client.
Characters.CharacterAdded(player: Player, model: Model, data: any)
Fired when a new character is registered for a player.
Characters.CharacterRemoved(player: Player, model: Model)
Fired when a character is removed (e.g. when replaced or on PlayerRemoving).
Internal Behavior
- Models are parented to a hidden
Camerainworkspaceto prevent them from replicating automatically. - On the server, each player’s character is cloned into
PLAYER_MODEL_CACHE
with theirUserIdas the name for identification. - On the client, clones from
PLAYER_MODEL_CACHEare consumed, registered, and removed. - When a player leaves, their model is destroyed and
CharacterRemovedis fired.
Usage Example
--Enable custom characters, else the character system would not work
require(ReplicatedStorage.Packages.chrono).Config.ENABLE_CUSTOM_CHARACTERS = true
local Characters = require(ReplicatedStorage.Packages.chrono).Characters
--Character lifecycles:
Characters.CharacterAdded:Connect(function(player, model, data)
print("Character added:", player.Name, model, data)
end)
Characters.CharacterRemoved:Connect(function(player, model)
print("Character removed:", player.Name, model)
end)
--On the server, set a custom character for Chrono to manage
local player = game.Players.PlayerAdded:Wait()
Characters.SetCharacter(player, "paris", { skidding = true })
--On the client (or server), get the character Chrono is managing
local character = Characters.GetCharacter(game.Players.LocalPlayer)
--I recommend setting up your own custom character system and calling chrono so that they can still be custom replicated, rather than depending on chrono to get your characters. We designed chrono's api to be simple and flexible for exactly that.Important Notes on Reset Behavior
When using custom characters with the Characters module, the default Roblox reset flow no longer works.
- If a player resets while using a custom character:
- The character will not respawn automatically.
- On the client, the character will remain in a "dead" state.
- On the server, the character will still be considered alive and will not be replaced.
DANGER
If you enable Config.ENABLE_CUSTOM_CHARACTERS, you must implement your own respawn / reset logic.
Roblox’s built-in reset button will no longer respawn the player automatically.
