[Free] ox_lib - UI and common code

Summary

Provides a variety of exports and importable modules to utilise in other resources, using the lib global (Lua) or with JS modules. Modules are loaded into the environment of the invoking resource, rather than being called by reference.

Some code is loaded internally and may be accessible through exports (such as the UI), or used by modules to listen to events or call function references.


Usage

Add the following to your server.cfg.

add_ace resource.ox_lib command.add_ace allow
add_ace resource.ox_lib command.remove_ace allow
add_ace resource.ox_lib command.add_principal allow
add_ace resource.ox_lib command.remove_principal allow

Load into your desired resources by adding the following to fxmanifest.lua.

  • lua54 'yes'
  • shared_script '@ox_lib/init.lua'
    • Should be included above other script files. Can use server_script or client_script when applicable.

Features

Not a comprehensive list; refer to the documentation for more features and explanations.

Modules

AddCommand

Register a server command and assign permissions to a group (principal).

---@param commandName string | string[]
---@param properties table false
---@param cb fun(source: number, args: table, raw: string)
lib.addCommand(commandName, properties, cb)

lib.addCommand('giveitem', {
    help = 'Gives an item to a player',
    params = {
        {
            name = 'target',
            type = 'playerId',
            help = 'Target player\'s server id', },
        {
            name = 'item',
            type = 'string',
            help = 'Name of the item to give',
        },
        {
            name = 'count',
            type = 'number',
            help = 'Amount of the item to give, or blank to give 1',
            optional = true,
        },
        {
            name = 'metatype',
            help = 'Sets the item\'s "metadata.type"',
            optional = true,
        },
    },
    restricted = 'group.admin'
}, function(source, args, raw)
    local item = Items(args.item)

    if item then
        Inventory.AddItem(args.target, item.name, args.count or 1, args.metatype)
    end
end)
Callback

Server callback events to send data to the server and receive a response. Includes a simple timer to prevent unintentional event spam. Client callback events are also available.

Server

-- name: string
-- cb: function
lib.callback.register(name, cb)

lib.callback.register('ox_inventory:getItemCount', function(source, item, metadata, target)
    local inventory = target and Inventory(target) or Inventory(source)
    return (inventory and Inventory.GetItem(inventory, item, metadata, true)) or 0
end)

Client

-- name: string
-- delay: number or false
-- cb: function
lib.callback(name, delay, cb, ...)

lib.callback('ox_inventory:getItemCount', false, function(count)
    print(count)
end, 'water', {type = 'fresh'})
-- name: string
-- delay: number or false
lib.callback.await(name, delay, ...)

local count = lib.callback.await('ox_inventory:getItemCount', false, 'water', {type = 'fresh'})
print(count)
Points

Wrapper around distance checks. Works similarly to lib.zones.sphere.
Any arbitrary data can be included in the table for easy reference.

local point = lib.points.new({
    coords = vec3(442.5363, -1017.666, 28.65637),
    distance = 8,
    dunak = 'nerd'
})

function point:onEnter()
    print('entered range of point', self.id)
end

function point:onExit()
    print('left range of point', self.id)
end

function point:nearby()
    DrawMarker(2, self.coords.x, self.coords.y, self.coords.z, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 1.0, 1.0, 1.0, 200, 20, 20, 50, false, true, 2, nil, nil, false)

    if self.currentDistance < 1 and IsControlJustReleased(0, 38) then
        print('dunak is a '..self.dunak)
    end
end
Zones

Similar to PolyZone, but utilises the GLM library. API is not, and will never be, 1:1.

Box
local box = lib.zones.box({
    coords = vec3(442.5363, -1017.666, 28.65637),
    size = vec3(1, 1, 1),
    rotation = 45,
    debug = true
})

function box:onEnter()
    print('entered zone', self.id)
end

function box:onExit()
    print('exited zone', self.id)
end

function box:inside()
    print('you are inside zone ' .. self.id)
end
Poly
local poly = lib.zones.poly({
    points = {
        vec(413.8, -1026.1, 29),
        vec(411.6, -1023.1, 29),
        vec(412.2, -1018.0, 29),
        vec(417.2, -1016.3, 29),
        vec(422.3, -1020.0, 29),
        vec(426.8, -1015.9, 29),
        vec(431.8, -1013.0, 29),
        vec(437.3, -1018.4, 29),
        vec(432.4, -1027.2, 29),
        vec(424.7, -1023.5, 29),
        vec(420.0, -1030.2, 29),
        vec(409.8, -1028.4, 29),
    },
  thickness = 2,
    debug = true
})

function poly:onEnter()
    print('entered zone', self.id)
end

function poly:onExit()
    print('exited zone', self.id)
end

function poly:inside()
    print('you are inside zone ' .. self.id)
end
Sphere

Just a distance check under the hood. Almost 1:1 with the points module.

local sphere = lib.zones.sphere({
    coords = vec3(442.5363, -1017.666, 28.65637),
    radius = 1,
    debug = true
})

function sphere:onEnter()
    print('entered zone', self.id)
end

function sphere:onExit()
    print('exited zone', self.id)
end

function sphere:inside()
    print('you are inside zone ' .. self.id)
end

UI

