Architettura
L’unica regola
Sezione intitolata “L’unica regola”bs_core possiede lo stato. Denaro, XP, bisogni, posizione, dati del personaggio: solo bs_core li scrive e solo bs_core salva la riga. Ogni altra risorsa chiede a bs_core tramite export. È ciò che mantiene onesti i salvataggi: c’è un solo posto che segna un personaggio come modificato e un solo posto che scrive.
Livelli
Sezione intitolata “Livelli”NUI (html in each resource, shared shell in bs_ui) | SendNUIMessage / fetch (NUI callbacks)Client Lua mirrors state, never authoritative | net events + BSB callbacksServer Lua Player objects, validation, hooks | oxmysql (behind bs_core/server/sv_database.lua)MariaDB migrations in bs_core/sqlIl client chiede, il server decide, il server rimanda il risultato. Tutto ciò che un client invia viene ricontrollato sul server. I bisogni, per esempio, da un report del client possono solo scendere, ripristinare la fame è un’azione del server da un consumabile.
Mappa delle risorse
Sezione intitolata “Mappa delle risorse”Cosa fa ciascuna è nell’elenco delle resource.
| Gruppo | Risorse |
|---|---|
| Nucleo | bs_core, bs_loading, bs_multichar, bs_esx_bridge |
| UI | bs_ui (HUD, notifiche, parti NUI condivise), bs_radial, bs_menu (hub), bs_chat, bs_scoreboard |
| Giocatore | bs_inventory, bs_skills, bs_medical, bs_bodily, bs_emotes, bs_boosters, bs_gadgets, bs_drugs |
| Mondo | bs_world, bs_interactions (ALT target dot, containers), bs_economy (loot), bs_traders, bs_vehicles, bs_building, bs_crafting, bs_gates, bs_stash, bs_recycler, bs_mining, bs_scenes, bs_events, bs_extraction |
| Zombie | bs_zombies, bs_zombiepeds, bs_zombiesfx, bs_atlas, nodes |
| Sociale | bs_factions, bs_faction_bases, bs_jobs, bs_vip |
| Staff | bs_admin, bs_tester, bs_config, bs_guard, bs_cinecam |
| Asset | bs_assets |
Stati di sessione
Sezione intitolata “Stati di sessione”connecting -> playerConnecting: identity resolved, ban checkedloading -> client handshake (bs:session:clientReady)select -> limbo, frozen and invisible, character list/create/delete/selectplaying -> Player object exists server side, ped spawned/logout e una disconnessione passano entrambi per BS.UnloadPlayer, che prima forza il salvataggio. Lato client, exports.bs_core:GetSessionState() dice dove sei, e exports.bs_core:IsLoaded() è il semplice controllo “c’è un personaggio”.
Dati del giocatore da un’altra risorsa
Sezione intitolata “Dati del giocatore da un’altra risorsa”L’oggetto Player vive nello stato Lua di bs_core. Le funzioni non attraversano il confine degli export, quindi non ottieni l’oggetto, chiami export che fanno il lavoro:
-- serverlocal p = exports.bs_core:GetPlayerSummary(src) -- plain table: charId, name, level, xp, accounts, needs, role...exports.bs_core:AddMoney(src, 'cash', 50, 'my_reason')exports.bs_core:RemoveMoney(src, 'bank', 200, 'my_reason')exports.bs_core:AddXP(src, 25, 'my_reason')local v = exports.bs_core:GetPlayerMeta(src, 'my_key', nil)exports.bs_core:SetPlayerMeta(src, 'my_key', { any = 'table' })exports.bs_core:AwardAction(src, 'zombie_kill') -- uses Config.RewardsLato client: exports.bs_core:GetData(), GetNeeds(), IsLoaded().
I metadati del personaggio (GetPlayerMeta/SetPlayerMeta) sono il posto facile per piccoli dati per personaggio. bs_drugs tiene lì la dipendenza senza una tabella propria.
bs_core ha un pub/sub in-process (BS.On / BS.Emit) e ritrasmette ogni hook come un normale evento chiamato bs:hook:<name>. Dalla tua risorsa:
AddEventHandler('bs:hook:player:loaded', function(data) ... end)AddEventHandler('bs:hook:player:unloaded', function(...) ... end)| Hook | Lato |
|---|---|
core:ready | entrambi |
player:loaded, player:spawned, player:unloaded | entrambi |
player:money, player:levelUp | entrambi |
player:xp, player:action | server |
character:created, character:selected | server |
session:state, needs:changed | client |
Il ponte di callback (BSB)
Sezione intitolata “Il ponte di callback (BSB)”Richiesta/risposta su eventi net. Includi il file nel tuo manifest e ottieni BSB nel tuo stato Lua:
shared_scripts { '@bs_core/shared/sh_bridge.lua' }-- serverBSB.RegisterCallback('mything:get', function(src, a, b) return { ok = true, value = a + b }end)
-- clientlocal res = BSB.Await('mything:get', 5000, 1, 2) -- blocks this thread, nil on timeoutL’altro verso, il server chiede a un client:
-- clientBSB.RegisterClientCallback('mything:where', function() return GetEntityCoords(PlayerPedId()) end)-- serverlocal pos = BSB.AwaitClient(src, 'mything:where', 3000)Come funziona: una richiesta viene trasmessa a ogni risorsa e risponde quella che ha registrato il nome, le altre tacciono. Quindi:
- un nome sconosciuto o fermato va in timeout, non dà errore
- i nomi sono globali, prefissali con il tuo sistema (
squad:invite,factions:roster,vendor:buy) - il server limita ogni client a 40 richieste al secondo per risorsa
- un gestore che lancia un errore stampa
callback "x" errorede il client ricevenil
La convenzione per i ritorni è una tabella con ok, ed error quando fallisce: { ok = false, error = 'Not in a squad.' }.
C’è anche BSB.RegisterCommand(name, ace, help, args, handler) (controllo ACE, pcall e suggerimento in chat in uno) e BSB.Radial(spec) sul client per la ruota radiale. Usali invece di scrivere i tuoi.
Servizi
Sezione intitolata “Servizi”@bs_core/shared/sh_services.lua fornisce BS.Provide / BS.Use. È un modo controllato di chiamare gli export: il fornitore dice cosa offre, il consumatore ottiene un handle o una riga di log rumorosa, mai un nil silenzioso.
local inv = BS.Use('inventory')if inv then inv.GiveItem(src, 'bandage', 1) endÈ nuovo, la maggior parte del codice chiama ancora gli export direttamente. Funzionano entrambi.
Statebag usati
Sezione intitolata “Statebag usati”| Bag | Su | Impostato da | Significato |
|---|---|---|---|
bsDowned | giocatore | bs_medical | il giocatore è a terra |
bsDead, bsRevivable | giocatore | bs_medical | |
bsDrugMods | giocatore (locale) | bs_drugs | drain, regen, cap, infection, sway |
bsSteady | giocatore (locale) | bs_boosters | moltiplicatore di rinculo/oscillazione |
bsDrone | giocatore | bs_gadgets | pilotaggio di un drone |
bsSquad | giocatore | bs_factions | info sulla squadra |
bsFactionStyle, bsFactionTag, bsFactionCanInvite, bsFactionSafeZone | giocatore | bs_factions | stile del tag, permessi, zona sicura |
bsVipTag | giocatore | bs_vip | { tier, colour, style, hex, blip, hud }, nil senza VIP |
bsInRaid, bsRogue | giocatore | bs_extraction | stato della zona PvP |
bsSitting | giocatore | bs_emotes | |
bsZombie | entità | bs_zombies | id del record del camminatore. Anche zType, zGait, zState… in modalità di rete |
bsZombieDead | entità | bs_zombies | cadavere in rete |
bsCorpse | entità | bs_medical | corpo del giocatore |
bsProtected, bsKeep | entità | molti | la pulizia di bs_world lo salta |
bsVehicle, bsLocked, bsOwned, bsWindowsDown | veicolo | bs_vehicles | |
bsBuilt | entità | bs_building |
Se fai comparire un’entità che non deve essere ripulita da bs_world, imposta bsProtected su di essa.
Nomi degli eventi
Sezione intitolata “Nomi degli eventi”bs:<system>:<thing>, lower camel case alla fine:
bs:session:clientReady bs:characters:select bs:player:moneybs:inventory:state bs:squad:sync bs:z:addbs:ui:notify bs:ui:opened bs:medical:diedbs_core tiene i propri nomi in BS.Events (bs_core/shared/sh_events.lua) così nulla è scritto a mano. Gli hook sono bs:hook:*. I nomi dei callback usano system:action senza il prefisso bs:.
Ogni evento e callback per risorsa è nel riferimento API.
bs19.org · Privacy · Terms · Cookie settings
Cookies and outside content
The site only needs two essential cookies to keep you logged in and protect forms. Videos and streams from YouTube and Twitch load from their servers, which can set their own cookies, so they stay off until you say yes. Nothing is pre-ticked and you can change your mind any time with "Cookie settings" at the bottom of every page. Details.
Questions about the server, the framework or the site? A real person reads this, usually within a day.