Multicharacter
Hooks
Editable server and client hooks for adding your own code to the escrow protected resource.
On this page5 sections
The resource code is encrypted, but your server often needs its own logic at a specific moment: starting items, a phone number, a jail spawn, or pausing the anticheat while loading.
Two open files are for that:
| File | Use for |
|---|---|
bridge/server/editable.lua | Starting items, character create and delete, custom spawn and bucket, select veto |
bridge/client/editable.lua | Anticheat, HUD, anything that depends on the player's stage |
Implement a hook by filling the function already in the file:
function SC.Editable.GiveStartingItems(src, citizenid) exports.ox_inventory:AddItem(src, 'phone', 1)endYour code cannot break loading
- Every hook has a safe default in the encrypted part, so a deleted function still exists.
- Every call is wrapped in
pcall. An error is printed with the hook name, and the character still spawns.
[sc_multicharacter] error in editable hook "GiveStartingItems": ...Hooks or exports
| You write code... | Use |
|---|---|
| in this resource, in the editable files | Hooks on this page |
| in another resource that reacts to this one | Exports and Events |
Call order
Player creates a character OnCharacterCreated(src, character, isFirst) OnStartingItemsPicked(src, citizenid, lines, total)Player selects a character CanSelectCharacter(src, character) ResolveSpawn(src, character, spawnKey) OnCharacterLoaded(src, character) ResolveBucket(src, character) GiveStartingItems(src, citizenid) OnStartingItemsGranted(src, citizenid, lines, total)Player gets control OnPlayerSpawned(character) clientRelog or disconnect OnCharacterLogout(src, citizenid)Character deleted OnCharacterDeleted(src, citizenid)Stage changes, all the time OnStateChanged(state) client OnSelectOpened() clientServer hooks
File: bridge/server/editable.lua.
| Hook | When | Returns |
|---|---|---|
OnCharacterCreated(src, character, isFirst) | The character row exists in the database | nothing |
OnStartingItemsPicked(src, citizenid, lines, total) | The player paid for the starter basket | nothing |
GiveStartingItems(src, citizenid) | The selected character's inventory exists | nothing |
OnStartingItemsGranted(src, citizenid, lines, total) | The basket was granted | nothing |
OnCharacterDeleted(src, citizenid) | The character was deleted | nothing |
OnCharacterLoaded(src, character) | Selected and handed to the framework | nothing |
OnCharacterLogout(src, citizenid) | Relog or disconnect | nothing |
ResolveSpawn(src, character, spawnKey) | Before the spawn point is resolved | vector4, table, or nil |
ResolveBucket(src, character) | When leaving the private world | bucket id or nil |
CanSelectCharacter(src, character) | Before the character loads | boolean, reason |
OnCharacterCreated
function SC.Editable.OnCharacterCreated(src, character, isFirst)endThe new character row exists, but the character has nothing yet: no items, phone number, or licenses.
characterhascitizenid,firstname,lastname,gender,dateofbirth,nationality, andheight.isFirstistrueonly for the player's first character.
GiveStartingItems
function SC.Editable.GiveStartingItems(src, citizenid)endRuns when the selected character's inventory exists, on every login, not only the first. To grant items once, track it yourself. See Examples.
OnStartingItemsPicked
function SC.Editable.OnStartingItemsPicked(src, citizenid, lines, total)endThe basket at payment time, before the appearance editor and arrival. The character has no session or inventory yet. Use it for logs, webhooks, or saving the choice in your own table.
OnStartingItemsGranted
function SC.Editable.OnStartingItemsGranted(src, citizenid, lines, total)endThe basket at grant time. Normal items are already in the inventory. Anything with a kind other than 'item', such as 'vehicle', was not granted and waits here for your code. Runs once per basket, a relog does not run it again.
lines is a list of:
{ key = 'car', item = 'blista', kind = 'vehicle', count = 1, price = 2000 }total is the total cost from the budget.
OnCharacterDeleted
function SC.Editable.OnCharacterDeleted(src, citizenid)endThe character was deleted. The only moment to clean up records in your tables, such as phone, vehicles, or properties.
OnCharacterLoaded
function SC.Editable.OnCharacterLoaded(src, character)endThe character was selected and handed to the framework. The player is still watching the camera flight.
OnCharacterLogout
function SC.Editable.OnCharacterLogout(src, citizenid)endThe character was released by a relog or disconnect.
ResolveSpawn
function SC.Editable.ResolveSpawn(src, character, spawnKey) return nilendYou decide where the character spawns. Runs before all resource rules, and what you return wins:
vector4(x, y, z, heading)- a table
{ x, y, z, heading }, orwinstead ofheading nilfor the normal rules: player choice, last position,Config.Spawn.default
spawnKey is the key of the location the player picked, or nil.
Use it when jail or hospital must override the player's choice. Only your jail resource knows who is jailed.
ResolveBucket
function SC.Editable.ResolveBucket(src, character) return nilendThe routing bucket the character joins after leaving the private world. nil means the main world (0). Use it for instanced apartments, a jail bucket, or a running event.
Runs only while the player is still in the bucket this resource put them in. If something else already moved them, they stay there.
CanSelectCharacter
function SC.Editable.CanSelectCharacter(src, character) return trueendVeto on character selection. Return false and a reason, and the player sees the reason as an error on the select screen. Use it for suspended characters, a whitelist, or a full gang.
Client hooks
File: bridge/client/editable.lua.
| Hook | When |
|---|---|
OnStateChanged(state) | The player's stage changed |
OnPlayerSpawned(character) | The whole flow ended and the player has control |
OnSelectOpened() | Character select opened, on join and every relog |
OnStateChanged
function SC.Editable.OnStateChanged(state)end| Field | Type | Meaning |
|---|---|---|
busy | boolean | true from the loading screen until the player has control |
spawned | boolean | The opposite of busy |
open | boolean | The resource UI is on screen |
citizenid | string/nil | Citizen id of the character being played |
Runs only on a real change, so you do not need to filter it.
OnPlayerSpawned
function SC.Editable.OnPlayerSpawned(character)endThe camera is back on the player and they have control. Turn your HUD or phone back on here.
OnSelectOpened
function SC.Editable.OnSelectOpened()endCharacter select just opened, on join and on every /relog. A good place to hide the HUD.