Context menu
RegisterCommand('testcontext', function()
    lib.registerContext({
        id = 'example_menu',
        title = 'Example Context',
        options = {
            {title = 'Empty button'},
            {
                title = 'Example button',
                description = 'Example button description',
                metadata = {
                    {label = 'Value 1', value = 'Some value'},
                    {label = 'Value 2', value = 300},
                }
            },
            {
                title = 'Menu button',
                menu = 'other_example_menu',
                description = 'Takes you to another menu!',
                metadata = {'It also has metadata support'}
            },
            {
                title = 'Event button',
                description = 'Open a menu and send event data',
                arrow = true,
                event = 'some_event',
                args = {value1 = 300, value2 = 'Other value'}
            }
        },
        {
            id = 'other_example_menu',
            title = 'Other Context Menu',
            menu = 'example_menu',
            options = {
                ['Nothing here'] = {}
            }
        }
    })
    lib.showContext('example_menu')
end)

image

Input
local input = lib.inputDialog('Police locker', {
    { type = "input", label = "Locker number" },
    { type = "checkbox", label = "Some checkbox" },
    { type = "input", label = "Locker PIN", password = true, icon = 'lock' },
    { type = "checkbox", label = "Some other checkbox" },
    { type = 'select', label = 'Value select', options = {
        { value = 'option1', label = 'Option 1' },
        { value = 'option2', label = 'Option 2' },
        { value = 'option3', label = 'Option 3'},
    }}
})
print(json.encode(input, {indent=true}))

Notifications
lib.notify({
    title = 'Notification title',
    description = 'Notification description',
    type = 'success'
})

image

Progress bar/circle
local success = lib.progressBar({
    duration = 2000,
    label = 'Drinking water',
    useWhileDead = false,
    canCancel = true,
    disable = {
        car = true,
    },
    anim = {
        dict = 'mp_player_intdrink',
        clip = 'loop_bottle' 
    },
    prop = {
        model = `prop_ld_flow_bottle`,
        pos = vec3(0.03, 0.03, 0.02),
        rot = vec3(0.0, 0.0, -1.5) 
    },
})

if success then
    print('Do stuff when complete')
else
    print('Do stuff when cancelled')
end

image

local success = lib.progressCircle({
    duration = 2000,
    position = 'bottom',
    useWhileDead = false,
    canCancel = true,
    disable = {
        car = true,
    },
    anim = {
        dict = 'mp_player_intdrink',
        clip = 'loop_bottle' 
    },
    prop = {
        model = `prop_ld_flow_bottle`,
        pos = vec3(0.03, 0.03, 0.02),
        rot = vec3(0.0, 0.0, -1.5) 
    },
})

if success then
    print('Do stuff when complete')
else
    print('Do stuff when cancelled')
end

image

Skill check
local success = lib.skillCheck({'easy', 'easy', {areaSize = 60, speedMultiplier = 2}, 'hard'}, {'w', 'a', 's', 'd'})

image

52 Likes

:ox: :ox: :ox: :ox:

1 Like

:ox: :ox: :ox: :ox:

1 Like

:ox: :ox: :ox: :ox:

:ox: :ox: :ox: :ox:

Hello,

I tried this lib but couldn’t use “lib.disableControls ()”.
My attempt:

fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_scripts {
	'@es_extended/imports.lua',
	'@ox_lib/init.lua',
}

client_scripts {
    'config.lua',
    'client.lua'
}

server_scripts{
	'@oxmysql/lib/MySQL.lua',
    'config.lua',
    'server.lua'
}

client.lua

local _PlayerPedId

Citizen.CreateThread(function()
	_PlayerPedId = PlayerPedId()
	local state = GetPedParachuteState(_PlayerPedId)
	while state ~= -1 do
		Citizen.Wait(0)
		state = GetPedParachuteState(_PlayerPedId)
	
		if state ~= -1 then
			lib.disableControls:Add(157, 158, 160, 164, 289, 45)
		else
			lib.disableControls:Remove(157, 158, 160, 164, 289, 45)
		end
	end
end)

Anyone can help me?

1 Like

you need to call this every frame: Client | Overextended

I need to expand documentation a bit more to better explain some things (and give examples).

DisableControls lets you quickly define additional controls to add into an array from elsewhere in your code; you then add lib.disableControls() into a thread that executes on every frame.

I use it in statebag change handlers or events to say what I want to disable, while actually disabling them as part of my “main” thread.

1 Like

Hi Linden,

Thanks for the quick reply so I understand.

Thank you Linda, very cool!

1 Like

:ox: :ox: :ox: :ox:

:ox::ox::ox::ox::ox:

:ox: :ox: :ox: :ox:

1 Like

Examples are there already :person_shrugging:

local box = lib.zones.box({
    coords = vec3(442.5363, -1017.666, 28.65637),
    size = vec3(1, 1, 1),
    rotation = 45,
    debug = true
})

function box:onEnter(self)
    print('entered zone', self.id)
end

function box:onExit()
    print('exited zone', self.id)
end

function box:inside()
    print('you are inside zone ' .. self.id)
end

Creates a box in the MRPD parking lot, expanding from the given coordinates (0.5 units in each direction).
Walking into it triggers box:onEnter once and box:inside repeatedly, until you leave.

1 Like

:ox: :ox: :ox: :ox:

:ox: :ox: :ox: :ox:

:orangutan::orangutan::orangutan::orangutan::orangutan:

Any idea?


Make sure you downloaded the release and not source code.

I’ve done that

1 Like