[Free] Ox Library - UI and Lua modules

Documentation
Repository
Download

Summary

Ox Library provides a variety of modules to utilise in other resources with the lib global. Modules are loaded into the environment of the invoking resource during runtime, 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 lines to the fxmanifest of any resource.

  • 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).

-- principal: string or false
-- command: string
-- callback: function
-- parameters: table (optional)
-- help: string (optional)
lib.addCommand(principal, command, callback, parameters, help)

lib.addCommand('group.admin', {'additem', 'giveitem'}, function(source, args)
    args.item = Items(args.item)
    if args.item and args.count > 0 then
        Inventory.AddItem(args.target, args.item.name, args.count, args.metatype)
    end
end, {'target:number', 'item:string', 'count:number', 'metatype:?string'})
Callback

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

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(self)
    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(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
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(self)
    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(self)
    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}))

image

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

image

lib.notify({
    id = 'some_identifier',
    title = 'Notification title',
    description = 'Notification description',
    position = 'top',
    style = {
        backgroundColor = '#141517',
        color = '#909296'
    },
    icon = 'ban',
    iconColor = '#C53030'
})

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

TextUI
lib.showTextUI('[E] - Fuel vehicle')
lib.hideTextUI()

image

27 Likes

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

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

: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!

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

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

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

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.

: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