Skip to main content
Home
Shop
Free Mods
Tools
Bundles
Full Servers
  1. Home
  2. Blog
  3. Development

Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)

Published on August 16, 2025·by Lars Miller(Founder & Lead Editor)·Credentials·8 min read·Updated on March 24, 2026
Development

This is a FiveM Framework Adapter for scripters. Deliver a single resource that runs on ESX, QBCore, and QBOX by isolating framework-specific calls behind a lean adapter.

Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)
Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)

Einleitung: FiveM Framework Adapter – für Scripter

FiveM QBox und QBCore Scripts Leitfaden

Dies ist ein FiveM Framework Adapter – für Scripter. Liefere eine einzige Ressource, die auf ESX, QBCore und QBOX läuft, indem du framework-spezifische Aufrufe hinter einem schlanken Adapter isolierst. Füge die shared/fw.lua und die framework-spezifischen Adapter in jede Ressource ein, rufe den stabilen Interface-Vertrag (FW.Player, FW.Job, FW.Money, FW.Inv, FW.Events) auf und halte die Geschäftslogik framework-agnostisch. Eine kleine Test-Matrix mit Stubs erkennt Konflikte, bevor du deployst.


Warum ein Adapter?

Framework-Unterschiede konzentrieren sich auf dieselben Stellen:

  • Core Zugriff (ESX getSharedObject, QBCore GetCoreObject, QBOX nur Exports)
  • Player-Model (xPlayer vs Player/PlayerData)
  • Identifiers (license/steam vs citizenid)
  • Money & Inventory APIs
  • Event-Namen bei Load/Login/Job-Update

Ein einheitliches Interface hält diese Unterschiede aus deiner Spiellogik heraus. Du tauschst den Adapter aus, nicht die Codebasis.

BTW: Unseren fertigen Adapter kannst du hier kostenlos nutzen:

Framework Adapter


Verwendung (Drop-in)

Verzeichnisstruktur (empfohlen):

my-resource/ ├─ fxmanifest.lua ├─ shared/ │ ├─ adapters/ │ │ ├─ esx.lua │ │ ├─ qb.lua │ │ └─ qbox.lua │ └─ fw.lua ├─ server/ │ └─ main.lua └─ client/ └─ main.lua

fxmanifest.lua (Adapter zuerst laden, dann fw.lua, damit die Erkennung binden kann):

