VORP And RSG Compatibility
wc_libs exists so your resource calls wc:AddMoney(source, 50) once and it works on both frameworks — no if framework == 'vorp' branches scattered through your code. This page explains exactly what's normalized, what's asymmetric on purpose, and what genuinely has no equivalent on one side.
How normalization works
Every module is split into a public function (in server/modules/*.lua or client/modules/*.lua) and an adapter (in server/adapters/vorp.lua/rsg.lua or the client equivalents). The public function never contains framework-specific code — it just calls whichever adapter server/init.lua/client/init.lua wired up after detecting the running core. All the VORP/RSG differences live in exactly two files per side.
wc:AddMoney(source, 50, 0)
wc:Notify(source, { title = "+$50" })
Fully normalized — safe to use identically on both
| Area | Notes |
|---|---|
| Player / character / job | GetPlayer, GetCharacter, GetJob return the same table shape on both. |
| Money reads/writes | GetMoney, AddMoney, RemoveMoney — cash works identically; see the asymmetric section below for gold/bank. |
| Inventory | GetItemCount, HasItem, CanCarryItem, AddItem, RemoveItem return the same boolean/number shapes on both. |
| Callbacks | RegisterCallback/TriggerCallback — same namespacing and signature on both, despite very different underlying APIs (VORP promises vs RSG callback functions). |
| Lifecycle — player loaded | OnPlayerLoaded fires reliably on both. |
| Webhook, nearby players, battlepass | Framework-agnostic by construction — pure FiveM natives or pcall-guarded external exports. |
Asymmetric by design — works on both, looks different
| Area | What differs |
|---|---|
| Notify | VORP gets all 17 native visual styles. RSG collapses every style to ox_lib's inform/success/error types. Both show a notification — they just don't look identical. |
| Revive / Heal | Native on VORP. On RSG, delegates to a configurable ambulance job export — no-ops with a console warning if that resource isn't running. |
| Skills | VORP-only. RSG has no skill system at all — calls return safe defaults and log a warning rather than erroring. |
Genuine gaps — no confirmed equivalent
| Function | Gap |
|---|---|
| GetBankMoney | Warns + returns nil on VORP — VORP has no bank currency (money/gold/rol only). |
| GetGold | Warns + returns 0 on RSG unless WCLibConfig.Money.rsg.gold is configured — RSG has no native gold currency. |
| OnPlayerUnload | Fires reliably on RSG. Registers but never fires on VORP — no confirmed dedicated server-side "unload" event exists. Use AddEventHandler('playerDropped', ...) on VORP instead. |
| OnJobUpdate | Fires on VORP via vorp:playerJobChange. No confirmed server-side equivalent on RSG — registers but never fires there. |
Writing code that targets both frameworks
Use Framework.Is only for the genuine gaps above — not for things wc_libs already normalizes.
-- Skills is VORP-only, so this guard is necessary:
if wc:Framework_Is('vorp') then
wc:ApplySkillBonus(source, 'trading', 15)
end
if wc:Framework_Is('vorp') then
wc:AddMoney(source, 50, 0)
else
wc:AddMoney(source, 50, 'cash') -- unnecessary — AddMoney already defaults to cash on both
end
Escape hatch when wc_libs doesn't cover something yet
Reach past the bridge with WCLib.Raw.VORP()/WCLib.Raw.RSG() for a one-off. If you find yourself doing it more than once or twice for the same thing, wrap it in _custom/ instead so every resource gets the clean version.
Raw.VORP()/Raw.RSG() aren't exported to other resources in the current build — only usable from _custom/client.lua/_custom/server.lua, which load inside wc_libs' own Lua state. See the full explanation on the Framework & Raw page.
Common mistakes
- Writing an
if/elseframework branch for something wc_libs already normalizes — check the table above before reaching forFramework.Is. - Assuming
Notifylooks pixel-identical on both frameworks — it's functionally equivalent, not visually identical, by design. - Relying on
OnPlayerUnload/OnJobUpdatefiring on the framework side that has a documented gap — use the framework-native event directly viaWCLib.Raw.VORP()/WCLib.Raw.RSG()from_custom/instead. - Calling
wc:Raw_VORP()/wc:Raw_RSG()from a resource other than wc_libs itself — it isn't exported today; see the limitation note above. - Setting
WCLibConfig.ForceFrameworkand forgetting to unset it after a migration — it silently overrides auto-detection forever.