Don's Utility Functions for FiveM
Has you're script gone up the duff? Well, this is the solution for you! This is a collection of optimised utility modules for FiveM, to be imported and used in your scripts. It's designed to be lightweight, and easy to use, with a focus on performance and efficiency.
- Require: Emulates Lua's default require function, using package.path, package.preload and package.loaded. Also precaches all modules labled as
file
in thefxmanifest.lua
and any modules that are imported using therequire
function. - Array: A class for the creation and manipulation of consecutive integer indexed arrays, providing a number of Functional Programming methods.
- Bridge: Provides common functions between different frameworks and libraries for use in creating cross-framework scripts.
- Locale: Contains functions for localisation and translation, based on the i18n.lua library by kikito.
- Math: Contains some useful math functions, including a
seedrng
function which generates a random seed based on the current time, and an improvement to the default luarandom
function. - Vector: Contains some useful vector functions, including a
getclosest
function which finds the closest vector3 in an array to a given vector3. - Blips: Contains functions for managing blips, including
getall
,onscreen
,bycoords
,bysprite
,bytype
,getinfo
andremove
. - Pools: Contains functions for managing entity pools, including
getpeds
,getvehicles
,getobjects
,getpickups
,getclosestped
,getclosestvehicle
,getclosestobject
andgetclosestpickup
. - Streaming: Contains functions for managing streaming, including
loadanimdict
,loadanimset
,loadcollision
,loadipl
,loadmodel
andloadptfx
. - Scope: Contains functions for managing scope, including
getplayerscope
,triggerscopeevent
,createsyncedscopeevent
andremovesyncedscopeevent
. - Zone: Contains functions for management of map zones similar to PolyZone but is server-side only, including
contains
,getzone
,getzonename
,getzoneindex
,addzoneevent
andremovezoneevent
.
- duff
- Always use the latest FiveM artifacts (tested on 6683), you can find them here.
- Download the latest version from releases.
- Extract the contents of the zip file into your resources folder, into a folder which starts after your framework and any script this is a dependency for, or;
- Ensure the script in your
server.cfg
after your framework and any script this is a dependency for. - If using
ox_lib
, ensure'@ox_lib/init.lua'
is uncommented in yourfxmanifest.lua
file.
Require is a function that allows you to import modules, emulating Lua Default require function, using package.path, package.preload and package.loaded. It also precaches all modules labled as file
in the fxmanifest.lua
file and any modules that are imported using the require
function.
---@param path string @The name of the module to require. This can be a path, or a module name. If a path is provided, it must be relative to the resource root.
---@return {[string]: any} module
exports.duff:require(path)
-- Using the `require` export
---@module 'duff.shared.import'
local duff = exports.duff:require 'duff.shared.import'
-- Using '@duff/shared/import.lua' in your `fxmanifest.lua`
shared_script '@duff/shared/import.lua'
array is a class for the creation and manipulation of consecutive integer indexed arrays. It provides a number of Functional Programming methods, and is designed to be used in a similar way to the Array class in JavaScript.
This is a shared module, and can be used on both the client, server and shared enviroment.
-- Using the `require` export
---@module 'duff.shared.array'
local array = exports.duff:require 'duff.shared.array'
-- Attaching array to a local variable from the duff object
local array = duff.array
Creates a new array.
---@param list any[]?
---@return array
local tbl = array.new(list)
---@param self array
---@param pos integer
---@param value any
function array.insert(self, pos, value)
---@param self array
---@param pos integer?
function array.remove(self, pos)
---@param self array
---@param compare fun(a: any, b: any): boolean
function array.sort(self, compare)
---@param self array
---@param sep any?
---@param i integer?
---@param j integer?
function array.concat(self, sep, i, j)
Checks if a table is an array.
---@param tbl any[]|array
---@return boolean?
function array.isarray(tbl)
Adds one or more elements to the end of the array.
---@param self array
---@param arg any?
---@param ... any?
---@return array
function array.push(self, arg, ...)
Adds all elements from a table to the end of the array.
---@param self array
---@param list any[]
---@return array
function array.pusharray(self, list)
Returns the element at the specified index without removing it.
---@param self array
---@param index integer?
---@return any
function array.peek(self, index)
Returns a new array containing the elements from the specified index to the end of the array.
---@param self array
---@param index integer?
---@return any[]
function array.peekarray(self, index)
Removes and returns the element at the specified index.
---@param self array
---@param index integer?
---@return any?, array?
function array.pop(self, index)
Removes and returns a new array containing the elements from the specified index to the end of the array.
---@param self array
---@param index integer?
---@return array
function array.poparray(self, index)
Checks if the array contains a specific element or key or key-value pair.
---@param self array
---@param key integer?
---@param value any?
---@return boolean?
function array.contains(self, key, value)
Creates a shallow copy of the array.
---@param self array
---@return array
function array.copy(self)
Searches for the first element that satisfies a given condition and returns its index.
---@param self array
---@param func fun(val: any, i: integer): boolean
---@return integer?
function array.find(self, func)
Applies a function to each element from left to right, accumulating a result.
---@param self array
---@param func fun(acc: any, val: any): any
---@param arg any?
function array.foldleft(self, func, arg)
Applies a function to each element from right to left, accumulating a result.
---@param self array
---@param func fun(acc: any, val: any): any
---@param arg any?
function array.foldright(self, func, arg)
Creates a read-only array that can be used for enumeration.
---@param self array
---@return array enum
function array.setenum(self)
Applies a function to each element and returns a new array with the results.
---@param self array
---@param func fun(val: any): any
---@param inPlace boolean?
---@return array
function array.map(self, func, inPlace)
Returns a new array containing only the elements that satisfy a given condition.
---@param self array
---@param func fun(val: any, i: integer): boolean
---@param inPlace boolean?
---@return array
function array.filter(self, func, inPlace)
Executes a function for each element across the array.
---@param self array
---@param func fun(val: any, i: integer)
function array.foreach(self, func)
Reverses the order of elements.
---@param self array
---@param length integer?
---@return array
function array.reverse(self, length)
bridge is a class that provides common functions between different frameworks and libraries for use in creating cross-framework scripts. It currently has limited scope, managing player job/gang data, retreiving the core framework and some exposed methods between comon Inventory and Target scripts.
-- Using the `require` export
---@module 'duff.shared.bridge'
local bridge = exports.duff:require 'duff.shared.bridge'
-- Attaching the bridge to a local variable from the duff object
local bridge = duff.bridge
The _DATA
table is used to store common data for the bridge class.
---@class _DATA
---@field FRAMEWORK 'esx'|'qb'?
---@field INVENTORY 'ox'?
---@field LIB 'ox'?
---@field EVENTS {LOAD: string?, UNLOAD: string?, JOBDATA: string?, PLAYERDATA: string?, UPDATEOBJECT: string?}
---@field EXPORTS {CORE: {resource: string, method: string}, INV: {resource: string, method: string}, TARG: {resource: string, method: string}}
---@field ITEMS {[string]: {name: string, label: string, weight: number, useable: boolean, unique: boolean}}?
- The
FRAMEWORK
field is used to store the name of the core framework being used. - The
INVENTORY
field is used to store the name of the inventory framework being used. - The
LIB
field is used to store the name of the library being used. - The
EVENTS
table is used to store common event names, with theLOAD
,UNLOAD
,JOBDATA
andPLAYERDATA
being available on the client side, and theUPDATEOBJECT
being a shared element. - The
EXPORTS
table is used to store common exports. - The
ITEMS
table is only available on the server side, and is used to store item data for use in the inventory system.
Retrieves the core framework being used.
---@return table? framework
function bridge.getcore()
Retrieves the library being used.
---@return table? lib
function bridge.getlib()
Retrieves the inventory framework being used.
---@return table? inv
function bridge.getinv()
Retrieves the player data.
---@param player integer|string?
---@return table? player_data
function bridge.getplayer(player)
Retrieves the player identifier.
---@param player integer|string?
---@return string? identifier
function bridge.getidentifier(player)
Retrieves the player name.
---@param player integer|string?
---@return string? name
function bridge.getplayername(player)
Retrieves the player job data.
---@param player integer|string?
---@return {name: string, label: string, grade: number, grade_name: string, grade_label: string, job_type: string, salary: number}? job_data
function bridge.getjob(player)
Checks if the player has a specific group (either job or gang).
---@param player integer|string?
---@param groups string|string[]
---@return boolean?
function bridge.doesplayerhavegroup(player, groups)
Checks if the player is downed.
---@param player integer|string?
---@return boolean?
function bridge.isplayerdowned(player)
Creates a callback function.
---@param name string
---@param callback function
function bridge.createcallback(name, callback)
Triggers a callback function.
---@param player integer|string?
---@param name string
---@param callback function
---@param ... any
---@return any?
function bridge.triggercallback(player, name, callback, ...)
Note: When triggering client callbacks, player
is the source you wish to trigger the callback on, otherwise it can be left as nil
.
Retrieves all items.
---@return {[string]: {name: string, label: string, weight: number, useable: boolean, unique: boolean}}?
function bridge.getallitems()
Retrieves a specific item.
---@param item string
---@return {name: string, label: string, weight: number, useable: boolean, unique: boolean}?
function bridge.getitem(item)
Creates a useable item.
---@param name string
---@param callback fun(player: integer|string)
function bridge.createuseableitem(name, callback)
Adds an item to the player inventory.
---@param player integer|string?
---@param item string
---@param amount integer
---@return boolean? success
function bridge.additem(player, item, amount)
Removes an item from the player inventory.
---@param player integer|string?
---@param item string
---@param amount integer
---@return boolean? success
function bridge.removeitem(player, item, amount)
Adds a local target entity.
---@param entities integer|integer[]
---@param options {name: string?, label: string, icon: string?, distance: number?, item: string?, canInteract: fun(entity: number, distance: number)?, onSelect: fun()?, event_type: string?, event: string?, jobs: string|string[]?, gangs: string|string[]}
function bridge.addlocalentity(entities, options)
Removes a local target entity.
---@param entities integer|integer[]
function bridge.removelocalentity(entities)
locale is an object containing functions for localisation and translation. It's inspired by the i18n.lua library by kikito, and provides a simple way to manage translations in your FiveM scripts.
This is a shared module, and can be used on both the client, server and shared enviroment.
The module automatically uses the servers' convars to determine locale , both dialect and region. If the convars (sets locale
) are not set, it defaults to en
.
- Interpolation
welcome = 'Hello, {name}!'
->locale.translate('welcome', {name = 'John'})
->Hello, John!
(wherename
is a key in the data table)
- Fallbacks: When a value is not found, the lib has several fallback mechanisms:
- First, it will look in the current locale's parents. For example, if the locale was set to 'en-US' and the key 'msg' was not found there, it will be looked over in 'en'.
- Second, if the value is not found in the locale ancestry, a 'fallback locale' (by default: 'en') can be used. If the fallback locale has any parents, they will be looked over too.
- Third, if all the locales have failed, but there is a param called 'default' on the provided data, it will be used.
- Using files
- The language files are stored in the
locales
folder in the resource root. - The files are named after the locale they represent, e.g.
en.lua
,en-US.lua
,es.lua
.
- The language files are stored in the
-- Using the `require` export
---@module 'duff.shared.locale'
local locale = exports.duff:require 'duff.shared.locale'
-- Attaching the locale to a local variable from the duff object
local locale = duff.locale
Sets a translation key to a value.
---@param key string @A dot-separated key to set the translation value for.
---@param value string @The value to set the translation key to.
function locale.set(key, value)
Loads a translation table from a table.
---@param context string? @The context to load the translations into.
---@param data {[string]: {[string]: string}|string} @A table containing translation keys and values.
function locale.load(context, data)
The table should contain translation keys and values.
locale.load(nil, {
en = {
welcome = 'Hello, {name}!',
goodbye = 'Goodbye, {name}!',
}
})
Loads a translation table from a file.
---@param resource string? @The resource name to load the translation file from.
---@param file string? @The file path to load the translation file from.
function locale.loadfile(resource, file)
The file should return a table containing translation keys and values.
return {
en = {
welcome = 'Hello, {name}!',
goodbye = 'Goodbye, {name}!',
}
}
You can also use a context to load translations into a specific context, or even load all translations into a single context.
return {
en = {
AU = {
welcome = 'G\'day, {name}!',
goodbye = 'Later, {name}!',
},
US = {
welcome = 'Howdy, {name}!',
goodbye = 'See ya later, {name}!',
}
},
es = {
welcome = 'ยกHola, {name}!',
goodbye = 'ยกAdiรณs, {name}!',
}
}
This function has a wrapper function called t
.
Translates a key to a value. This function also supports placeholders, which can be replaced by providing a table of data.
---@param key string @The key to translate.
---@param data {[string]: string}? @A table containing data to replace placeholders in the translation.
---@return string? translation @The translated value, or nil if the key was not found.
function locale.translate(key, data)
math is an object containing some useful math functions. Most notably, it contains a seedrng
function which generates a random seed based on the current time, and a random
function which generates a random number between two values which should be an improvement over the default Lua pseudo-random number generator.
-- Using the `require` export
---@module 'duff.shared.math'
local math = exports.duff:require 'duff.shared.math'
-- Attaching the math to a local variable from the duff object
local math = duff.math
---@param val number
---@param min number
---@param max number
---@return boolean?
function math.between(val, min, max)
---@param value number
---@param min number
---@param max number
---@return number
function math.clamp(value, min, max)
---@param value number
---@param increment integer?
---@return integer
function math.round(value, increment)
---@return integer?
function math.seedrng()
---@param min integer
---@param max integer?
---@return integer
function math.random(min, max)
---@param time integer
---@param limit integer?
---@return boolean
function math.timer(time, limit)
This is a shared module, but has functions which are exclusive to their respective enviroments.
-- Using the `require` export
---@module 'duff.shared.vector'
local vector = exports.duff:require 'duff.shared.vector'
-- Attaching the vector to a local variable from the duff object
local vector = duff.vector
Checks if the table is a vector and converts it to a vector.
---@param tbl {x: number, y: number, z: number?, w: number?}
---@return vector2|vector3|vector4
function vector.tabletovector(tbl)
Finds the closest vector3 in an array to a given vector3.
---@param check integer|vector3|{x: number, y: number, z: number}
---@param tbl vector3[]|integer[]
---@param radius number?
---@param excluding any[]?
---@return integer|vector3?, number?, array?
function vector.getclosest(check, list, radius, ignore)
---@param entity integer
---@return vector3?
function vector.getentityright(entity)
---@param entity integer
---@return vector3?
function vector.getentityup(entity)
---@param entity integer
---@return vector3?, vector3?, vector3?, vector3?
function vector.getentitymatrix(entity)
---@param entity integer
---@return vector3?
function vector.getentityforward(entity)
---@param entity integer
---@param offsetX number
---@param offsetY number
---@param offsetZ number
---@return vector3?
function vector.getoffsetfromentityinworldcoords(entity, offsetX, offsetY, offsetZ)
This is a client module.
-- Using the `require` export
---@module 'duff.client.blips'
local blips = exports.duff:require 'duff.client.blips'
-- Attaching the blips to a local variable from the duff object
local blips = duff.blips
---@return array? blips
function blips.getall()
---@return array? blips
function blips.onscreen()
---@param coords vector3|vector3[]
---@param radius number?
---@return array? blips
function blips.bycoords(coords, radius)
---@param sprite integer
---@return array? blips
function blips.bysprite(sprite)
---@param type integer
---@return array? blips
function blips.bytype(type)
---@param blip integer
---@return {alpha: integer, coords: vector3, colour: integer, display: integer, fade: boolean, hud_colour: integer, type: integer, rotation: number, is_shortrange: boolean}? blip_info
function blips.getinfo(blip)
---@param blips integer|integer[]
function blips.remove(blips)
This is a client module.
-- Using the `require` export
---@module 'duff.client.pools'
local pools = exports.duff:require 'duff.client.pools'
-- Attaching the pools to a local variable from the duff object
local pools = duff.pools
---@return array? peds
function pools.getpeds()
---@return array? vehicles
function pools.getvehicles()
---@return array? objects
function pools.getobjects()
---@return array? pickups
function pools.getpickups()
---@param coords vector3|integer?
---@param ped_type integer?
---@param radius number?
---@param ignore integer[]?
---@return integer? ped, number? distance, array? peds
function pools.getclosestped(coords, ped_type, radius, ignore)
---@param coords vector3|integer?
---@param vehicle_type integer?
---@param radius number?
---@param ignore integer[]?
---@return integer? vehicle, number? distance, array? vehicles
function pools.getclosestvehicle(coords, vehicle_type, radius, ignore)
---@param coords vector3|integer?
---@param radius number?
---@param ignore integer[]?
---@return integer? object, number? distance, array? objects
function pools.getclosestobject(coords, radius, ignore)
---@param coords vector3|integer?
---@param hash string|number?
---@param radius number?
---@param ignore integer[]?
---@return integer? pickup, number? distance, array? pickups
function pools.getclosestpickup(coords, hash, radius, ignore)
This is a client module.
-- Using the `require` export
---@module 'duff.client.streaming'
local streaming = exports.duff:require 'duff.client.streaming'
-- Attaching the streaming to a local variable from the duff object
local streaming = duff.streaming
---@param dict string
---@param isAsync boolean?
---@return boolean?
function streaming.loadanimdict(dict, isAsync)
---@param set string
---@param isAsync boolean?
---@return boolean?
function streaming.loadanimset(set, isAsync)
---@param model string|number
---@param isAsync boolean?
---@return boolean?
function streaming.loadcollision(model, isAsync)
---@param ipl string
---@param isAsync boolean?
---@return boolean?
function streaming.loadipl(ipl, isAsync)
---@param model string|number
---@param isAsync boolean?
---@return boolean?
function streaming.loadmodel(model, isAsync)
---@param fx string
---@param isAsync boolean?
---@return boolean?
function streaming.loadptfx(fx, isAsync)
This is a server module.
-- Using the `require` export
---@module 'duff.server.scope'
local scope = exports.duff:require 'duff.server.scope'
-- Attaching the scope to a local variable from the duff object
local scope = duff.scope
---@param source number|integer
---@return {[string]: boolean}? Scope
function scope.getplayerscope(source)
---@param event string
---@param source number|integer
---@param ... any
---@return {[string]: boolean}? targets
function scope.triggerscopeevent(event, source, ...)
---@param event string
---@param source number|integer
---@param timer integer?
---@param duration integer?
---@param ... any
function scope.createsyncedscopeevent(event, source, timer, duration, ...)
---@param event string
function scope.removesyncedscopeevent(event)
This is a server module.
-- Using the `require` export
---@module 'duff.server.zone'
local zone = exports.duff:require 'duff.server.zone'
-- Attaching the zone to a local variable from the duff object
local zone = duff.zone
---@param check vector3|{x: number, y: number, z: number}|string
---@return boolean?, integer?
function zone.contains(check)
---@param index integer
---@return table?
function zone.getzone(index)
---@param check vector3|{x: number, y: number, z: number}|string
---@return string? name
function zone.getzonename(check)
---@param check vector3|{x: number, y: number, z: number}|string
---@return integer? index
function zone.getzoneindex(check)
---@param event string
---@param zone_id vector3|{x: number, y: number, z: number}|string
---@param onEnter fun(player: string, coords: vector3)
---@param onExit fun(player: string, coords: vector3, disconnected: boolean?)
---@param time integer?
---@param players string?\
function zone.addzoneevent(event, zone_id, onEnter, onExit, time, players)
---@param event string
function zone.removezoneevent(event)
- Join my discord.
- Use the relevant support channels.