Poradnik ox_lib: niezbędna biblioteka FiveM dla deweloperów
Poznaj ox_lib od zera. Powiadomienia, menu kontekstowe, callbacki, strefy i eksporty, na których opierają się nowoczesne skrypty FiveM, z prawdziwymi przykładami kodu.
Agency Scripts
Założyciel i główny deweloper w Agency Scripts
Czym jest ox_lib i dlaczego warto go używać?
ox_lib to biblioteka narzędziowa open-source dla FiveM, która stała się de facto standardem w nowoczesnym tworzeniu skryptów. Zapewnia ogromny zbiór gotowych komponentów UI, funkcji pomocniczych i narzędzi wydajnościowych, które eliminują potrzebę wymyślania koła na nowo przy każdym pisanym skrypcie. Zanim powstał ox_lib, deweloperzy musieli od zera budować własne systemy powiadomień, okna dialogowe, paski postępu i menu kontekstowe, co często prowadziło do niespójnego UI między różnymi skryptami na tym samym serwerze. ox_lib rozwiązuje ten problem, oferując ujednolicony, dopracowany zestaw komponentów, które wyglądają profesjonalnie i działają niezawodnie od razu po instalacji. Obsługuje zarówno Lua, jak i JavaScript, współpracuje z dowolnym frameworkiem (QBCore, ESX lub standalone) i jest aktywnie rozwijany przez zespół Overextended. Jeśli tworzysz skrypty FiveM w 2026 roku i nie korzystasz z ox_lib, marnujesz czas na budowanie rzeczy, które już istnieją.
Konfiguracja ox_lib w twoim zasobie
Dodanie ox_lib do Twojego zasobu wymaga tylko dwóch kroków: dodania zależności do Twojego fxmanifest.lua oraz wywoływanie biblioteki w Twoich skryptach. @ox_lib/init.lua import daje dostęp do wszystkich współdzielonych narzędzi, podczas gdy system modułów pozwala selektywnie ładować tylko te funkcje, których potrzebujesz. Dzięki temu Twój zasób pozostaje lekki, ponieważ nieużywane moduły nigdy nie są ładowane. Upewnij się, że ox_lib jest uruchamiany przed Twoim zasobem w server.cfg, umieszczając ensure ox_lib powyżej Twoich własnych resources. Oto minimalna konfiguracja dla nowego resource korzystającego z ox_lib:
-- 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'
Powiadomienia: czyste, spójne alerty
Powiadomienia ox_lib zastępują brzydkie, domyślne wiadomości na czacie i niestandardowe wyskakujące okienka NUI używane przez większość skryptów. Pojawiają się jako eleganckie komunikaty toast z ikonami, kolorami i automatycznym zamykaniem. Możesz ustawić pozycję, czas trwania, typ (success, error, warning, info), a nawet dodać opis pod tytułem. System powiadomień działa wyłącznie po stronie klienta (client-side) i jest niezwykle lekki, praktycznie nie obciążając twojego skryptu. Powiadomienia są najczęściej używaną funkcją ox_lib i powinny być twoim domyślnym sposobem przekazywania informacji zwrotnych graczom w każdym tworzonym skrypcie.
-- 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)
Menu kontekstowe: interaktywne listy opcji
Menu kontekstowe to przewijane listy opcji, w które gracze mogą klikać, aby wywołać akcje. Sprawdzają się idealnie w menu prac, interfejsach sklepów, opcjach pojazdów oraz w każdej sytuacji, gdy gracz musi wybrać spośród wielu akcji. Każda pozycja menu może mieć ikonę, opis, metadane wyświetlane po prawej stronie oraz zagnieżdżone podmenu do porządkowania złożonych drzew opcji. Menu pozostaje otwarte, dopóki gracz wyraźnie go nie zamknie lub nie wybierze opcji niebędącej podmenu, co czyni je idealnym do przeglądania kategorii przedmiotów. Menu kontekstowe można również generować dynamicznie na podstawie danych z serwera, dzięki czemu możesz tworzyć menu sklepów odzwierciedlające stan magazynowy z bazy danych w czasie rzeczywistym.
-- 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')
Paski i okręgi postępu
Paski postępu zapewniają wizualną informację zwrotną podczas czynności wymagających czasu, takich jak wytrychowanie, crafting, naprawa pojazdów czy gotowanie jedzenia. ox_lib oferuje zarówno pasek liniowy, jak i wskaźnik kołowy. Podczas animacji postępu możesz zablokować sterowanie gracza, na przykład poruszanie się, walkę i wsiadanie do pojazdu, aby zapobiec exploitom. Możesz także przypisać do gracza animację oraz prop, dzięki czemu będzie widocznie wykonywać daną akcję w trakcie zapełniania się paska. Funkcja zwraca true jeśli gracz anulował akcję (na przykład poruszając się) i false jeśli zakończyło się pomyślnie. Zawsze sprawdzaj tę wartość zwracaną, aby uniknąć przyznawania przedmiotów lub kończenia akcji przerwanych przez gracza.
-- 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
Okna dialogowe input: zbieranie danych gracza
Okna dialogowe pozwalają zbierać od graczy wpisany tekst, liczby, wybory z listy rozwijanej, checkboxy, próbniki kolorów, daty oraz wartości suwaków za pomocą przejrzystego interfejsu modalnego. Jest to kluczowe dla skryptów wymagających danych od gracza, takich jak ustalanie ceny domu, wprowadzanie tablicy rejestracyjnej, nazywanie gangu czy konfiguracja ustawień pracy. Każde pole wejściowe posiada etykietę, opcjonalny opis, flagę wymagalności oraz opcje specyficzne dla danego typu, np. wartości min/max dla liczb lub predefiniowane opcje dla list rozwijanych. Funkcja zwraca nil jeśli gracz anuluje okno dialogowe, oraz tablicę wartości w kolejności pól po zatwierdzeniu. Zawsze weryfikuj zwrócone dane zarówno po stronie klienta, jak i serwera, aby zapobiec exploitom.
-- 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,
})
Strefy: wydajne wykrywanie obszarów
Strefy ox_lib zastępują starą, niewydajną metodę sprawdzania pozycji gracza w każdej klatce za pomocą GetEntityCoords oraz obliczeń odległości. System stref wykorzystuje zoptymalizowany algorytm wykrywania przestrzennego, który sprawdza współrzędne tylko w konfigurowalnych odstępach czasu i wyzwala callbacki enter/exit, gdy gracze przekraczają granice strefy. Możesz definiować strefy jako kule, prostopadłościany lub wielokąty, dzięki czemu są wystarczająco elastyczne dla wszystkiego: od małych punktów interakcji po duże granice dzielnic. Strefy obsługują rotację, rysowanie debugowania podczas developmentu oraz dowolne dane przekazywane do callbacków. Dla każdego skryptu, który musi wykrywać obecność gracza w określonym obszarze, strefy ox_lib są najbardziej wydajnym dostępnym rozwiązaniem.
-- 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: inteligentny dostęp do danych
Ten lib.cache moduł zapewnia natychmiastowy dostęp do często potrzebnych danych gracza bez konieczności wywoływania funkcji natywnych w każdej klatce. Wartości takie jak cache.ped, cache.vehicle, cache.seat, cache.weapon, oraz cache.playerId są automatycznie aktualizowane przez ox_lib za pomocą event listenerów zamiast odpytywania. Oznacza to, że możesz bezpiecznie odczytywać cache.vehicle w dowolnym miejscu kodu bez obaw o wydajność. Cache wywołuje również zdarzenia przy zmianie wartości, więc możesz zarejestrować handlery dla ox_lib:cache:vehicle aby reagować na wejście lub wyjście gracza z pojazdu. W połączeniu ze strefami i resztą ox_lib, system cache pozwala pisać przejrzysty, sterowany zdarzeniami kod zamiast pętli sprawdzających co klatkę, które marnują cykle procesora na sprawdzanie rzadko zmieniających się warunków.
-- 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)