دليل ox_lib: المكتبة الأساسية لمطوري FiveM
تعلم ox_lib من الصفر. الإشعارات، قوائم السياق، ردود النداء، المناطق والتصديرات التي تعتمد عليها سكريبتات FiveM الحديثة، مع أمثلة شفرة حقيقية.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
ما هو ox_lib ولماذا يجب عليك استخدامه؟
ox_lib هي مكتبة أدوات مفتوحة المصدر لـ FiveM أصبحت المعيار الفعلي لتطوير السكربتات الحديثة. توفر مجموعة ضخمة من مكونات واجهة المستخدم الجاهزة، وظائف الأدوات، وأدوات الأداء التي تلغي الحاجة لإعادة اختراع العجلة مع كل سكربت تكتبه. قبل وجود ox_lib، كان على المطورين بناء أنظمة إشعاراتهم الخاصة، حوارات الإدخال، أشرطة التقدم، وقوائم السياق من الصفر، مما أدى غالبًا إلى واجهات مستخدم غير متناسقة عبر السكربتات المختلفة على نفس الخادم. تحل ox_lib هذه المشكلة من خلال توفير مجموعة موحدة ومصقولة من المكونات التي تبدو احترافية وتعمل بشكل موثوق مباشرة. تدعم كل من Lua وJavaScript، وتعمل مع أي إطار عمل (QBCore، ESX، أو standalone)، ويتم صيانتها بنشاط من قبل فريق Overextended. إذا كنت تكتب سكربتات FiveM في 2026 ولا تستخدم ox_lib، فأنت تقضي وقتًا غير ضروري في بناء أشياء موجودة بالفعل.
إعداد ox_lib في المورد الخاص بك
إضافة ox_lib إلى المورد الخاص بك يتطلب خطوتين فقط: إضافة التبعية إلى fxmanifest.lua واستدعاء المكتبة في سكريبتاتك. ال @ox_lib/init.lua يمنحك الاستيراد الوصول إلى جميع الأدوات المشتركة، بينما يتيح لك نظام الوحدات تحميل الميزات التي تحتاجها فقط بشكل انتقائي. هذا يحافظ على خفة المورد الخاص بك لأن الوحدات غير المستخدمة لا يتم تحميلها أبدًا. تأكد من بدء ox_lib قبل المورد الخاص بك في server.cfg الخاص بك بوضع ensure ox_lib فوق مواردك المخصصة. هذا هو الإعداد الأدنى لمورد جديد يستخدم 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'
الإشعارات: تنبيهات نظيفة ومتسقة
تحل إشعارات ox_lib محل رسائل الدردشة الافتراضية القبيحة والنوافذ المنبثقة NUI المخصصة التي تستخدمها معظم السكربتات. تظهر كرسائل توست أنيقة مع أيقونات وألوان وإغلاق تلقائي. يمكنك تعيين الموقع، المدة، النوع (نجاح، خطأ، تحذير، معلومات)، وحتى إضافة وصف تحت العنوان. نظام الإشعارات يعمل على جانب العميل فقط وخفيف جدًا، ولا يضيف أي حمل تقريبًا على سكربتك. الإشعارات هي أكثر ميزات ox_lib استخدامًا ويجب أن تكون طريقتك الافتراضية للتواصل مع اللاعبين في أي سكربت تبنيه.
-- 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)
قوائم السياق: قوائم خيارات تفاعلية
قوائم السياق هي قوائم قابلة للتمرير من الخيارات التي يمكن للاعبين النقر عليها لتنفيذ إجراءات. إنها مثالية لقوائم الوظائف، واجهات المتاجر، خيارات المركبات، وأي سيناريو يحتاج فيه اللاعب لاختيار من بين عدة إجراءات. يمكن لكل عنصر في القائمة أن يحتوي على أيقونة، وصف، بيانات وصفية معروضة على الجانب الأيمن، وقوائم فرعية متداخلة لتنظيم شجرات الخيارات المعقدة. تبقى القائمة مفتوحة حتى يغلقها اللاعب صراحة أو يختار خيارًا غير فرعي، مما يجعلها مثالية لتصفح فئات العناصر. يمكن أيضًا إنشاء قوائم السياق ديناميكيًا بناءً على بيانات الخادم، بحيث يمكنك بناء قوائم المتاجر التي تعكس المخزون في الوقت الحقيقي من قاعدة بياناتك.
-- 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')
أشرطة التقدم ودوائر التقدم
توفر أشرطة التقدم ردود فعل بصرية أثناء الإجراءات المؤقتة مثل فتح الأقفال، الصنع، إصلاح المركبات، أو طهي الطعام. يوفر ox_lib شريطًا خطيًا ومؤشرًا دائريًا. أثناء تحريك شريط التقدم، يمكنك تعطيل تحكم اللاعب مثل الحركة، القتال، ودخول السيارة لمنع الاستغلال. يمكنك أيضًا إرفاق حركة وprop باللاعب ليؤدي الإجراء بشكل مرئي أثناء ملء الشريط. تُعيد الدالة true إذا ألغى اللاعب الإجراء (عن طريق الحركة، على سبيل المثال) و false إذا اكتمل بنجاح. تحقق دائمًا من قيمة الإرجاع هذه لتجنب منح العناصر أو إكمال الإجراءات التي أوقفها اللاعب.
-- 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
حوارات الإدخال: جمع بيانات اللاعب
تتيح حوارات الإدخال جمع نص مكتوب، أرقام، اختيارات منسدلة، مربعات اختيار، منتقيات ألوان، تواريخ، وقيم منزلق من اللاعبين عبر واجهة مودال نظيفة. هذا ضروري للسكريبتات التي تحتاج إدخال اللاعب مثل تعيين سعر منزل، إدخال لوحة ترخيص، تسمية عصابة، أو تكوين إعدادات الوظيفة. لكل حقل إدخال تسمية، وصف اختياري، علامة مطلوب، وخيارات خاصة بالنوع مثل القيم الدنيا/العليا للأرقام أو خيارات محددة مسبقًا للقوائم المنسدلة. الدالة تُرجع nil إذا ألغى اللاعب الحوار ومصفوفة القيم بترتيب الحقول إذا قام بالإرسال. تحقق دائمًا من صحة البيانات المرجعة على كل من العميل والخادم لمنع الاستغلال.
-- 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,
})
المناطق: كشف فعال للمناطق
تحل مناطق ox_lib محل الطريقة القديمة غير الفعالة لفحص موقع اللاعب في كل إطار مع GetEntityCoords وحساب المسافة. يستخدم نظام المناطق خوارزمية كشف مكانية محسنة تتحقق فقط من الإحداثيات على فواصل زمنية قابلة للتكوين وتفعّل ردود نداء الدخول/الخروج عندما يعبر اللاعبون حدود المنطقة. يمكنك تعريف المناطق ككرات، صناديق، أو مضلعات، مما يجعلها مرنة بما يكفي لكل شيء من نقاط التفاعل الصغيرة إلى حدود الأحياء الكبيرة. تدعم المناطق التدوير، والرسم التصحيحي للتطوير، والبيانات التعسفية التي تُمرر إلى ردود النداء. لأي سكريبت يحتاج إلى كشف متى يكون اللاعب في منطقة معينة، فإن مناطق ox_lib هي الحل الأكثر كفاءة المتاح.
-- 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)
التخزين المؤقت: وصول ذكي للبيانات
ال lib.cache الوحدة توفر وصولًا فوريًا إلى بيانات اللاعب المطلوبة بشكل متكرر دون إجراء نداءات أصلية في كل إطار. القيم مثل cache.ped, cache.vehicle, cache.seat, cache.weapon، و cache.playerId يتم تحديثها تلقائيًا بواسطة ox_lib من خلال مستمعي الأحداث بدلاً من الاستطلاع. هذا يعني أنه يمكنك قراءة بأمان cache.vehicle في أي مكان في الكود الخاص بك دون القلق بشأن الأداء. كما يطلق الكاش أحداثًا عند تغير القيم، لذا يمكنك تسجيل معالجات لـ ox_lib:cache:vehicle للاستجابة عندما يدخل اللاعب أو يخرج من مركبة. مع الجمع بين المناطق وبقية ox_lib، يتيح نظام التخزين المؤقت كتابة كود نظيف قائم على الأحداث بدلاً من حلقات الاستطلاع القائمة على الإطارات التي تهدر دورات وحدة المعالجة المركزية في التحقق من شروط نادرًا ما تتغير.
-- 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)