lib
JRS Lib is a modular scripting library for RedM that simplifies game development by providing reusable, instance-based components with automatic cleanup. Designed specifically for JRS Core Framework, it helps developers write cleaner, more efficient scripts while eliminating common issues like memory leaks and global variable pollution
This documentation is for developers who are making scripts for redm, you should also note that this is a work in progress and anything can be changed at any time until the final release.
You cannot Import encrypted files like with escrow etc, only files that aren't encrypted can be imported.
Lib usage#
To import modules to your script you must add the following to the script fxmanifest.lua file
shared_script "@jrs_core/lib/import.lua"Module Import#
Only Lua files can be imported
List of Modules#
modules (client)#
entities (module)#
this module contains methods that allows you to create entities like peds, vehicles, objects, etc
blips (module)#
this module contains methods that allows you to create various types of blips styles and map related stuff
inputs (module)#
this module contains methods that allows you to create input controls
raycast (module)#
this module contains methods that allows you to perform gameplay raycasts from the camera or from an entity
prompts (module)#
this module contains methods that allows you to create prompts
commands (module) (client)#
this module contains methods that allows you to register commands
points (module)#
this module contains methods that allows you to create points enter/exit with debug options
polyzones (module)#
this module contains methods that allows you to create polygon, circle, or box detection zones with callbacks and debug tools
events (module)#
this module contains methods that allows you to register game events
dataview (module)#
this module contains methods that allows you to use dataview in lua
streaming (module)#
this module contains methods that allows you to call to load several game assets like anim dics models etc
Importing Modules#
Import#
modulestringrequiredAllows to import any modules from the lib, a list of modules available can be found here
local module = Import "modulename" -- no symbols
local prompts = Import("prompts").Prompts -- every module has a table with the module name as the key for readability
local Lib = Import "prompts"
local Prompts = Lib.Prompts -- [[@as PROMPTS]] -- for intellisenseImport#
modulestringrequiredAllows to import any files from the script you are currently in, must always start with . or / to get the desired path to the file
local module = Import "/filename"
local module = Import "/folder/filename"Import#
modulestringrequiredAllows to import any files from other scripts, must always start with @ then use the special characters / or . to get the desired path to the file
local module = Import "@script_name/filename"
local module = Import "@script_name/folder/filename"Import Usage#
Single#
modulestringrequiredThe module name to import
local module = Import "module"Multiple#
modulearrayrequiredThe module name to import
local module = Import ({"module", "module2", "module3"})
local prompts = module.PromptsMixed#
modulearrayrequiredThe module names to import
local module = Import ({"module", "/internal/filename", "@script_name/external/filename"})
local prompts = module.Prompts
local commands = module.CommandsModules Usage#
The following modules are available in the lib, you can import them using the Import function, documentation for each module will be available below
Entities#
This module is used to create entities like peds, vehicles, objects, etc, it has a baseclass for all entities and sub classes for each entity type all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the entities will be removed for easy development
it has a entity tracker if you wish to track the entities from other scripts (see collector file) for exports
Ped#
- This sub class is used to create peds (inherits from
Entitybase class ) these are instanced objects every creation will have its own instance - Below are the methods available for the ped class
Create#
create a ped
ModelintegerrequiredThe model of the ped
Posvector3requiredThe position of the ped
IsNetworkedbooleanif the ped is networked
ScriptHostPedbooleanif the ped is a script host ped
P7booleanunknown
P8booleanunknown
Optionstablethese are optional parameters
PlaceOnGround = boolean, OutfitPreset = integer
OnCreatefunctionThe function to will be called when the ped is created
OnDeletefunctionThe function to will be called when the ped is deleted
-- Example
-- Import the entities module
local Entity = Import 'entities' --[[@as ENTITY]]
local ped = Entity.Ped:Create({
Model = 'A_C_COW',
Pos = vector4(0, 0, 0, 0),
IsNetworked = true,
Options = {
PlaceOnGround = true,
OutfitPreset = 0,
},
print('Ped created use your own logic here, handle: ', self:GetHandle())
end,
netid)
print('Ped deleted use your own logic here, handle: ', handle, 'netid: ', netid)
end
})
-- methods you can use
local handle = ped:GetHandle()
ped:Delete()Vehicle#
- This sub class is used to create vehicles (inherits from
Entitybase class ) these are instanced objects every creation will have its own instance - Below are the methods available for the vehicle class
Create#
ModelstringrequiredThe model of the vehicle
PosvectorrequiredThe position for the vehicle
IsNetworkedbooleanif the vehicle is networked
ScriptHostVehbooleanif the vehicle is a script host vehicle
DontAutoCreateDraftAnimalsbooleancreate draft animals if true
P8booleanunknown
OptionstablePlaceOnGround, Seat = { Ped = ped, Index = -1}
OnCreatefunctionThe function to call when the vehicle is created
OnDeletefunctionThe function to call when the vehicle is deleted
-- Example
-- Import the entities module
local Entity = Import 'entities' --[[@as ENTITY]]
local vehicle = Entity.Vehicle:Create({
Model = 'wagon01x',
Pos = vector4(0, 0, 0, 0),
IsNetworked = true,
Options = {
PlaceOnGround = true,
Seat = { -- optional
Ped = ped, -- entity
Index = -1, -- -1 for driver, 0 for passenger, 1 for passenger, 2 for passenger, etc
}
},
print('Vehicle created use your own logic here, handle: ', self:GetHandle())
end,
print('Vehicle deleted use your own logic here, handle: ', self:GetHandle())
end
})
local handle = vehicle:GetHandle()
vehicle:Delete()Object#
- This sub class is used to create objects (inherits from
Entitybase class ) these are instanced objects every creation will have its own instance - Below are the methods available for the object class
Create#
ModelintegerrequiredThe model of the object
Posvector3requiredThe position for the object
IsNetworkedbooleanif the object is networked
ScriptHostObjbooleanif the object is a script host object
Dynamicbooleanif the object is dynamic
OptionstablePlaceOnGround = boolean, Rot = vector3,Rot.Order = integer, Rot.P5 = boolean
OnCreatefunctionThe function will be called when the object is created
OnDeletefunctionThe function will be called when the object is deleted
-- Example
-- Import the entities module
local Entity = Import 'entities' --[[@as ENTITY]]
local object = Entity.Object:Create({
Model = 'prop_paper_bag_01',
Pos = vector4(0, 0, 0, 0),
IsNetworked = true,
Options = { -- optional
PlaceOnGround = true,
Rot = {
Pos = vector3(0, 0, 0),
Order = 2,
P5 = true,
}
},
print('Object created use your own logic here, handle: ', self:GetHandle())
end,
print('Object deleted use your own logic here, handle: ', self:GetHandle())
end
})
local handle = object:GetHandle()
object:Delete()Map#
The map module is used to create blips for now but will be expanded to include more map related features when you restart your resource the blips will be removed for easy development
Blip#
This is the baseclass for blips, you can use these methods below or use directly the natives
GetHandle#
returnintegerGet the handle of the blip
GetBlipColor#
colorstring|tablerequiredGet the color value's for blip colors, can be a single color string or table of color strings
returnintegerReturns the color value's corresponding to the color name's
-- single string or multiple colors can be requested just for ease of use
local blue, red, yellow = Map.Blips:GetBlipColor({ 'blue', 'red', 'yellow' })
blip:AddModifierColor(blue) -- or string "blue"Remove#
returnnilRemove/Delete the blip
SetName#
namestringrequiredSet the name/label of the blip
SetCoords#
posvector3requiredSet the coordinates for the blip (pos.x, pos.y, pos.z)
SetStyle#
styleinteger|stringrequiredSet the style for the blip, see blip style
SetSprite#
spriteinteger|stringrequiredSet the sprite icon for the blip. see blip sprite
AddModifier#
modifierinteger|stringrequiredAdd a modifier for the blip see blip modifier
RemoveModifier#
modifierinteger|stringrequiredRemove a modifier from the blip see blip modifier
AddModifierColor#
colorstring|integerrequiredAdd a color modifier for the blip, use the GetBlipColor method to get the color value's if needed
Create#
create a blip
BlipTypestringrequiredThe type of blip to create: entity, coords, area, radius each will have specific params
Blipinteger|stringrequiredThe blip sprite/hash to use, see blip sprite hash
EntityintegerRequired for 'entity' type - the entity handle to attach the blip to
Posvector3Required for 'coords', 'area', and 'radius' types - the position for the blip
Scalevector3Required for 'area' type - the scale dimensions (x, y, z)
RadiusnumberRequired for 'radius' type - the radius size (defaults to 0.5)
P7integerOptional parameter for 'area' type (defaults to 0)
OptionstableOptional parameters for blip appearance:
sprite = integer|string, name = string, style = integer|string, modifier = integer|string, color = string
OnCreatefunctionThe function that will be called when the blip is created
-- Example
-- Import the blips module
local Map = Import 'blips' --[[@as BLIPS]]
local blip = Map.Blips:Create('radius', { -- type can be entity, coords, area, radius
Entity = ped, -- if type is entity, you need to provide a handle
Pos = vector3(2865.88, 475.38, 66.09), -- position
Radius = 50.0, -- if type is radius or area
P7 = 0, -- optional default is 0
Blip = 1673015813, -- blip hash the style of the blip
Scale = vector3(1.0, 1.0, 1.0), -- for type area only
Options = { -- optional
sprite = 1, --string or integer if type is entity or coords
name = 'Test',
modifier = 'BLIP_MODIFIER_MP_COLOR_1', -- int or string
color = 'blue', -- internal color name
},
print('Created', self:GetHandle())
local blue, red, yellow = self:GetBlipColor({ 'blue', 'red', 'yellow' })
self:AddModifier(red)
end
})
local handle = blip:GetHandle()
blip:Remove()Inputs#
this module is used to create input controls for your resource, single or multiple , without the user having to create loops and a bunch of code all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the inputs will be removed for easy development
Input#
use these methods below to manage input controls
Destroy#
returnnilDestroy the input instance and stop all processing
RemoveKey#
keystringrequiredRemove a specific key from multiple inputs or if single input , destroys the input
Pause#
returnnilPause the input processing without destroying the instance
Resume#
returnnilResume the input processing after being paused
Update#
datatablerequiredUpdate custom parameters for the input if needed
keystring|integerrequiredRequired if using multiple inputs - specifies which input to update
Start#
returnnilStart the input processing if is not running, useful when you set state to false and start this when player is near something or character is selected
Register#
register an input or multiple inputs
inputTypestringrequiredThe type of input: Press, Hold, Release
keystring|integerrequiredThe key to listen for (e.g., E, W) these are predefined keys, you can use any hash or string controls
callbackfunctionrequiredFunction called when input is triggered - receives (instance, customParams)
statebooleanIf true, input will start automatically after registration, useful when you set state to false and start this when player is near something or character is selected
-- Example
-- Import the inputs module
local controls = Import 'inputs' --[[@as INPUTS]]
-- Multiple input support
local inputs = {
{ inputType = "Press", key = "E" },
{ inputType = "Hold", key = "W" },
{ inputType = "Release", key = "S" },
}
local input = controls.Inputs:Register(inputs,function(input, customParams)
if input.key == "E" then
print("E was pressed")
elseif input.key == "W" then
print("W is being held")
elseif input.key == "S" then
print("S was released")
end
end, true) -- auto start on register
input:Destroy()Raycast#
this module is used to perform line-of-sight shape tests from the gameplay camera or from an entity
it accepts vector3 values or { x, y, z } tables for coordinates and returns a structured result table with hit data
when a flag is missing or invalid, the module falls back to World
Import#
local Raycast = Import('raycast').Raycast --[[@as RAYCAST]]Flags#
Available flag names:
WorldVehiclesPedsRagdollsObjectsPickupsGlassRiversFoliageAll
FromCamera#
Cast a ray from the gameplay camera forward
distancenumberDistance of the raycast, defaults to 10.0
flagsstringFlag name to use for the shape test, invalid or missing values fallback to World
ignoreEntityintegerEntity handle to ignore, defaults to PlayerPedId()
options.offsetvector3 | tableOptional offset added to the camera coordinates
options.traceTypeintegerShape test trace type, defaults to 7
options.timeoutintegerMax wait time in milliseconds for the result, defaults to 1000
options.waitintegerDelay between polling attempts, defaults to 0
returnRAYCAST_RESULTReturns a result table with hit, coords, normal, entity, material, state, didHit and handle
local Raycast = Import('raycast').Raycast --[[@as RAYCAST]]
local result = Raycast:FromCamera(15.0, 'World')
if result.hit then
print('Hit coords:', result.coords)
print('Hit entity:', result.entity)
endFromEntity#
Cast a ray from an entity forward using its current forward vector
entityintegerrequiredEntity handle to cast from, the entity must exist
distancenumberDistance of the raycast, defaults to 10.0
flagsstringFlag name to use for the shape test, invalid or missing values fallback to World
ignoreEntityintegerEntity handle to ignore, defaults to the provided entity
options.offsetvector3 | tableOptional offset added to the entity coordinates before casting
options.traceTypeintegerShape test trace type, defaults to 7
options.timeoutintegerMax wait time in milliseconds for the result, defaults to 1000
options.waitintegerDelay between polling attempts, defaults to 0
returnRAYCAST_RESULTReturns a result table with hit, coords, normal, entity, material, state, didHit and handle
local Raycast = Import('raycast').Raycast --[[@as RAYCAST]]
local horse = GetMount(PlayerPedId())
if horse ~= 0 then
local result = Raycast:FromEntity(horse, 8.0, 'Peds', horse)
if result.hit then
print('Entity raycast hit:', result.entity)
end
endRAYCAST_RESULT#
Result fields returned by FromCamera and FromEntity
hitbooleanTrue when the shape test hit something
stateintegerNative shape test state
handleintegerShape test handle returned by the native
didHitintegerRaw native hit result
coordsvector3Hit coordinates
normalvector3Surface normal
entityintegerHit entity handle, or 0 if no entity was hit
materialintegerMaterial hash returned by GetShapeTestResultIncludingMaterial
Prompts#
this module is used to create prompts with coordinate-based activation, multiple prompts can be grouped together and managed as one unit all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the prompts will be removed for easy development
Prompt#
use these methods below to manage prompts
GetHandle#
keystring|integerrequiredThe key identifier of the specific prompt, its whatever you set in the register
returnintegerGet the handle of a specific prompt by key
GetPromptGroup#
keystring|integerrequiredThe key identifier of the specific prompt, its whatever you set in the register
returnintegerGet the group ID of a specific prompt
GetGroupLabel#
keystring|integerrequiredThe key identifier of the specific prompt, its whatever you set in the register
returnstringGet the group label of a specific prompt
IsRunning#
returnbooleanCheck if the prompt you registered is currently running
SetLabel#
labelstringrequiredNew label text for the prompt
keystring|integerrequiredThe key identifier of the prompt to update, its whatever you set in the register
SetEnabled#
enabledbooleanrequiredWhether the prompt should be enabled or disabled
keystring|integerrequiredThe key identifier of the prompt to update, its whatever you set in the register
SetVisible#
visiblebooleanrequiredWhether the prompt should be visible or hidden
keystring|integerrequiredThe key identifier of the prompt to update, its whatever you set in the register
SetMashMode#
mashCountintegerrequiredNumber of times the key must be mashed
keystring|integerrequiredThe key identifier of the prompt to update, its whatever you set in the register
SetMashIndefinitelyMode#
keystring|integerrequiredThe key identifier of the prompt to set to indefinite mash mode, its whatever you set in the register
Start#
returnnilStart the prompt system if is not running, useful when you set state to false and start this when player is near something or character is selected
Pause#
returnnilPause the prompt system without destroying it
Resume#
returnnilResume the prompt system after being paused
Remove#
keystringrequiredThe key identifier of the specific prompt to remove if multiple, if single will destroy
Destroy#
returnnilDestroy the entire prompt system
Register#
register prompts
coordsvector3requiredThe center coordinates where prompts will be active
distancenumberActivation radius from coords (defaults to 2.0)
labelstringrequiredThe group label shown at the top of the prompt group
sleepintegerSleep time when not in range (defaults to 700ms)
markertableOptional marker configuration: type, color = {r,g,b,a}, distance, scale = {x,y,z} can be used for debug as well
promptsarrayrequiredArray of prompt objects with: type, key, label, mode, and mode-specific parameters
Types: Press, Hold, Release, Standard, Pressed, Released, Mash
Modes: Hold (holdTime), Timed (timedMode), Mash (mashCount), Standard (releaseMode), Standardized (eventHash)
callbackfunctionrequiredFunction called when any prompt is triggered - receives (prompt, index, instance, value).
value is the current entry from the locations table, which avoids having to look it up again manually.
statebooleanIf true, prompts will start automatically after registration (defaults to false) useful when you set state to false and start this when player is near something or character is selected
-- Example
-- Import the prompts module
local Game = Import 'prompts' --[[@as PROMPTS]]
local data = {
locations = {
{ -- index 1
coords = vector3(2868.43, 480.19, 65.02), -- distance based prompts
label = 'group label', -- group label
distance = 2.0, -- distance from coords
marker = { -- optional marker
type = 0x94FDAE17,
color = { r = 0, g = 255, b = 0, a = 96 },
distance = 4.0,
scale = { x = 2.0, y = 2.0, z = 0.5 },
}
}
},
sleep = 700, -- sleep time when not in range
prompts = { -- group prompts or single prompt
{ type = 'Press', key = 'G', label = 'press', mode = 'Standard' },
{ type = 'Hold', key = 'E', label = 'hold', mode = 'Hold', holdTime = 3000 }
}
}
local prompt = Game.Prompts:Register(data, function(prompt, index, self, location)
-- location is the current entry from data.locations[index]
if index == 1 and location.label == 'group label' then
if prompt.key == 'G' then
print('G pressed')
elseif prompt.key == 'E' then
print('E held for 3 seconds')
end
end
end, true) -- auto start on register
prompt:Destroy() -- the lib it self will destroy any prompt on script restartCommands#
this module is used to register client-side/server-side commands with permissions, suggestions, and argument validation all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the commands will be removed for easy development, if a command is active and suggestion hasnt been marked to add on register, it will be added on character selected automatically
Command#
use these methods below to manage command controls
Remove#
returnnilRemoves the command and its suggestion from chat
AddSuggestion#
returnnilAdds command suggestion to chat
RemoveSuggestion#
returnnilRemoves the command suggestion from chat
Pause#
returnnilPause the command without removing it (temporarily disables the command)
Resume#
returnnilResume the command after being paused
Destroy#
returnnilCompletely destroy the command instance and clean up
Start#
addSuggestionbooleanWhether to add chat suggestion when registering the command, use this only on runtime, by default when player selects character suggestion is added automatically
returnnilStart/activate the command
OnExecute#
callbackfunctionrequiredits called when the command is executed
OnError#
callbackfunctionits called when the command has errors
Register#
register a command
namestringrequiredThe command name (without the / prefix)
SuggestiontableChat suggestion configuration with Description and Arguments array
PermissionstablePermission configuration with Ace group settings
OnExecutefunctionrequiredFunction called when command executes - receives (args, rawCommand, instance)
OnErrorfunctionFunction called on command errors - receives error type string
statebooleanIf true, command starts automatically after registration, useful when you set state to false and start this when player is near something or character is selected
-- Example
-- Import the commands module
local Commands = Import 'commands' --[[@as COMMANDS]]
local command = Commands.Command:Register("mycommand", {
Suggestion = { -- optional
Description = "My custom command description",
Arguments = {
-- if type is number or integer, it will be converted to a number
-- if type is message, it will give it as a message
{ name = "playerId", help = "Target player ID", type = "integer", required = true },
{ name = "amount", help = "Amount value", type = "number", required = true },
{ name = "message", help = "Optional message", type = "message"}
}
},
Permissions = { -- optional
Ace = "group.admin" -- Restrict to admin group, or remove for public command
},
rawCommand, instance)
print("Command executed with args:", json.encode(args))
print("Player ID:", args[1]) -- integer type
print("Amount:", args[2]) -- number type
print("Message:", args[3]) -- message type (remaining args combined)
end,
if errorType == 'missing_arguments' then
print('Usage: /mycommand <playerId> <amount> [message]')
elseif errorType == 'missing_permission' then
print('You do not have permission to use this command')
elseif errorType == 'command_active' then
print('Command is currently paused')
end
end
}, true) -- Auto-start
-- Control methods
command:Start(true) -- Start and add suggestion if not have been added yet
command:Destroy() -- Clean up completely
-- Argument types:
-- "integer" - converts to number (whole numbers)
-- "number" - converts to number (decimals allowed)
-- "message" - combines remaining arguments into string
-- (no type) - keeps as string
-- Error types:
-- "missing_arguments" - Required argument not provided
-- "missing_permission" - User lacks required permissions
-- "command_active" - Command is paused
-- "missing_target" - Target not found (if applicable)Command#
use these methods below to manage server command controls
Remove#
returnnilRemove the command, its suggestion from all clients, and ACE permissions
AddSuggestion#
targetintegerrequiredThe player source ID to send suggestion to
returnnilAdd command suggestion to specific player's chat
RemoveSuggestion#
targetintegerrequiredThe player source ID to remove suggestion from
returnnilRemove command suggestion from specific player's chat
Pause#
returnnilPause the command without removing it (temporarily disable)
Resume#
returnnilResume the command after being paused
Destroy#
returnnilCompletely destroy the command instance and clean up
Start#
returnnilStart/activate the command and register ACE permissions if configured
OnExecute#
callbackfunctionrequiredSet or update the callback function called when command executes
OnError#
callbackfunctionrequiredSet or update the callback function called when command has errors
Register#
register a server command
namestringrequiredThe command name (without the / prefix)
SuggestiontableChat suggestion configuration with Description and Arguments array
- Description: The description of the command
- Arguments: The arguments of the command
- name: The name of the argument
- help: The help of the argument
- type: The type of the argument if type is number or integer, it will be converted to a number if type is message, it will give it as a message
- required: Whether the argument is required
Suggestion = { -- optional
Description = "Admin command with complex permissions",
Arguments = {
{ name = "playerId", help = "Target player ID", type = "integer", required = true },
{ name = "amount", help = "Amount value", type = "number", required = true },
{ name = "message", help = "Optional message", type = "message" }
}
}PermissionstableAdvanced permission configuration with Ace, Jobs, Groups, and CharIds
- Ace: ACE permission (overrides others) leave false if you dont want to use ace permissions
- Groups: Group permissions with users (DB users table) and characters (DB characters table) sections
- Jobs: Job-based permissions with optional grade restrictions
- CharIds: Specific character ID based permissions
Permissions = { -- optional
Ace = "group.admin", -- ACE permission (overrides others) leave false if you dont want to use ace permissions
Groups = { -- optional
users = {
admin = true,
moderator = true
},
characters = {
gang_leader = true
}
},
Jobs = { -- optional
Police = { -- jobname
[0] = false,
[1] = true
},
Sheriff = true -- All ranks allowed
},
CharIds = { -- optional
[123] = true, -- Specific character ID
[456] = true
},
}OnExecutefunctionrequiredFunction called when command executes - receives (source, args, rawCommand, instance)
OnErrorfunctionFunction called on command errors - receives error type string
statebooleanIf true, command starts automatically after registration (defaults to false)
-- Example
-- Import the server commands module
local LIB = Import 'commands' --[[@as COMMANDS]]
local command = LIB.Command:Register("commandName", {
Suggestion = { -- optional
Description = "Admin command with complex permissions",
Arguments = {
{ name = "playerId", help = "Target player ID", type = "integer", required = true },
{ name = "amount", help = "Amount value", type = "number", required = true },
{ name = "message", help = "Optional message", type = "message" }
}
},
Permissions = { -- optional
Ace = "group.admin", -- ACE permission (overrides others) leave false if you dont want to use ace permissions
Jobs = { -- optional
Police = { -- jobname
[0] = false, -- Rank 0 not allowed
[1] = true, -- Rank 1+ allowed
},
Sheriff = true -- All ranks allowed
},
Groups = { -- optional
users = {
admin = true,
moderator = true
},
characters = {
gang_leader = true
}
},
CharIds = { -- optional
[123] = true, -- Specific character ID
[456] = true
}
},
args, rawCommand, instance)
print("Command executed by source:", source)
print("Player ID:", args[1]) -- player type (validated)
print("Amount:", args[2]) -- number type
print("Message:", args[3]) -- message type
end,
if errorType == 'missing_arguments' then
print('Usage: /admincommand <playerId> <amount> [message]')
elseif errorType == 'missing_permission' then
print('You do not have permission to use this command')
elseif errorType == 'missing_job' then
print('You do not have the required job')
elseif errorType == 'missing_grade' then
print('You do not have the required job rank')
elseif errorType == 'missing_group' then
print('You do not have the required group')
elseif errorType == 'missing_character' then
print('Your character is not authorized')
elseif errorType == 'missing_user' then
print('User not found or console command not supported')
elseif errorType == 'command_active' then
print('Command is currently paused')
end
end
}, true) -- Auto-start
-- Control methods
command:Destroy() -- Clean up completely
-- Server-specific features:
-- - Automatic ACE permission management
-- - Complex job/grade validation
-- - Character and user group permissions
-- - Per-player suggestion management
-- - Console command restriction (source = 0)
-- Error types (additional server-side):
-- "missing_user" - User not found or console command
-- "missing_job" - Player doesn't have required job
-- "missing_grade" - Player doesn't have required job rank
-- "missing_group" - Player doesn't have required group
-- "missing_character" - Character not authorized
-- "missing_state" - State validation failed
-- Permission priority:
-- 1. ACE permissions (highest) all others will be ignored
-- 2. Job permissions
-- 3. Group permissions
-- 4. Character ID permissionsPoints#
this module is used to create coordinate-based enter/exit areas with radius detection, multiple points can be registered and managed independently all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the points will be removed for easy development
Point#
use these methods below to manage points
IsPointActive#
idstring|integerrequiredThe unique identifier of the point to check
returnbooleanReturns true if the point is active and not deactivated
IsPointInside#
idstring|integerrequiredThe unique identifier of the point to check
returnbooleanReturns true if the player is currently inside the point radius
IsPointOutside#
idstring|integerrequiredThe unique identifier of the point to check
returnbooleanReturns true if the player is currently outside the point radius
UpdatePoint#
idstring|integerrequiredThe unique identifier of the point to update
datatablerequiredNew point data to replace the existing point configuration
RemovePoint#
idstring|integerrequiredThe unique identifier of the point to remove
returnnilRemoves the specified point from the instance
PausePoint#
idstring|integerrequiredThe unique identifier of the point to pause
returnnilDeactivates the specified point without removing it
ResumePoint#
idstring|integerrequiredThe unique identifier of the point to resume
returnnilReactivates a previously paused point
Start#
returnnilStart the point system if not already running, begins monitoring player position
Pause#
returnnilPause the entire point system without destroying it
Resume#
returnnilResume the point system after being paused
Destroy#
returnnilDestroy the entire point instance and clean up all points
DebugPoints#
returnnilEnable visual debug markers for points that have debug enabled
Register#
register coordinate-based points for enter/exit detection
ArgumentsarrayrequiredArray of point configurations, each point must have unique id, center coordinates, and radius
- id: Unique identifier for the point (string/integer)
- center: Point center coordinates (vector3)
- radius: Detection radius around center (number)
- wait: Check interval in milliseconds (optional, defaults to 500)
- debug: Enable visual debug marker (optional, boolean)
- deActivate: If true, point starts inactive and must be manually activated (optional, boolean)
-- supports multiple points
Arguments = {
{
id = 'bank_entrance',
center = vector3(2843.49, 474.49, 64.03),
radius = 15.0,
wait = 500,
debug = true,
deActivate = false,
}
}OnEnterfunctionrequiredFunction called when player enters any point - receives (point, distance)
OnExitfunctionrequiredFunction called when player exits any point - receives (point, distance)
statebooleanIf true, point system starts automatically after registration other wise use the Start method to start the point system
-- Example
-- Import the points module
local GamePoints = Import 'points' --[[@as POINTS]]
local points = GamePoints.Points:Register({
Arguments = {
{
id = 'bank_entrance', -- unique identifier
center = vector3(2843.49, 474.49, 64.03), -- center coordinates
radius = 15.0, -- detection radius
wait = 500, -- check interval (ms)
debug = true, -- show debug marker
deActivate = true, -- start active? remove to start active
},
{
id = 'shop_door',
center = vector3(2884.03, 484.19, 66.73),
radius = 10.0,
wait = 300,
debug = true,
},
},
distance)
print("Entered point:", point.id, "Distance:", distance)
if point.id == 'bank_entrance' then
print("Welcome to the bank!")
elseif point.id == 'shop_door' then
print("Welcome to the shop!")
end
end,
distance)
print("Exited point:", point.id, "Distance:", distance)
if point.id == 'bank_entrance' then
print("Left the bank area")
elseif point.id == 'shop_door' then
print("Left the shop area")
end
end
}, true) -- Auto-start
-- Control methods
points:PausePoint('shop_door') -- Pause specific point
points:ResumePoint('shop_door') -- Resume specific point
points:RemovePoint('bank_entrance') -- Remove specific point
-- Check point status
local isActive = points:IsPointActive('shop_door')
local isInside = points:IsPointInside('shop_door')
local isOutside = points:IsPointOutside('shop_door')
-- System control
points:Pause() -- Pause entire system
points:Resume() -- Resume entire system
points:Destroy() -- Clean up completelyPolyZones#
this module is used to create polygon, circle, or box shaped detection zones with height filtering, debug rendering, and enter/inside/exit callbacks all creations are instanced objects every zone instance is private to the script that imports it and will be removed automatically when the resource restarts
PolyZone#
use these methods below to register and manage advanced zone shapes
GetId#
returnstring|integerReturns the unique identifier assigned to the zone (auto-generated when not provided)
GetType#
returnstringReturns the zone type poly, circle, or box
IsRunning#
returnbooleanReturns true when the zone polling loop is currently running
IsInside#
returnbooleanReturns true if the local player is currently inside the zone
SetCallbacks#
cbEnterfunctionReplaces the onEnter callback (receives zone instance and player coords)
cbExitfunctionReplaces the onExit callback (receives zone instance and player coords)
cbInsidefunctionReplaces the onInside callback that runs every tick while inside
UpdatePolygon#
pointsarrayUpdates polygon points (vector3 list) and recalculates bounds, available for polygon zones only
UpdateCircle#
centervector3Updates circle center position
radiusnumberUpdates circle radius, available for circle zones only
UpdateBox#
centervector3Updates box center position
lengthnumberUpdates box length, available for box zones only
widthnumberUpdates box width, available for box zones only
headingnumberOptional new heading in degrees for the box zone
SetHeight#
minZnumberSets the minimum Z (height) allowed before the zone considers the player outside
maxZnumberSets the maximum Z (height) allowed before the zone considers the player outside
SetDebug#
enabledbooleanEnables or disables debug drawing (auto-starts debug loop when the zone is running)
SetTickRates#
outsideMsnumberSets polling interval in milliseconds while the player is outside the zone (defaults to 200)
insideMsnumberSets polling interval in milliseconds while the player stays inside (defaults to 1)
Start#
returnnilStarts the background thread that evaluates the zone, automatically launches debug rendering when enabled
Pause#
returnnilTemporarily stops the zone without clearing callbacks or shape data
Resume#
returnnilRestarts a paused zone and resumes detection
Destroy#
returnnilDisables the zone and clears its configuration (instance should be discarded afterwards)
Register#
register polygon, circle, or box zones with callbacks and optional auto-start
datatablerequiredZone configuration table:
- id: Optional string or integer unique identifier (
polyzone_<timestamp>when omitted) - type: Zone type
poly,circle, orbox(defaults topoly, case-insensitive) - sleep: Interval in milliseconds while outside the zone (default 200)
- sleepInside: Interval in milliseconds while inside the zone (default 1)
- padding: Extra meters added to the bounding radius for early rejection (default 1.5)
- debug: Enable debug drawing for the zone (boolean)
- minZ / maxZ: Optional height bounds restricting detection
- onEnter(zone, coords): Callback fired when the player enters the zone
- onInside(zone, coords): Optional tick callback executed while the player stays inside
- onExit(zone, coords): Callback fired when the player leaves the zone
- polygon: provide
pointswith at least 3 vector3 values and optionalcenter - circle: provide
centervector3 andradiusnumber (orsizetable with same values) - box: provide
centervector3,lengthandwidthnumbers, optionalheading(degrees) orsizetable{ x, y }
statebooleanWhen true the zone starts immediately after registration (defaults to false, call Start() manually otherwise)
returnPolyZoneReturns the zone instance so you can control it with the methods above
local PolyZones = Import('polyzones').PolyZones
local stables = PolyZones:Register({
id = 'valentine_stables',
type = 'poly',
points = {
vector3(-546.83, -600.65, 42.23),
vector3(-548.62, -607.16, 42.32),
vector3(-554.35, -605.86, 42.31),
vector3(-552.20, -599.25, 42.27),
vector3(-554.13, -594.14, 42.19),
},
minZ = 41.8,
maxZ = 45.0,
debug = true,
coords)
print(('Entered %s at %.2f %.2f'):format(zone:GetId(), coords.x, coords.y))
end,
print('Left zone', zone:GetId())
end,
}, true) local PolyZones = Import('polyzones').PolyZones
local campfire = PolyZones:Register({
id = 'campfire_radius',
type = 'circle',
center = vector3(-567.97, -594.54, 42.51),
radius = 2.5,
debug = true,
sleepInside = 250,
coords)
print(('Warming up at %.2f %.2f'):format(coords.x, coords.y))
end,
print('Leaving the fire')
end,
}, true) local PolyZones = Import('polyzones').PolyZones
local jailCell = PolyZones:Register({
id = 'jail_cell_a',
type = 'box',
center = vector3(-565.68, -605.77, 42.31),
length = 4.0,
width = 3.0,
heading = 90.0,
minZ = 41.5,
maxZ = 44.0,
}, true)
jailCell:SetDebug(true)
jailCell:SetTickRates(100, 10)Destroy#
instancePolyZoneZone instance returned by Register
returnnilStops the zone, removes it from the manager, and cleans it up
local PolyZones = Import('polyzones').PolyZones
local zone = PolyZones:Register({
id = 'temp_zone',
type = 'circle',
center = vector3(-100.0, 120.0, 40.0),
radius = 3.0,
}, true)
PolyZones:Destroy(zone)Events#
this module is used to register game event listeners that can capture and process native game events with automatic data parsing all creations are instanced objects every creation will have its own instance and wont be shared with other scripts since its imported to your script when you restart your resource the event listeners will be removed for easy development
Event#
use these methods below to manage event listeners
Start#
returnnilStart the event listener and begin monitoring for the registered event
Pause#
returnnilPause the event listener without destroying the instance
Resume#
returnnilResume the event listener after being paused
Destroy#
returnnilDestroy the event listener instance and clean up
DevMode#
enabledbooleanrequiredEnable or disable developer mode for debugging events
eventsToIgnorestring|arrayOptional events to ignore when in dev mode (can be event name string, hash)
returnnilWhen enabled, logs all events in the group. Use eventsToIgnore to filter out noise.
-- Enable dev mode and ignore specific events
event:DevMode(true, {"EVENT_PED_CREATED", "EVENT_PED_DESTROYED"})
-- Enable dev mode for all events
event:DevMode(true)
-- Disable dev mode
event:DevMode(false)Register#
register a game event listener
eventNamestring|integerrequiredThe game event name (string) or hash (integer) to listen for
groupintegerrequiredThe event group to monitor: 0 for SCRIPT_EVENT_QUEUE_AI or 1 for SCRIPT_EVENT_QUEUE_NETWORK
- SCRIPT_EVENT_QUEUE_AI (0): For AI and NPC related events
- SCRIPT_EVENT_QUEUE_NETWORK (1): For network and player related events
callbackfunctionrequiredFunction called when the event triggers - receives parsed event data or nothing if event has no data
statebooleanIf true, event listener starts automatically after registration, otherwise use Start method
-- Example
-- Import the events module
local Game = Import 'events' --[[@as EVENTS]]
-- Register event with automatic data parsing
local event = Game.Events:Register('EVENT_PED_CREATED', 0, function(data)
print("Ped created with data:", json.encode(data, {indent = true}))
end, true) -- Auto-start
-- Developer mode for debugging, dont fire this events when in dev mode
event:DevMode(true, {"EVENT_PED_CREATED","EVENT_VEHICLE_CREATED"}) -- Enable dev mode, ignore these events
-- dev mode enables all events to be triggered
-- Clean up
event:Destroy()DataView#
this module provides JavaScript-like DataView functionality for handling binary data in Lua with support for various data types and endianness this module is based on gottfriedleibniz's DataView implementation providing efficient binary data manipulation
DataView#
use these methods below to manage binary data
Buffer#
returnstringGet the underlying binary buffer as a string
ByteLength#
returnintegerGet the length of the buffer in bytes
ByteOffset#
returnintegerGet the current offset position within the buffer
Data Type Getters#
Available getter methods for reading different data types:
GetInt8(offset, endian)- Read 8-bit signed integerGetUint8(offset, endian)- Read 8-bit unsigned integerGetInt16(offset, endian)- Read 16-bit signed integerGetUint16(offset, endian)- Read 16-bit unsigned integerGetInt32(offset, endian)- Read 32-bit signed integerGetUint32(offset, endian)- Read 32-bit unsigned integerGetInt64(offset, endian)- Read 64-bit signed integerGetUint64(offset, endian)- Read 64-bit unsigned integerGetFloat32(offset, endian)- Read 32-bit floatGetFloat64(offset, endian)- Read 64-bit doubleGetString(offset, endian)- Read null-terminated stringGetLuaInt(offset, endian)- Read Lua integerGetLuaNum(offset, endian)- Read Lua number
offsetintegerrequiredByte offset from buffer start to read from
endianbooleanEndianness: true for big-endian, false/nil for little-endian
returnnumber|string|nilThe read value, or nil if offset is out of bounds
Fixed Size Getters#
GetFixedString(offset, length, endian)- Read fixed-length stringGetFixedInt(offset, length, endian)- Read fixed-size signed integerGetFixedUint(offset, length, endian)- Read fixed-size unsigned integer
offsetintegerrequiredByte offset from buffer start
lengthintegerrequiredNumber of bytes to read
endianbooleanEndianness: true for big-endian, false/nil for little-endian
SubView#
offsetintegerrequiredByte offset to create the sub-view from
returnDataViewCreate a new DataView that shares the same buffer but with different offset
Data Type Setters#
Available setter methods for writing different data types:
SetInt8(offset, value, endian)- Write 8-bit signed integerSetUint8(offset, value, endian)- Write 8-bit unsigned integerSetInt16(offset, value, endian)- Write 16-bit signed integerSetUint16(offset, value, endian)- Write 16-bit unsigned integerSetInt32(offset, value, endian)- Write 32-bit signed integerSetUint32(offset, value, endian)- Write 32-bit unsigned integerSetInt64(offset, value, endian)- Write 64-bit signed integerSetUint64(offset, value, endian)- Write 64-bit unsigned integerSetFloat32(offset, value, endian)- Write 32-bit floatSetFloat64(offset, value, endian)- Write 64-bit doubleSetString(offset, value, endian)- Write null-terminated stringSetLuaInt(offset, value, endian)- Write Lua integerSetLuaNum(offset, value, endian)- Write Lua number
offsetintegerrequiredByte offset from buffer start to write to
valuenumber|stringrequiredThe value to write
endianbooleanEndianness: true for big-endian, false/nil for little-endian
returnDataViewReturns self for method chaining
Fixed Size Setters#
SetFixedString(offset, length, value, endian)- Write fixed-length stringSetFixedInt(offset, length, value, endian)- Write fixed-size signed integerSetFixedUint(offset, length, value, endian)- Write fixed-size unsigned integer
offsetintegerrequiredByte offset from buffer start
lengthintegerrequiredNumber of bytes for the data type
valuenumber|stringrequiredThe value to write
endianbooleanEndianness: true for big-endian, false/nil for little-endian
ArrayBuffer#
create a new binary buffer
lengthintegerrequiredSize of the buffer to allocate in bytes
returnDataViewReturns a new DataView instance with allocated buffer
-- Import the dataview module
local Data = Import 'dataview' --[[@as DATAVIEW]]
-- Create a 64-byte buffer
local buffer = Data.DataView.ArrayBuffer(64)
-- Write different data types
buffer:SetInt32(0, 42) -- Write integer at offset 0
buffer:SetFloat32(4, 3.14159) -- Write float at offset 4
buffer:SetString(8, "Hello") -- Write string at offset 8
-- Read the data back
local intValue = buffer:GetInt32(0) -- 42
local floatValue = buffer:GetFloat32(4) -- 3.14159
local stringValue = buffer:GetString(8) -- "Hello"
print("Buffer length:", buffer:ByteLength()) -- 64
print("Values:", intValue, floatValue, stringValue)Wrap#
wrap existing binary data
binaryDatastringrequiredExisting binary data string to wrap
returnDataViewReturns a DataView instance wrapping the existing data
-- Wrap existing binary data
local existingData = string.pack("i4f", 100, 2.718)
local wrappedView = Data.DataView.Wrap(existingData)
-- Read from wrapped data
local intVal = wrappedView:GetInt32(0) -- 100
local floatVal = wrappedView:GetFloat32(4) -- 2.718DataStream#
create sequential data reader
dataViewDataViewrequiredDataView instance to create stream from
returnDataStreamReturns a DataStream for sequential reading
Available DataStream methods (automatically advance offset):
Int8(endian, align),Uint8(endian, align)Int16(endian, align),Uint16(endian, align)Int32(endian, align),Uint32(endian, align)Int64(endian, align),Uint64(endian, align)Float32(endian, align),Float64(endian, align)String(endian, align),LuaInt(endian, align),LuaNum(endian, align)
-- Create buffer with mixed data
local buffer = Data.DataView.ArrayBuffer(32)
buffer:SetInt32(0, 123)
buffer:SetFloat32(4, 4.56)
buffer:SetInt16(8, 789)
-- Create stream for sequential reading
local stream = Data.DataView.DataStream.New(buffer)
-- Read sequentially (offset advances automatically)
local int1 = stream:Int32() -- 123, offset now at 4
local float1 = stream:Float32() -- 4.56, offset now at 8
local int2 = stream:Int16() -- 789, offset now at 10
print("Sequential read:", int1, float1, int2)Streaming#
this module provides utility functions for loading various game assets like models, animations, textures, and more with automatic cleanup and timeout handling all functions handle the loading process with proper validation and error handling, preventing common issues with asset streaming
Asset Loading#
use these functions below to load various game assets with automatic cleanup
LoadModel#
modelstring|integerrequiredModel name (string) or hash (integer) to load
timeoutintegerOptional timeout in milliseconds to automatically unload the model and free memory
returnnilLoads and validates the model, throws error if invalid or fails to load within 5 seconds
LoadTextureDict#
dictstringrequiredTexture dictionary name to load
timeoutintegerOptional timeout in milliseconds to automatically unload the texture dictionary
returnnilLoads texture dictionary with validation and error handling
LoadParticleFx#
dictstringrequiredParticle effect dictionary name to load
timeoutintegerOptional timeout in milliseconds to automatically remove the particle effect asset
returnnilLoads particle effect dictionary for use with particle systems
LoadAnimDict#
dictstringrequiredAnimation dictionary name to load
timeoutintegerOptional timeout in milliseconds to automatically remove the animation dictionary
returnnilLoads animation dictionary with existence validation
LoadWeaponAsset#
weaponstring|integerrequiredWeapon name (string) or hash (integer) to load
p1integerrequiredUnknown parameter (usually 31)
p2booleanrequiredUnknown parameter (usually false)
timeoutintegerOptional timeout in milliseconds to automatically remove the weapon asset
returnnilLoads weapon asset with validation
LoadMoveNetworkDef#
netDefstringrequiredMove network definition name to load
timeoutintegerOptional timeout in milliseconds to automatically remove the network definition
returnnilLoads move network definition for advanced movement systems
LoadClipSet#
clipSetstringrequiredClip set name to load
timeoutintegerOptional timeout in milliseconds to automatically remove the clip set
returnnilLoads animation clip set for character movement styles
RequestCollisionAtCoord#
coordsvector3requiredCoordinates where collision should be loaded
returnnilLoads collision data for terrain at specified coordinates
RequestCollisionForModel#
modelstring|integerrequiredModel name or hash to load collision for
returnnilLoads collision data for a specific model
RequestIpl#
iplstring|integerrequiredIPL (Interior Proxy List) name or hash to load
returnnilLoads IPL for interior or map sections, warns if already loaded
LoadScene#
posvector3requiredPosition to load scene around
offsetvector3requiredOffset from position
radiusnumberrequiredRadius to load scene within
p7integerrequiredUnknown parameter (usually 0)
returnnilLoads world area around entity - use carefully as it can cause crashes with too many MLOs
Import#
import the streaming module
-- Import the streaming module
local Assets = Import 'streaming' --[[@as STREAMING]]
-- Use any function
Assets.Streaming.LoadModel('A_C_BEAR_01')
Assets.Streaming.LoadAnimDict('amb@world_human_drinking@coffee@male@idle_a')
Class#
this module provides a complete object-oriented programming system for Lua with classes, inheritance, private members, and automatic getters/setters supports both traditional Lua OOP patterns and modern structured approaches with automatic property management was inspired by JavaScript classes
OOP System#
use these methods below to create classes with full OOP support
Create#
basetable|classBase class to inherit from, or table of initial methods/properties
classNamestringOptional name for the class (used in error messages)
returnclassReturns a new class that can create instances with :New()
-- Import the class module
local Lib = Import 'class' --[[@as CLASS]]
-- Create a basic class
local MyClass = Lib.Class:Create({
constructor = function(self, name)
self.name = name
end,
getName = function(self)
return self.name
end
}, "MyClass")
-- Create instance
local instance = MyClass:New("Test")
print(instance:getName()) -- "Test"- Traditional Lua example
local MyClass = Lib.Class:Create({},"MyClass")
function MyClass:constructor(name)
self.name = name
end
function MyClass:getName()
return self.name
end
local instance = MyClass:New("Test")
print(instance:getName()) -- "Test"New#
...anyArguments to pass to the constructor
returninstanceReturns a new instance of the class
Creates new instances of the class. Supports both table-based and argument-based constructors.
-- Table-based constructor
local instance1 = MyClass:New({
name = "John",
age = 30
})
-- Argument-based constructor
local instance2 = MyClass:New("John", 30)Class Inheritance#
Classes can inherit from other classes, gaining access to all parent methods and properties.
-- Base class
local Entity = Lib.Class:Create({
constructor = function(self, id)
self.id = id
self.created = os.time()
end,
getId = function(self)
return self.id
end,
getInfo = function(self)
return "Entity " .. self.id
end
}, "Entity")
-- Inherited class
local Ped = Lib.Class:Create(Entity, "Ped")
function Ped:constructor(id, model)
self:super(id) -- Call parent constructor
self.model = model
end
function Ped:getInfo()
return "Ped " .. self.id .. " (" .. self.model .. ")"
end
-- Usage
local ped = Ped:New(123, "A_M_M_FARMER_01")
print(ped:getInfo()) -- "Ped 123 (A_M_M_FARMER_01)"
print(ped:getId()) -- 123 (inherited method)super#
...anyArguments to pass to parent constructor
returnnilCalls the parent class constructor
Used within a constructor to call the parent class constructor.
local Ped = Lib.Class:Create(Entity, "Ped")
function Ped:constructor(id, model)
self:super(id) -- Call parent constructor
self.model = model
endAutomatic Properties#
Define automatic getters and setters for properties using get and set tables.
local Person = Lib.Class:Create({
constructor = function(self, name, age)
self.name = name
self.age = age
end,
-- can be used to organize your code as well just like JS classes
get = {
name = function(self)
return self.name:upper() -- Always return uppercase
end,
age = function(self)
return self.age
end,
isAdult = function(self)
return self.age >= 18
end
},
-- can be used to organize your code as well just like JS classes
set = {
name = function(self, value)
if type(value) ~= "string" then
error("Name must be a string")
end
self.name = value
end,
age = function(self, value)
if type(value) ~= "number" or value < 0 then
error("Age must be a positive number")
end
self.age = value
end
}
})
local person = Person:New("john", 25)
-- Using getters
print(person.name) -- "JOHN" (automatic uppercase)
print(person.isAdult) -- true
-- Using setters
person.name = "jane" -- Validates and stores
person.age = 30 -- Validates and storesPrivate Properties & Methods#
Members starting with underscore _ are private and can only be accessed from within the same class.
local BankAccount = Lib.Class:Create({
constructor = function(self, accountNumber, initialBalance)
self._accountNumber = accountNumber -- Private
self._balance = initialBalance -- Private
self.accountType = "Checking" -- Public
end,
-- Public method that accesses private members
getBalance = function(self)
self:_validateAccess() -- Private method call
return self._balance
end,
deposit = function(self, amount)
if amount > 0 then
self._balance = self._balance + amount
return true
end
return false
end,
-- Private method
_validateAccess = function(self)
print("Validating access to account " .. self._accountNumber)
end,
-- Private method
_calculateInterest = function(self)
return self._balance * 0.01
end
}, "BankAccount")
local account = BankAccount:New("12345", 1000)
-- ✅ Public access
print(account:getBalance()) -- 1000
account:deposit(500)
-- ❌ Private access will error
-- print(account._balance) -- ERROR
-- account:_validateAccess() -- ERRORInheritance & Privacy#
Private members are class-specific and cannot be accessed by subclasses.
local Vehicle = Lib.Class:Create({
constructor = function(self, model)
self._engine = "V8" -- Private to Vehicle
self.model = model -- Public
end,
getEngineInfo = function(self)
return "Engine: " .. self._engine -- ✅ Same class access
end,
_startEngine = function(self)
print("Starting " .. self._engine .. " engine")
end
})
local Car = Lib.Class:Create(Vehicle, "Car")
function Car:constructor(model, doors)
self:super(model)
self.doors = doors
-- self._engine = "Modified" -- ❌ Would error - can't access parent private
end
function Car:tryAccessPrivate()
-- ❌ Cannot access parent's private members
-- local engine = self._engine -- ERROR
-- self:_startEngine() -- ERROR
print("Cannot access parent private members")
end
local car = Car:New("Mustang", 2)
print(car:getEngineInfo()) -- ✅ "Engine: V8" (via public method)
car:tryAccessPrivate() -- Shows privacy enforcementComplete Example#
comprehensive class system example
-- Import the class module
local Lib = Import 'class' --[[@as CLASS]]
-- Base Entity class
local Entity = Lib.Class:Create({
constructor = function(self, data)
self._id = data.id or 0 -- Private ID
self._position = data.pos or vector3(0,0,0) -- Private position
self.name = data.name or "Entity" -- Public name
self._created = os.time() -- Private creation time
end,
-- Public methods
getId = function(self)
return self._id
end,
getPosition = function(self)
return self._position
end,
setPosition = function(self, pos)
self._position = pos
self:_onPositionChanged() -- Private method call
end,
getAge = function(self)
return os.time() - self._created
end,
-- Private methods
_onPositionChanged = function(self)
print("Entity " .. self._id .. " moved to " .. tostring(self._position))
end,
-- Automatic getters/setters
get = {
displayName = function(self)
return self.name .. " (#" .. self._id .. ")"
end
},
set = {
name = function(self, value)
if type(value) ~= "string" or #value == 0 then
error("Name must be a non-empty string")
end
self.name = value
end
}
}, "Entity")
-- Ped class inheriting from Entity
local Ped = Lib.Class:Create(Entity, "Ped")
function Ped:constructor(data)
self:super(data) -- Call parent constructor
self._model = data.model or "A_M_M_FARMER_01" -- Private model
self._health = data.health or 100 -- Private health
self.faction = data.faction or "Civilian" -- Public faction
end
function Ped:spawn()
local pos = self:getPosition()
local handle = CreatePed(joaat(self._model), pos.x, pos.y, pos.z, 0.0, true, false, false, false)
self._handle = handle
print("Spawned " .. self.displayName .. " at " .. tostring(pos))
return handle
end
function Ped:damage(amount)
self._health = math.max(0, self._health - amount)
if self._health <= 0 then
self:_onDeath()
end
end
-- Private method
function Ped:_onDeath()
print(self.displayName .. " has died")
if self._handle then
DeletePed(self._handle)
end
end
-- Getters for private properties
Ped.get.health = function(self)
return self._health
end
Ped.get.model = function(self)
return self._model
end
-- Usage
local ped = Ped:New({
id = 123,
name = "John Marston",
pos = vector3(100, 200, 300),
model = "CS_JOHNMARSTON",
health = 150,
faction = "Van der Linde Gang"
})
-- Public interface
print(ped.displayName) -- "John Marston (#123)"
print("Health:", ped.health) -- 150 (via getter)
print("Age:", ped:getAge(), "seconds old")
ped:setPosition(vector3(150, 250, 350))
ped:spawn()
ped:damage(50)
print("Health after damage:", ped.health) -- 100
-- Validation works
ped.name = "Arthur Morgan" -- ✅ Valid
-- ped.name = "" -- ❌ Would error
-- Privacy enforced
-- print(ped._health) -- ❌ Would error
-- ped:_onDeath() -- ❌ Would error
Traditional Lua Style#
using traditional lua function syntax
local Lib = Import 'class' --[[@as CLASS]]
-- Create class with traditional Lua methods
local Timer = Lib.Class:Create({},"Timer")
function Timer:constructor(name, duration)
self.name = name or "Timer"
self._startTime = nil
self._duration = duration or 5000
self._isRunning = false
end
function Timer:start()
self._startTime = GetGameTimer()
self._isRunning = true
print(self.name .. " started for " .. self._duration .. "ms")
end
function Timer:stop()
self._isRunning = false
print(self.name .. " stopped")
end
function Timer:isExpired()
if not self._isRunning or not self._startTime then
return false
end
return (GetGameTimer() - self._startTime) >= self._duration
end
function Timer:getTimeLeft()
if not self._isRunning or not self._startTime then
return 0
end
local elapsed = GetGameTimer() - self._startTime
return math.max(0, self._duration - elapsed)
end
-- Usage
local timer = Timer:New("Countdown", 10000)
timer:start()
-- Check in a loop or thread
CreateThread(function()
while not timer:isExpired() do
print("Time left:", timer:getTimeLeft() .. "ms")
Wait(1000)
end
print("Timer expired!")
timer:stop()
end)
Functions#
utility classes for control flow, timing, and conditional execution provides Switch-case patterns, repeating intervals, and one-time timeouts with full control over execution state shared between server and client environments
Switch#
use these utilities for advanced control flow and timing operations
valueanyThe value to match against cases
creates a switch-case control structure that allows chaining case statements and default handling inspired by JS
-- Import the functions module
local Lib = Import 'functions' --[[@as FUNCTIONS]]
-- Basic switch usage
local result = Lib.Switch(playerLevel)
:case(1, function(value)
return "Beginner"
end)
:case(2, function(value)
return "Intermediate"
end)
:case(3, function(value)
return "Advanced"
end)
:default(function(value)
return "Unknown Level: " .. value
end)
:execute()
print(result)SetInterval#
callbackfunctionrequiredFunction to execute repeatedly
delayintegerrequiredDelay between executions in milliseconds
customArgstableArguments to pass to the callback function
startbooleanWhether to start the interval immediately
returnIntervalrequiredReturns an Interval instance for control
creates a repeating interval that executes a function at specified intervals
-- Import the functions module
local Lib = Import 'functions' --[[@as FUNCTIONS]]
-- Create an interval that runs every 5 seconds
local healthCheck = Lib.SetInterval(function(self, playerId)
local player = GetPlayerPed(playerId)
if player and DoesEntityExist(player) then
local health = GetEntityHealth(player)
print("Player " .. playerId .. " health: " .. health)
self:Destroy() -- destroy the interval
end
end, 5000,{GetPlayerServerId(PlayerId())}, true)GetState#
returnbooleanReturns true if interval is running, false if paused
returns the current state of the interval
local isRunning = healthCheck:GetState()
print("Interval running: " .. tostring(isRunning))SetTimeout#
callbackfunctionrequiredFunction to execute after delay
delayintegerrequiredDelay before execution in milliseconds
customArgstableArguments to pass to the callback function
returnTimeoutrequiredReturns a Timeout instance for control
creates a one-time delayed execution that can be controlled
-- Import the functions module
local Lib = Import 'functions' --[[@as FUNCTIONS]]
-- Create a timeout that executes after 10 seconds
local delayedAction = Lib.SetTimeout(function(message, playerId)
print("Delayed message: " .. message)
end, 10000, {"Welcome to the server!", PlayerId()})GetState#
returnbooleanReturns true if timeout is active, false if paused/executed
Pause#
returnnilPauses the timeout, preventing execution
Resume#
...anyNew arguments to pass to the callback accepts update arguments too like the update method
Update#
...anyNew arguments to pass to the callback
updates the callback arguments
delayedAction:Update("Modified message", differentPlayerId)Destroy#
returnnilCancels and cleans up the timeout completely
Logger#
this shared module is used to print formatted logs with timestamps, log levels, optional prefixes and structured context
the base console already provides the resource name, so the logger output only adds time, level and your message
by default DEBUG logs are disabled until you enable them with SetDebugEnabled(true) or force them with the debug option
Import#
local Logger = Import('logger').Logger --[[@as LOGGER]]Output Format#
[12:34:56] [INFO] message
[12:34:56] [WARN] [BANK] message | charId=1 money=250
[12:34:56] [ERROR] something failedLog#
Base method used by all other log helpers
levelstringrequiredSupported values are INFO, WARN, ERROR and DEBUG
...anyMessage parts, values are concatenated in order
contexttableOptional context table appended as key=value pairs
options.prefixstringOptional prefix displayed before the message body
options.debugbooleanForces a DEBUG log even when debug mode is disabled
options.colorizebooleanSet to false to disable console colors
local Logger = Import('logger').Logger --[[@as LOGGER]]
Logger:Log('INFO', 'player connected', {
charId = 12,
source = 4
}, {
prefix = 'CHARACTER'
})Info / Warn / Error / Debug#
Shorthand helpers for the supported log levels
local Logger = Import('logger').Logger --[[@as LOGGER]]
Logger:Info('inventory loaded')
Logger:Warn('low ammo', { weapon = 'WEAPON_REPEATER_CARBINE' })
Logger:Error('failed to save character', { charId = 5 })
Logger:SetDebugEnabled(true)
Logger:Debug('debug output enabled')SetDebugEnabled#
Enables or disables debug output globally for this logger instance
enabledbooleanrequiredSet to true to allow DEBUG logs, false to disable them
GetDebugEnabled#
Returns the current debug state
returnbooleantrue if debug logs are enabled, otherwise false
Client Example#
local Logger = Import('logger').Logger --[[@as LOGGER]]
Logger:Info('client logger info output', {
side = 'client',
ped = PlayerPedId()
}, {
prefix = 'TEST'
})Server Example#
local Logger = Import('logger').Logger --[[@as LOGGER]]
Logger:SetDebugEnabled(true)
Logger:Debug('server logger debug output', {
side = 'server',
source = source
}, {
prefix = 'TEST'
})Exports#
Selector#
This Selector allows you to select players with a NUI selector that will return the player id that was selected
Select#
allow_selfbooleanAllow self selection
amount_of_playersintegerAmount of players to select
distancenumberDistance to select players
allow_in_vehiclebooleanAllow selection of players in vehicles
allow_on_horsebooleanAllow selection of players on horses
playeridintegerThe player id that was selected
local result <const> = exports.jrs_core:Select({
allow_self = true,
amount_of_players = 4,
distance = 8.0,
allow_in_vehicle = true,
allow_on_horse = true
})ProgressBar#
Allows you to create a progress bar that will be displayed on screen for a specified amount of time
Start#
textstringrequiredText to display in the progress bar
colorstablerequiredTable with the colors for the progress bar startColor and endColor are the colors for the text and backgroundColor and fillColor are the colors for the background and the fill of the progress bar image
durationintegerrequiredDuration in milliseconds for the progress bar
typestringrequiredType of progress bar only linear is avaliable for now
positiontablerequiredTable with the position for the progress bar on screen top and left are the position in % for the progress bar
imagestringImage for the progress bar only png is avaliable for now
callbackfunctionCallback function if you want to use it as async
returnbooleanthe result of the progress bar true or false if false the progress bar was cancelled
local data = {
text = 'Some text here',
colors = {
-- for text
startColor = 'white', -- starting color of the text
endColor = 'black', -- ending color of the text
-- these colors are filters they dont really represent the color that well but its an option if you want to change it
-- for background
-- https://colorpicker.dev/#21d70d use this website choose hwb and its the first number just add deg to it like this 330deg
-- backgroundColor = '0deg', -- Changes grey bar to blue-ish
--fillColor = '120deg', -- Changes white bar to green-ish
},
duration = 5000,
type = 'linear', -- only linear is avaliable for now
position = { top = 90, left = 50 }, -- in % for position on the screen
image = 'score_timer_extralong', -- only png this is optional you can add your own image , images must be in this script images folder
}
-- SYNC
local result = exports.jrs_core:progressStart(data)
if not result then
print('cancelled')
else
print('completed')
end
--OR ASYNC
exports.jrs_core:progressStart(data, function(result)
if result then
print('Progress bar completed')
else
print('Progress bar cancelled')
end
end)Cancel#
cancel the progress bar
exports.jrs_core:progressCancel()Copy#
Allows you to send a clipboard copy request from jrs_core NUI.
copyToClipBoard#
textstringrequiredText to copy to the clipboard
exports.jrs_core:copyToClipBoard("Hello from jrs_core")Density#
Allows you to inspect or change the population density multipliers handled by jrs_core at runtime.
The module keeps a default value and can also apply a temporary override. When a temporary value exists, it is used first. When no temporary value exists, the default value is used.
Valid density names are:
"AnimalDensity"
"HumanDensity"
"PedDensity"
"VehicleDensity"
"ScenarioAnimalDensity"
"ScenarioHumanDensity"
"ScenarioPedDensity"
"ParkedVehicleDensity"
"RandomVehicleDensity"GetDensityMultipliers#
namestringDensity name. If omitted, the export returns the full multipliers table.
returntableReturns either one density entry or the full density table. A single entry contains the configured value, and can also contain temp_value when a temporary override is active.
local allMultipliers = exports.jrs_core:GetDensityMultipliers()
local vehicleDensity = exports.jrs_core:GetDensityMultipliers("VehicleDensity")
print(vehicleDensity.value, vehicleDensity.temp_value)SetDefaultDensityMultipliers#
sourceintegerrequiredTarget player source or -1 for all.
namestringrequiredOne of the valid density names listed above.
valuenumberrequiredDensity multiplier value. Use values between 0.0 and 1.0.
local target <const> = source
exports.jrs_core:SetDefaultDensityMultipliers(target, "VehicleDensity", 0.2)SetTemporaryDensityMultipliers#
sourceintegerrequiredTarget player source or -1 for all.
namestringrequiredOne of the valid density names listed above.
valuenumberrequiredDensity multiplier value, Use values between 0.0 and 1.0.
timerintegerOptional time in seconds before the temporary density override is removed automatically.
local target <const> = source
exports.jrs_core:SetTemporaryDensityMultipliers(target, "VehicleDensity", 0.2)RemoveTemporayDensityMultipliers#
sourceintegerrequiredTarget player source or -1 for all.
namestringrequiredOne of the valid density names listed above.
local target <const> = source
exports.jrs_core:RemoveTemporayDensityMultipliers(target, "ScenarioHumanDensity")Collector#
Not yet implemented
Cache#
Cache system to help reduce the amount of most used natives calls like PlayerPedId
CACHE#
CACHE is a Global Client table that contains cached data for Ped,Player,ServerID,Vehicle,Mount,Weapon
these are updated every 5 milliseconds Vehicle, Mount reset to 0 when the player is not in a vehicle or mount
LastVehicle, LastMount, LastWeapon keep the previous value when it changes, they are not reset to 0
returnanyThe cached data
local ped = CACHE.Ped -- current player ped id
local player = CACHE.Player -- current player id
local serverId = CACHE.ServerID -- current player server id
local vehicle = CACHE.Vehicle -- current vehicle or 0 if not in a vehicle
local mount = CACHE.Mount -- current mounted entity or 0 if not mounted
local weapon = CACHE.Weapon -- current held weapon
local isDead = CACHE.IsDead -- current player is dead or not
local lastVehicle = CACHE.LastVehicle -- last vehicle the player was in
local lastMount = CACHE.LastMount -- last mount the player was on
local lastWeapon = CACHE.LastWeapon -- last weapon the player heldCACHE#
these allow you to have more control over the cache system, by default all are false you must disable the ones you dont need
-- at the top of your client file.
CACHE.SkipWeapon = true -- no need for weapon cache
CACHE.SkipVehicle = true -- no need for vehicle cache
CACHE.SkipMount = true -- no need for mount cache
CACHE.Wait = 500 -- by default is 500 , you can adjust to your needsOnPedChange#
register a callback that is called when the player ped changes, the new ped id is passed to the callback
callbackfunctionrequiredThe function called with the new ped id when the player ped changes
CACHE.OnPedChange(function(pedId)
print('ped changed', pedId)
end)OnPlayerDeath#
register a callback that is called when the player dies, relies on the IsDead check so CACHE.SkipIsDead must stay false
callbackfunctionrequiredThe function called when the player dies
CACHE.OnPlayerDeath(function()
print('player died')
end)