ox_lib-Leitfaden: Die unverzichtbare FiveM-Bibliothek für Entwickler
Lerne ox_lib von Grund auf: Benachrichtigungen, Kontextmenüs, Rückrufe, Zonen und Exports, auf die moderne FiveM-Skripte setzen.
Agency Scripts
Gründer und leitender Entwickler bei Agency Scripts
Was ist ox_lib und warum solltest du es verwenden?
ox_lib ist eine Open-Source-Utility-Bibliothek für FiveM, die sich zum De-facto-Standard für die moderne Script-Entwicklung entwickelt hat. Sie bietet eine umfangreiche Sammlung vorgefertigter UI-Komponenten, Utility-Funktionen und Performance-Tools. Damit musst du das Rad nicht für jedes Script neu erfinden. Bevor es ox_lib gab, mussten Entwickler eigene Benachrichtigungssysteme, Eingabedialoge, Fortschrittsbalken und Kontextmenüs von Grund auf erstellen. Das führte oft zu uneinheitlichen UIs zwischen verschiedenen Scripts auf demselben Server. ox_lib löst dieses Problem mit einer einheitlichen, ausgereiften Sammlung von Komponenten, die professionell aussehen und sofort zuverlässig funktionieren. Die Bibliothek unterstützt Lua und JavaScript, funktioniert mit jedem Framework (QBCore, ESX oder standalone) und wird vom Overextended-Team aktiv gepflegt. Wenn du 2026 FiveM-Scripts schreibst und ox_lib nicht verwendest, investierst du unnötig Zeit in die Entwicklung von Funktionen, die es bereits gibt.
ox_lib in deiner Resource einrichten
ox_lib in deine Resource einzubinden, erfordert nur zwei Schritte: Füge die Abhängigkeit zu deiner fxmanifest.lua hinzu und rufe die Bibliothek in deinen Scripts auf. Der @ox_lib/init.lua -Import gibt dir Zugriff auf alle gemeinsam genutzten Utilities, während du mit dem Modulsystem gezielt nur die Funktionen laden kannst, die du brauchst. So bleibt deine Resource schlank, da ungenutzte Module nicht geladen werden. Achte darauf, dass ox_lib in deiner server.cfg vor deiner Resource gestartet wird, indem du ensure ox_lib oberhalb deiner eigenen Resources platzierst. Hier ist die minimale Einrichtung für eine neue Resource, die ox_lib verwendet:
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
name 'my-awesome-script'
version '1.0.0'
-- Required: import ox_lib
shared_scripts {
'@ox_lib/init.lua',
'config.lua',
}
client_scripts {
'client/*.lua',
}
server_scripts {
'server/*.lua',
}
-- Declare ox_lib as a dependency
dependencies {
'ox_lib',
}
-- Enable ox_lib locale system (optional)
lua54 'yes'
Benachrichtigungen: übersichtliche, einheitliche Hinweise
Benachrichtigungen von ox_lib ersetzen die unschönen Standard-Chatnachrichten und benutzerdefinierten NUI-Pop-ups, die in den meisten Scripts zum Einsatz kommen. Sie werden als elegante Toast-Nachrichten mit Symbolen und Farben angezeigt und schließen sich automatisch. Du kannst Position, Dauer und Typ (Erfolg, Fehler, Warnung, Info) festlegen und sogar eine Beschreibung unter dem Titel hinzufügen. Das Benachrichtigungssystem läuft ausschließlich clientseitig und ist äußerst leichtgewichtig, wodurch dein Script praktisch nicht zusätzlich belastet wird. Benachrichtigungen sind die am häufigsten verwendete ox_lib-Funktion und sollten deine erste Wahl sein, wenn du Spielern in deinen Scripts Rückmeldungen gibst.
-- client.lua: Notification examples
-- Simple notification
lib.notify({
title = 'Vehicle Stored',
description = 'Your vehicle has been stored in the garage.',
type = 'success', -- 'success' | 'error' | 'warning' | 'info'
duration = 5000, -- milliseconds
position = 'top-right', -- 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left'
})
-- Error notification with icon
lib.notify({
title = 'Access Denied',
description = 'You do not have the required key.',
type = 'error',
icon = 'lock',
iconColor = '#ff4444',
})
-- Notification from server side
-- server.lua
RegisterNetEvent('garage:store', function()
local src = source
TriggerClientEvent('ox_lib:notify', src, {
title = 'Garage',
description = 'Vehicle stored successfully.',
type = 'success',
})
end)
Kontextmenüs: interaktive Optionslisten
Kontextmenüs sind scrollbare Optionslisten, auf die Spieler klicken können, um Aktionen auszulösen. Sie eignen sich ideal für Jobmenüs, Shop-Oberflächen, Fahrzeugoptionen und alle Situationen, in denen ein Spieler aus mehreren Aktionen auswählen muss. Jeder Menüpunkt kann ein Symbol, eine Beschreibung und rechts angezeigte Metadaten enthalten. Außerdem kannst du Untermenüs einrichten, um komplexe Optionsstrukturen zu organisieren. Das Menü bleibt geöffnet, bis der Spieler es ausdrücklich schließt oder eine Option ohne Untermenü auswählt. Dadurch eignet es sich ideal zum Durchstöbern von Artikelkategorien. Kontextmenüs lassen sich auch dynamisch anhand von Serverdaten erstellen. So kannst du Shopmenüs erstellen, die den aktuellen Bestand aus deiner Datenbank anzeigen.
-- client.lua: Context menu examples
-- Simple shop menu
lib.registerContext({
id = 'weapons_shop',
title = 'Ammu-Nation',
options = {
{
title = 'Pistol',
description = 'Standard 9mm handgun',
icon = 'gun',
metadata = {
{label = 'Price', value = '$2,500'},
{label = 'Ammo', value = '12 rounds'},
},
onSelect = function()
TriggerServerEvent('shop:buy', 'weapon_pistol')
end,
},
{
title = 'Body Armor',
description = 'Standard kevlar vest',
icon = 'shield',
metadata = {
{label = 'Price', value = '$5,000'},
{label = 'Protection', value = '50%'},
},
onSelect = function()
TriggerServerEvent('shop:buy', 'armor')
end,
},
{
title = 'Attachments',
description = 'Browse weapon modifications',
icon = 'wrench',
arrow = true, -- Shows arrow indicating submenu
menu = 'attachments_submenu',
},
},
})
lib.showContext('weapons_shop')
Fortschrittsbalken und Fortschrittskreise
Fortschrittsanzeigen geben visuelles Feedback bei zeitgebundenen Aktionen wie Schlösserknacken, Herstellen, Fahrzeugreparaturen oder Kochen. ox_lib bietet sowohl einen linearen Balken als auch eine kreisförmige Anzeige. Während der Fortschrittsanimation kannst du Spielersteuerungen wie Bewegung, Kämpfen und Fahrzeugeinstieg deaktivieren, um Exploits zu verhindern. Du kannst dem Spieler auch eine Animation und ein Prop zuweisen, damit er die Aktion sichtbar ausführt, während sich der Balken füllt. Die Funktion gibt true zurück, wenn der Spieler die Aktion abgebrochen hat, zum Beispiel durch Bewegung, und false wenn sie erfolgreich abgeschlossen wurde. Prüfe diesen Rückgabewert immer, damit du keine Items vergibst oder Aktionen abschließt, die der Spieler abgebrochen hat.
-- client.lua: Progress bar examples
-- Linear progress bar with animation
local cancelled = lib.progressBar({
duration = 8000,
label = 'Lockpicking door...',
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
},
anim = {
dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
clip = 'machinic_loop_mechandler',
},
prop = {
model = 'prop_lockpick_01',
bone = 57005,
pos = vec3(0.14, 0.0, -0.01),
rot = vec3(0.0, 0.0, 0.0),
},
})
if cancelled then
lib.notify({ title = 'Cancelled', type = 'error' })
else
lib.notify({ title = 'Door Unlocked', type = 'success' })
TriggerServerEvent('lockpick:success', doorId)
end
-- Circular progress (useful for quick actions)
if lib.progressCircle({
duration = 2000,
label = 'Searching...',
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { move = true },
}) then
lib.notify({ title = 'Search cancelled', type = 'error' })
else
TriggerServerEvent('search:complete')
end
Eingabedialoge: Spielerdaten erfassen
Mit Eingabedialogen kannst du über eine übersichtliche modale Oberfläche Texte, Zahlen, Dropdown-Auswahlen, Kontrollkästchen, Farbwähler, Datumsangaben und Schiebereglerwerte von Spielern erfassen. Das ist wichtig für Scripts, die Spielereingaben benötigen, etwa zum Festlegen eines Hauspreises, Eingeben eines Kennzeichens, Benennen einer Gang oder Konfigurieren von Jobeinstellungen. Jedes Eingabefeld hat eine Beschriftung, eine optionale Beschreibung, eine Angabe dazu, ob es erforderlich ist, und typspezifische Optionen wie Mindest- und Höchstwerte für Zahlen oder vordefinierte Dropdown-Optionen. Die Funktion gibt nil zurück, wenn der Spieler den Dialog abbricht. Bei einer Eingabe gibt sie ein Array mit den Werten in der Reihenfolge der Felder zurück. Validiere die zurückgegebenen Daten immer sowohl client- als auch serverseitig, um Exploits zu verhindern.
-- client.lua: Input dialog examples
-- Vehicle listing form
local input = lib.inputDialog('List Vehicle for Sale', {
{ type = 'input', label = 'Title', description = 'Name for the listing', required = true, max = 50 },
{ type = 'number', label = 'Price ($)', description = 'Asking price', required = true, min = 1000, max = 10000000 },
{ type = 'select', label = 'Condition', options = {
{ value = 'new', label = 'Brand New' },
{ value = 'used', label = 'Used - Good' },
{ value = 'damaged', label = 'Damaged' },
}},
{ type = 'textarea', label = 'Description', description = 'Describe your vehicle', max = 500 },
{ type = 'checkbox', label = 'I agree to the marketplace terms' },
})
if not input then return end -- Player cancelled
local title, price, condition, description, agreedTerms = table.unpack(input)
if not agreedTerms then
lib.notify({ title = 'You must agree to the terms', type = 'error' })
return
end
TriggerServerEvent('marketplace:list', {
title = title,
price = price,
condition = condition,
description = description,
})
Zonen: effiziente Bereichserkennung
ox_lib-Zonen ersetzen die alte, ineffiziente Methode, die Spielerposition mit GetEntityCoords und Distanzberechnungen in jedem Frame zu prüfen. Das Zonensystem verwendet einen optimierten Algorithmus zur räumlichen Erkennung, der Koordinaten nur in konfigurierbaren Intervallen prüft und beim Überschreiten von Zonengrenzen Rückrufe für das Betreten und Verlassen auslöst. Du kannst Zonen als Kugeln, Boxen oder Polygone definieren. Damit eignen sie sich für alles, von kleinen Interaktionspunkten bis hin zu großen Nachbarschaftsgrenzen. Zonen unterstützen Rotation, Debug-Anzeige für die Entwicklung und beliebige Daten, die an die Rückrufe übergeben werden. Für jedes Script, das erkennen muss, ob sich ein Spieler in einem bestimmten Bereich befindet, bieten ox_lib-Zonen die beste Performance.
-- client.lua: Zone examples
-- Sphere zone for a shop entrance
local shopZone = lib.zones.sphere({
coords = vec3(25.7, -1347.3, 29.5),
radius = 3.0,
debug = true, -- Set false in production
onEnter = function(self)
lib.notify({ title = 'Press [E] to open shop', type = 'info' })
lib.showTextUI('[E] Open Shop', { position = 'right-center' })
end,
onExit = function(self)
lib.hideTextUI()
end,
})
-- Box zone with rotation for a parking spot
local parkingZone = lib.zones.box({
coords = vec3(215.3, -810.0, 30.7),
size = vec3(6.0, 3.0, 2.0),
rotation = 70.0,
debug = true,
onEnter = function(self)
lib.showTextUI('[E] Store Vehicle')
end,
onExit = function(self)
lib.hideTextUI()
end,
})
-- Clean up zones when resource stops
AddEventHandler('onResourceStop', function(resource)
if resource == GetCurrentResourceName() then
shopZone:remove()
parkingZone:remove()
end
end)
Cache: intelligenter Datenzugriff
Die lib.cache Das Modul bietet sofortigen Zugriff auf häufig benötigte Spielerdaten, ohne native Aufrufe in jedem Frame auszuführen. Werte wie cache.ped, cache.vehicle, cache.seat, cache.weapon , und cache.playerId werden von ox_lib automatisch über Event-Listener aktuell gehalten, statt sie regelmäßig abzufragen. So kannst du cache.vehicle an jeder Stelle in deinem Code sicher auslesen, ohne dir Gedanken über die Performance machen zu müssen. Der Cache löst auch Events aus, wenn sich Werte ändern. So kannst du Handler für ox_lib:cache:vehicle registrieren und darauf reagieren, wenn ein Spieler in ein Fahrzeug ein- oder aussteigt. In Kombination mit Zonen und den übrigen Funktionen von ox_lib ermöglicht dir das Cachesystem, übersichtlichen, ereignisgesteuerten Code zu schreiben, statt framebasierte Abfrageschleifen zu verwenden, die CPU-Zyklen mit der Prüfung von Bedingungen verschwenden, die sich nur selten ändern.
-- client.lua: Cache examples
-- Access cached values (no native calls needed)
local myPed = cache.ped
local myVehicle = cache.vehicle -- nil if not in a vehicle
local mySeat = cache.seat -- -1 = driver, 0 = front passenger, etc.
local myWeapon = cache.weapon
-- React to vehicle changes
lib.onCache('vehicle', function(vehicle)
if vehicle then
-- Player entered a vehicle
local plate = GetVehicleNumberPlateText(vehicle)
lib.notify({
title = 'Vehicle',
description = 'Plate: ' .. plate,
type = 'info',
})
else
-- Player exited a vehicle
lib.notify({ title = 'On foot', type = 'info' })
end
end)
-- React to weapon changes
lib.onCache('weapon', function(weapon)
if weapon then
print('Player equipped weapon:', weapon)
end
end)