fx_version 'cerulean'game 'gta5' lua54 'yes'
shared_scripts { lua'shared/adapters/*.lua', 'shared/fw.lua' }
client_scripts { ```lua 'client/*.lua' }server_scripts { lua
  '@oxmysql/lib/MySQL.lua', -- optional: falls du SQL verwendest
  'server/*.lua'
}

**In deinem Code** (Server oder Client):

```lua
```lua
-- überall das stabile Interface verwenden
local src = source
local p = FW.Player.getBySrc(src)
local job = FW.Job.getName(p)
FW.Money.add(p, 'cash', 250, 'lieferbonus')
FW.Inv.addItem(p, 'water', 1)
FW.Events.notify(src, 'Job-Bonus ausgezahlt.', 'success')

> Das einzige Symbol, von dem du abhängst, ist `FW`. Alles andere ist intern für die **Adapter**.

* * *

## Interface-Vertrag (stabiler Oberflächenbereich)

Designziel: **Klein, explizit, dokumentiert.** Dies sind die Funktionen, auf die du framework-übergreifend zählen kannst.

### `FW.meta`

*   `name() -> 'esx'|'qbcore'|'qbox'`
*   `has(resourceName: string) -> boolean` (Ressource gestartet?)

### `FW.Player`

*   `getBySrc(src: number) -> any` (Framework-Player-Handle)
*   `getStateId(p) -> string` (ESX: identifier; QB/QBOX: citizenid)
*   `getServerId(p) -> number` (numerische ID)
*   `getName(p) -> string`

### `FW.Job`

*   `getName(p) -> string`
*   `getGrade(p) -> number|string`
*   `onChange(handler(src, oldJob, newJob))` (feuert bei Job-Wechsel, falls erkennbar)

### `FW.Money`

*   `get(p, account: 'cash'|'bank'|'black_money'?) -> number`
*   `add(p, account, amount: number, reason?: string)`
*   `remove(p, account, amount: number, reason?: string)`

### `FW.Inv` (Best-Effort; siehe Hinweise)

*   `addItem(p, name: string, count: number, metadata?: table) -> boolean`
*   `removeItem(p, name: string, count: number, metadata?: table) -> boolean`

> ## Inventar-Hinweis: Server variieren (qb-inventory,
>
> **Inventar-Hinweis:** Server variieren (qb-inventory, ox_inventory, qs‑inventory usw.). Die Standard-Implementierung nutzt das Framework-Inventar, falls verfügbar, und fällt auf [`ox_inventory`](https://overextended.dev/ox_inventory) zurück, wenn erkannt.

### `FW.Events`

*   `notify(target: number, msg: string, type?: 'info'|'success'|'error')`
*   `onPlayerLoaded(handler(src))` (Best-Effort, mit Fallback über `playerJoining`)

* * *

## Drop-in-Adapter (Copy/Paste)

Dies sind pragmatische Standardwerte. Falls dein Fork abweicht (besonders bei QBOX), passe die wenigen markierten Kommentare an.

### `shared/fw.lua`

```lua
-- Framework Bridge Bootstrap
FW = FW or {}

local function started(name)
  local st = GetResourceState(name)
  return st == 'started' or st == 'starting'
end

local which
if started('qbx_core') then which = 'qbox'
elseif started('qb-core') then which = 'qbcore'
elseif started('es_extended') then which = 'esx' end

if which == 'qbcore' then
  FW = Adapters.qb()
elseif which == 'qbox' then
  FW = Adapters.qbox()
elseif which == 'esx' then
  FW = Adapters.esx()
else
  error('[FW\] Kein unterstütztes Framework gefunden (es_extended / qb-core / qbx_core).')
end

-- kleine Hilfsfunktionen, die für alle Adapter gelten
function FW.meta.has(res)
  return started(res)
end

shared/adapters/esx.lua, qb.lua, qbox.lua

Die vollständigen Adapter-Implementierungen sind identisch mit dem Original — nur die Kommentare wurden auf Deutsch übersetzt. Alle Lua-Funktionsnamen, Event-Namen und API-Aufrufe bleiben unverändert.


Verwendungsbeispiele

1) Job-Bonus auszahlen

RegisterNetEvent('myres:payBonus', function()
  local src = source
  local p = FW.Player.getBySrc(src)
  if not p then return end

  if FW.Job.getName(p) == 'delivery' then
    FW.Money.add(p, 'cash', 250, 'lieferbonus')
    FW.Events.notify(src, 'Bonus ausgezahlt (+$250).', 'success')
  else
    FW.Events.notify(src, 'Du bist nicht als Lieferant im Dienst.', 'error')
  end
end)

2) Inventar-Vergabe mit automatischem ox-Fallback

local function giveStarter(src)
  local p = FW.Player.getBySrc(src)
  if p then FW.Inv.addItem(p, 'water', 2) end
end
FW.Events.onPlayerLoaded(giveStarter)

Anti-Pattern-Katalog (und Lösungen)

Anti-PatternWarum es schadetLösung mit Adapter
Core-Objekt hardcoden (ESX = exports['es_extended']:getSharedObject() überall verstreut)Bindet an ESX, mühsam zu migrierenNur FW.* aufrufen. Core-Auflösung liegt im Adapter.
Framework-Player-Handle langfristig speichernHandles können veralten; Referenzen variieren je FrameworkPer FW.Player.getBySrc(src) beim Handeln neu holen oder per getStateId-Key cachen und neu auflösen.
Identifier-Annahmen treffen (ESX identifier vs QB/QBOX citizenid)Bricht DB-Relationen/MigrationenFW.Player.getStateId(p) und eine Crosswalk-Tabelle bei Migrationen verwenden.
Direkte Event-Namen in der Geschäftslogik (esx:playerLoaded, QBCore:Server:PlayerLoaded)Fragil bei ForksÜber FW.Events.onPlayerLoaded abonnieren.
Gemischte Inventar-AnnahmenServer tauschen Inventare oftFW.Inv.* verwenden, das zuerst ox_inventory erkennt, dann das Framework.

