ox_lib指南:FiveM开发者必备库
从零开始学习ox_lib。通知、上下文菜单、回调、区域和导出,现代FiveM脚本依赖的功能,附真实代码示例。
Agency Scripts
Agency Scripts 创始人兼首席开发者
什么是 ox_lib,为什么要使用?
ox_lib 是一个开源的 FiveM 实用库,已成为现代脚本开发的事实标准。它提供大量预构建的 UI 组件、实用函数和性能工具,免去每次编写脚本时重复造轮子的麻烦。在 ox_lib 出现之前,开发者必须从零构建通知系统、输入对话框、进度条和上下文菜单,导致同一服务器上不同脚本的 UI 不一致。ox_lib 通过提供统一且精致的组件集解决了这一问题,这些组件外观专业且开箱即用,支持 Lua 和 JavaScript,兼容任何框架(QBCore、ESX 或 standalone),由 Overextended 团队积极维护。如果你在 2026 年编写 FiveM 脚本却不使用 ox_lib,就会浪费时间重复构建已有功能。
在您的资源中设置 ox_lib
将 ox_lib 集成到您的资源只需两步:将依赖项添加到您的 fxmanifest.lua 并在您的脚本中调用库。 @ox_lib/init.lua import让您访问所有共享实用程序,而模块系统允许您选择性加载仅需的功能。这保持了资源的轻量,因为未使用的模块永远不会被加载。确保在server.cfg中将ox_lib放在您的资源之前启动,方法是放置 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 提供线性条和圆形指示器。在进度动画期间,可以禁用玩家控制如移动、战斗和车辆进入以防止利用。还可以附加动画和道具到玩家,使其在进度条填充时可见地执行动作。该函数返回 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 的其余部分,缓存系统让你编写干净的事件驱动代码,而非浪费 CPU 周期检查很少变化条件的帧轮询循环。
-- 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)