es_extended, qb-core, or qbx_core, you can still run every Atlas resource by filling in the custom framework adapter. An adapter normalizes your framework to one fixed shape, so consumer scripts call Bridge.GetJob(src) and Bridge.AddMoney(src, 'bank', 500) without ever branching on which framework you run.
This is the most important page for unsupported setups. Work through the contract once and every Atlas resource works.
Consumers always use
Bridge.Framework (and its shortcuts like Bridge.GetJob) — never the raw Fw* exports the bridge generates internally. You only implement the adapter; the bridge wires the rest.How it works
The bridge selects a framework provider with theatlas:framework convar and loads the matching adapter. When you set it to custom, the bridge loads your editable stub:
- Server →
editable/framework/server.lua - Client →
editable/framework/client.lua
custom adapter fails to load — a syntax error or a runtime error at load time — the bridge falls back to the _default adapter so the server still boots. That fallback is why a half-finished adapter can look like “money silently fails”: the default adapter’s no-op methods are running, not yours.
The single-return rule
Normalized shapes
Your methods must return these exact shapes so consumer scripts keep working unchanged:cash / bank / dirty inside the adapter. If your framework has no dirty-money concept, return 0 for it.
Server contract
Implement these ineditable/framework/server.lua. Required methods must return correct data for Atlas resources to function; optional methods can return a safe no-op (0 / false / {}) if your framework lacks the feature.
The player’s unique identifier (license, char id, etc.).
Source ids of all currently loaded players.
The player’s character name.
The normalized job shape
{ name, label, grade, gradeLabel, isBoss, onDuty }.Set the player’s job. Return
true on success.Balance of
'cash' | 'bank' | 'dirty'.Add money to an account.
reason is an optional audit string. Return true on success.Remove money. Return
false if the player has insufficient funds.Whether the player is a server admin.
Source ids of online players with that job.
Set the player’s duty state. Return
true on success.Society (job) account balance. Return
0 if you have no society banking.Add to a society account. Return
false if unsupported.Remove from a society account. Return
false if unsupported.Register
item as a usable item, calling onUse(src) when used. See Usable items.Client contract
Implement these ineditable/framework/client.lua:
The local player’s data.
name is { first, last }; job is the normalized job shape; money is optional.The local player’s normalized job shape.
Whether the local player is on duty.
Lifecycle events you must fire
The bridge does not poll your framework. You translate your framework’s events into the normalized bridge events so consumers can react. Fire these as the matching thing happens:- Server
- Client
Usable items
Usable-item registration lives on the framework adapter (not inventory), because most frameworks own item usage. ImplementRegisterUsable(item, onUse) to register a usable with your framework that calls onUse(src).
When a consumer registers a usable through Bridge.Inventory.RegisterUsableItem, the bridge calls your RegisterUsable with an onUse that fires a per-resource bus event:
onUse(src) runs when the item is used.
Worked example
A complete, copy-pasteable server adapter for a fictionalMyFramework, modeled on the real es_extended adapter: an account map, a normalizeJob helper, every contract method, and the three lifecycle translations.
Test it
Enable debug
Add
setr atlas:debug "true" and setr atlas:framework "custom", then restart atlasBridge.Confirm the adapter loaded
Look for
[Framework] server adapter: custom in the console. If you instead see _default, your stub errored at load — fix the error and restart.Read money and job back
From a test command, call
Bridge.GetJob(src) and Bridge.GetMoney(src, 'bank') and confirm they return real values for a loaded player.Buy or receive an item
Run a flow that removes money and grants an item, and confirm the notification, the balance change, and the item all land.
Pitfalls
Money silently 'fails'
Money silently 'fails'
Usually the
custom adapter errored at load and the bridge fell back to _default, whose money methods are no-ops that return false. Check the console for server adapter: _default and fix the load error.Returning two values
Returning two values
Adapter methods are single-return — exports drop the second value. Never
return ok, err; return one value.Wrong job or account shape
Wrong job or account shape
Consumers read
job.name / job.grade / job.isBoss and the accounts cash / bank / dirty. If your framework uses different keys, normalize them inside the adapter — do not pass the raw framework table through.Lifecycle events not fired
Lifecycle events not fired
If players never initialize or job-gated features never update, you likely forgot
atlasBridge:playerLoaded or atlasBridge:jobChange. The bridge relies entirely on these.Custom inventory adapter
Running an unsupported inventory too? Fill the inventory adapter next.