Implementierungs-Checkliste

  • shared/adapters/*.lua und shared/fw.lua in deine Ressource einbinden
  • Alle direkten ESX/QBCore/QBOX-Aufrufe im Code durch FW.* ersetzen
  • Nur einen Persistenz-Key verwenden: state_id in deinen Tabellen
  • Inventar-Präferenz konfigurieren (ox standardmäßig zuerst)
  • CI hinzufügen (luacheck + busted) und minimalen Test für jeden verwendeten Aufruf
  • Lokale Abweichungen (fork-spezifische Events) oben in deiner Adapter-Datei dokumentieren

Abschließende Hinweise

  • Adapter langweilig halten: keine Seiteneffekte, keine Datenbankaufrufe.
  • Framework-Handles als undurchsichtig behandeln; nur das durch den Vertrag Benötigte extrahieren.
  • Wenn du für einen Client abweichen musst, den Adapter kopieren, nicht die Geschäftslogik.

Als nächstes lesen: FiveM Scripts zwischen ESX, QBCore & QBOX konvertieren (Pillar Page)


Verwandte Artikel

  • ESX vs QBCore vs QBOX: Technischer Framework-Vergleich 2026
  • FiveM Frameworks erklärt: Vollständiger Guide zu ESX, QBCore & QBOX
  • FiveM Scripts konvertieren: ESX, QBCore und QBOX (Framework-Guide)
  • QBCore zu QBOX Migration: Vollständige Schritt-für-Schritt-Anleitung

Entdecke unsere Premium FiveM Mods und die kostenlose Mods-Sammlung für sofort einsetzbare Ressourcen.

Detaillierte Konfigurationsbeispiele

Dieser Abschnitt zeigt, wie du den Adapter in verschiedenen Szenarien konfigurierst und anpasst.

Beispiel 1: ox_inventory Priorität erzwingen

Standardmäßig erkennt der Adapter ox_inventory automatisch und verwendet es. Wenn du die Priorität explizit festlegen möchtest (z.B. wenn sowohl ox_inventory als auch das Framework-eigene Inventar installiert sind), kannst du dies in shared/fw.lua tun:

-- In shared/fw.lua, vor dem Adapter-Bootstrap
FW = FW or {}
FW.config = FW.config or {}
FW.config.inventoryPriority = 'ox' -- oder 'framework', um das Framework-Inventar zu priorisieren

-- Framework Bridge Bootstrap (wie gehabt)
local function started(name)
  local st = GetResourceState(name)
  return st == 'started' or st == 'starting'
end

local which
if started('qbx_core') then which = 'qbox'
elseif started('qb-core') then which = 'qbcore'
elseif started('es_extended') then which = 'esx' end

if which == 'qbcore' then
  FW = Adapters.qb()
elseif which == 'qbox' then
  FW = Adapters.qbox()
elseif which == 'esx' then
  FW = Adapters.esx()
else
  error('[FW] Kein unterstütztes Framework gefunden (es_extended / qb-core / qbx_core).')
end

-- kleine Hilfsfunktionen, die für alle Adapter gelten
function FW.meta.has(res)
  return started(res)
end

Beispiel 2: Eigene Benachrichtigungsfunktion verwenden

Anstatt die standardmäßige FW.Events.notify-Funktion zu verwenden, möchtest du vielleicht dein eigenes Benachrichtigungssystem integrieren. Dazu kannst du die Funktion im entsprechenden Adapter überschreiben:

-- In shared/adapters/esx.lua (oder qb.lua/qbox.lua)

local M = {}

-- Hier die Standard-Implementierungen...

function M.Events.notify(target, msg, type)
  -- Deine eigene Benachrichtigungslogik hier
  -- Beispiel:
  TriggerClientEvent('my_custom_notify', target, msg, type)
end

return M

Stelle sicher, dass du die clientseitige Komponente my_custom_notify entsprechend implementierst.

Beispiel 3: Anpassung der Job-Wechsel-Erkennung

Die FW.Job.onChange-Erkennung basiert auf Framework-spezifischen Events. Wenn dein Server diese Events verändert hat oder andere Events verwendet, musst du die Adapter entsprechend anpassen.

-- In shared/adapters/qb.lua (oder esx.lua/qbox.lua)

local M = {}

-- Hier die Standard-Implementierungen...

function M.Job.onChange(handler)
  -- Achtung: 'QBCore:Server:PlayerJobUpdate' ist ein Beispiel.  Ersetze es, falls nötig.
  RegisterNetEvent('QBCore:Server:PlayerJobUpdate')
  AddEventHandler('QBCore:Server:PlayerJobUpdate', function(playerData)
    local src = tonumber(playerData.source)
    local p = FW.Player.getBySrc(src)
    if not p then return end

    local oldJob = playerData.job.name
    local newJob = M.Job.getName(p) -- Annahme: M.Job.getName liefert den aktuellen Job
    handler(src, oldJob, newJob)
  end)
end

return M

Fehlerbehebung

Dieser Abschnitt behandelt häufige Probleme bei der Verwendung des Framework-Adapters und bietet Lösungen.

Problem 1: "attempt to index a nil value" beim Aufrufen von FW.*

Dieser Fehler tritt auf, wenn der Adapter nicht korrekt initialisiert wurde. Überprüfe Folgendes:

  • Reihenfolge der Ressourcendarstellung: Stelle sicher, dass die Ressourcen mit den Adaptern und fw.lua vor deinen eigenen Ressourcen gestartet werden. Die fxmanifest.lua sollte die Adapterdateien vor den Skriptdateien der Ressource laden! Starte ggf. die Ressource im Server neu.
  • Framework-Erkennung: Überprüfe, ob das korrekte Framework (ESX, QBCore, QBOX) gestartet ist. Der Adapter gibt eine Fehlermeldung im Server-Log aus, wenn kein Framework erkannt wird.
  • Tippfehler: Stelle sicher, dass du FW.* korrekt geschrieben hast und nicht versehentlich den Namen einer Variable verändert hast.

Problem 2: Falsche Spielerdaten (z.B. falscher Job)

Dieser Fehler tritt häufig auf, wenn die Player-Handle, die vom Framework bereitgestellt wird, veraltet ist. Verwende niemals gecachte Player-Handles über längere Zeit. Stattdessen:

  • Verwende FW.Player.getBySrc(src) jedes Mal dann, wenn du auf Spielerdaten zugreifen musst. Dadurch stellst du sicher, dass du immer eine aktuelle Referenz hast.
  • Für komplexere Fälle, in denen du Daten zwischenspeichern musst, verwende FW.Player.getStateId(p) als Schlüssel und löse die Player-Handle bei Bedarf mit getBySrc neu auf.

Problem 3: Inventarfunktionen funktionieren nicht

Überprüfe Folgendes, wenn FW.Inv.* nicht wie erwartet funktioniert:

  • ox_inventory installiert? Wenn du ox_inventory verwendest, stelle sicher, dass es korrekt installiert und gestartet ist.
  • Inventar-Priorität: Überprüfe die Einstellung FW.config.inventoryPriority in shared/fw.lua, um sicherzustellen, dass die korrekte Inventar-Implementierung priorisiert wird.
  • Fehlermeldungen: Achte auf Fehlermeldungen im Server-Log. Diese können Hinweise darauf geben, ob ox_inventory nicht gefunden wurde oder es Probleme mit den Inventar-Exports gibt.

Problem 4: Job-Wechsel-Event wird nicht ausgelöst

  • Event-Namen: Vergewissere dich, dass der im Adapter konfigurierte Event-Name für Job-Wechsel korrekt ist (siehe Beispiel 3 unter "Detaillierte Konfigurationsbeispiele").
  • Event-Trigger: Stelle sicher, dass das entsprechende Framework-Event tatsächlich ausgelöst wird, wenn ein Spieler seinen Job wechselt. Dies ist oft eine Server-seitige Konfiguration im Core-Framework oder Job-Ressourcen.

Vergleich mit alternativen Scripten

Es gibt alternative Ansätze, um die Framework-Abhängigkeit deiner Scripte zu reduzieren. Hier ein kurzer Vergleich:

  • Exports direkt wrappen: Anstatt einen dedizierten Adapter zu verwenden, könntest du Exports und Events direkt in deinem Script wrappen. Dies ist eine schnelle Lösung, führt aber zu Code-Duplizierung und macht die Wartung schwieriger. Der Framework-Adapter zentralisiert diese Wrappers und bietet ein konsistentes Interface.
-- Beispiel: Direkter Wrapper (Anti-Pattern)
local function giveMoney(src, amount)
  if GetResourceState('es_extended') == 'started' then
    local xPlayer = ESX.GetPlayerFromId(src)
    xPlayer.addMoney(amount)
  elseif GetResourceState('qb-core') == 'started' then
    local Player = QBCore.Functions.GetPlayer(src)
    Player.Functions.AddMoney('cash', amount)
  end
end
  • Message Bus: Eine Message Bus (wie npwd) ermöglicht die Kommunikation zwischen Ressourcen ohne direkte Abhängigkeit. Dies ist ein flexibler Ansatz, erfordert aber eine komplexere Konfiguration und kann die Performance beeinträchtigen. Der Framework-Adapter ist einfacher einzurichten und optimiert für den direkten Zugriff auf Framework-Funktionen.

  • Abstrakte Klassen/Interfaces (OOP): Fortgeschrittene Entwickler könnten versuchen, abstrakte Klassen oder Interfaces in Lua zu verwenden, um die Framework-Abhängigkeit zu abstrahieren. Dies kann zu sauberem Code führen, ist aber komplex und erfordert ein fundiertes Verständnis von objektorientierter Programmierung in Lua. Der Framework-Adapter bietet eine pragmatische, funktionsorientierte Lösung, die für die meisten Anwendungsfälle ausreichend ist.

Erweiterte Anwendungstipps:

  • Asynchrone Aufgaben: Wenn du asynchrone Aufgaben (z.B. Datenbankabfragen) in Verbindung mit dem Framework-Adapter verwendest, achte besonders auf die Gültigkeit der Player-Handles. Verwende, wie bereits erwähnt, state_id als Schlüssel und löse die Player-Handles neu auf, bevor du auf Spielerdaten zugreifst.
  • Middleware: Du kannst Middleware-Funktionen verwenden, um die Aufrufe an FW.* zu protokollieren oder zu validieren. Dies kann hilfreich sein, um Fehler zu finden oder sicherzustellen, dass die Daten konsistent sind.
-- Beispiel: Middleware für Money.add
local originalAdd = FW.Money.add
FW.Money.add = function(p, account, amount, reason)
  print(string.format("Spieler %s gibt %d %s aufgrund von %s.", FW.Player.getName(p), amount, account, reason))
  return originalAdd(p, account, amount, reason)
end
  • Testen: Schreibe Unit-Tests für deine Scripts, um sicherzustellen, dass sie korrekt funktionieren, unabhängig vom zugrunde liegenden Framework. Verwende Stubs und Mocks, um die FW.*-Funktionen zu simulieren und verschiedene Szenarien zu testen. Dies hilft, Regressionen zu vermeiden und die Codequalität zu verbessern.
  • Framework-spezifische Erweiterungen: Obwohl das Ziel des Adapters ist, Framework-Agnostizismus zu erreichen, kann es in einigen Fällen erforderlich sein, auf Framework-spezifische Funktionen zuzugreifen. In diesen Fällen kannst du FW.meta.name() verwenden, um das aktuelle Framework zu ermitteln und bedingt auf dessen Funktionen zuzugreifen. Dies sollte jedoch nur als letztes Mittel verwendet werden, um die Abhängigkeit vom Framework so gering wie möglich zu halten.

Framework-spezifische Hinweise (ESX/QBCore/QBox)

  • ESX:
    • Achte auf die Version von ESX, die du verwendest. Einige APIs und Event-Namen können sich zwischen den Versionen unterscheiden.
    • Das Inventar-System in ESX kann stark angepasst sein. Überprüfe, ob die Standard-Implementierung im Adapter mit deiner ESX-Konfiguration kompatibel ist.
  • QBCore:
    • QBCore verwendet ein modulares System, bei dem viele Funktionen in separaten Ressourcen implementiert sind. Stelle sicher, dass die erforderlichen Ressourcen (z.B. qb-inventory) gestartet sind, bevor du auf deren Funktionen zugreifst.
    • Die QBCore.Functions.GetPlayer Funktion gibt ein Player-Objekt zurück. Achte auf die Namenskonvention (gross geschrieben am Anfang).
  • QBox:
    • QBox ist eine Weiterentwicklung von QBCore und teilt viele Konzepte. Die meisten Hinweise zu QBCore gelten auch für QBox.
    • QBox verwendet oft Exports, um Funktionen bereitzustellen. Stelle sicher, dass die entsprechenden Exports verfügbar sind, bevor du sie aufrufst.

Durch Beachtung dieser Punkte kannst du sicherstellen, dass deine Scripte reibungslos auf allen drei Frameworks laufen.

Previous Article

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame...

Next Article

SQL & Identifiers Migration: steam/license to citizenid

More on This Topic

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame...QBOX vs QBCore: Which FiveM Framework Should You Choose?Best QBCore Scripts 2026: Essential Server StackBest QBOX Scripts 2026: Essential Resources for Your ServerHow to Migrate ESX → QBCore the Right Way

Turn framework research into a launch-ready script stack

Use this guide to narrow the framework decision, then move into the core commercial hubs for verified scripts, curated bundles, and a faster server launch path.

Framework hub

Browse QBCore-ready scripts

Move into the QBCore landing page to compare verified scripts, framework fit, and install-ready products built for modern FiveM servers.

Open QBCore hub

Framework hub

Review the ESX script path

Use the ESX landing page to compare framework-specific resources, launch guidance, and premium products that fit ESX-first servers.

Open ESX hub

Premium catalog

Browse premium FiveM scripts

Move from research into the main shop to compare real products, framework labels, screenshots, and production-ready quality signals.

Open premium shop

Launch faster

Compare curated bundles

Bundles shorten the path from planning to launch by grouping the highest-leverage scripts into a cleaner commercial starting point.

View bundles

Disclosure: Some links below are affiliate links to FiveMX products. We may earn a commission at no extra cost to you.

Related Articles

FiveM Frameworks Explained: Complete Guide to ESX, QBCore & QBOX

FiveM Frameworks Explained: Complete Guide to ESX, QBCore & QBOX

FiveM frameworks form the backbone of roleplay servers. They're not just code libraries—they're complete systems that manage player identity, jobs, inventory, permissions,…

February 22, 2026
QBox Framework Guide: Migrate from QBCore and Boost Performance (2026)

QBox Framework Guide: Migrate from QBCore and Boost Performance (2026)

QBox has firmly established itself as the natural successor to QBCore in the FiveM roleplay ecosystem.

March 31, 2026
ESX vs QBCore vs QBOX: Technical Framework Comparison 2026

ESX vs QBCore vs QBOX: Technical Framework Comparison 2026

Choosing a framework is the single most consequential decision when building a FiveM server. It determines which scripts you can use, how your developers write code, the…

February 24, 2026
Secure CheckoutInstant AccessMoney-Back GuaranteeLifetime Updates
FiveMX

Premium FiveM scripts and mods for serious server owners.

Shop

  • Shop
  • QBCore Scripts
  • ESX Scripts
  • FiveM Scripts
  • Free Mods
  • Best Scripts & Mods

Help

  • About
  • FAQ
  • Support
  • Contact
  • Account
  • Affiliate Program

Legal

  • Privacy Policy
  • Terms of Service
  • Refund Policy
  • Cookie Policy
  • GDPR Compliance
  • DMCA
  • Imprint
  • Editorial Policy
© 2026 FiveMX. All rights reserved.·support@fivemx.com

FiveMX is not affiliated with Rockstar Games, Take-Two Interactive, or CFX.re. All trademarks are property of their respective owners.

Flash Sale — Up to 19% off!Flash Sale — 19% off!Shop Now