Integration and exports
Add options from your scripts: tcmenu, exports, events, ox_target / qb-target compatibility.
There are three ways to add options:
| Way | For whom | Permanent |
|---|---|---|
/gestioncontexte (Options tab) | The admin, without touching code | Yes (database) |
Config.Options in config.lua | Whoever prefers a file | Yes (reloaded at every start) |
| In a script's code | The script developer | As long as the script runs |
#In a script: the simplest method
shared_script '@tc-contextmenu/init.lua'tcmenu.add({
label = 'Search', icon = 'search', types = { 'player' }, distance = 2.5,
require = { jobs = { police = 0 } },
onSelect = function(ctx) TriggerServerEvent('myscript:search', ctx.serverId) end,
})If tc-contextmenu is missing or starts after your script, calls are queued then replayed (also if it restarts). Options disappear when your script stops.
#tcmenu functions
| Side | Functions |
|---|---|
| Client | add, addMany, addModel, addGlobal, addGlobalPlayer / Ped / Vehicle / Object / Self / World, addLocalEntity, addEntity, addSphereZone, addBoxZone, remove, removeZone, open, close, isOpen, disable |
| Server | register, unregister, addOption, removeOption, getOptions |
tcmenu.ready() tells whether tc-contextmenu is started.
#Fields of a code option
| Field | Role |
|---|---|
key | Unique key (final: <your_resource>:<key>) |
label | Text (or function function(ctx) return '…' end) |
icon | Icon name, emoji or image URL |
types | { 'player', 'ped', 'vehicle', 'object', 'world', 'self' } |
models | Targeted models (names or hashes) |
distance | Maximum distance |
require | { jobs = { police = 0 }, items = { glove = 1 }, admin = true, ace = '…', inVehicle = true, onDuty = true } |
canInteract | function(ctx) return true end — dynamic condition |
onSelect | function(ctx) — Lua action |
type, parent | submenu / separator, and key of the parent submenu |
#Submenu and conditions
tcmenu.add({ key = 'police', type = 'submenu', label = 'Police', icon = 'shield', types = { 'player' },
require = { jobs = { police = 0 } } })
tcmenu.add({ parent = 'police', label = 'Handcuff', icon = 'lock', types = { 'player' },
canInteract = function(ctx) return not IsPedCuffed(ctx.entity) end,
onSelect = function(ctx) TriggerServerEvent('myscript:cuff', ctx.serverId) end })#Dynamic label and item condition
tcmenu.add({
label = function(ctx) return ('Search the bin (%s)'):format(ctx.model) end,
types = { 'object' }, models = { 'prop_bin_01a', 'prop_dumpster_01a' },
require = { items = { glove = 1 } }, -- checked server-side
onSelect = function(ctx) print('bin', ctx.entity) end,
})#Without writing a function
tcmenu.add({ label = 'Talk', types = { 'ped' }, serverEvent = 'myscript:talk', args = { topic = 'rumor' } })
tcmenu.add({ label = 'Call', types = { 'player' }, command = 'phone' })
tcmenu.add({ label = 'Open', types = { 'vehicle' }, export = 'myscript.open' }) -- client: (ctx, args)
tcmenu.add({ label = 'Seize', types = { 'vehicle' }, serverExport = 'myscript.seize' }) -- server: (src, ctx, args)#ox_target and qb-target compatible
Replace exports.ox_target or exports['qb-target'] with exports['tc-contextmenu']: same functions, same fields.
Functions: addModel, addEntity (netId), addLocalEntity, addGlobalPlayer / Ped / Vehicle / Object, addSphereZone, addBoxZone, removeZone, removeModel…
Fields: label, icon (the fa-solid fa-car format is accepted), distance, groups, items, canInteract(entity, distance, coords, name), onSelect(data), export, event, serverEvent, command.
exports['tc-contextmenu']:addGlobalVehicle({
{ label = 'Repair', icon = 'fa-solid fa-wrench', groups = { mechanic = 0 }, event = 'myscript:repair' },
})Functions: AddTargetModel, AddTargetEntity, AddGlobalPlayer / Ped / Vehicle / Object, AddCircleZone, AddBoxZone, RemoveZone, RemoveTargetModel…
Fields: label, icon, event, type, job, item, action(entity), canInteract, and the { options = {...}, distance = 2.5 } form.
Zones are spherical (a box becomes an enclosing sphere) and bones (bones) are ignored.
#With no dependency at all
TriggerEvent('tc-contextmenu:add', { label = 'Search', types = { 'player' }, serverEvent = 'myscript:search' }, GetCurrentResourceName())
TriggerEvent('tc-contextmenu:remove', 'search', GetCurrentResourceName())#From a server script
-- not persistent, removed when the script stops
exports['tc-contextmenu']:register({ label = 'Talk', types = { 'ped' }, serverEvent = 'myscript:talk' })
-- PERMANENT, in the database (editable with /gestioncontexte)
exports['tc-contextmenu']:addOption({
key = 'ped_talk', label = 'Talk', icon = 'phone',
target = { types = { 'ped' } }, distance = 3.0,
action = { type = 'server_event', name = 'myscript:talk', args = { topic = 'rumor' } },
})
-- also: TriggerEvent('tc-contextmenu:server:register', def, 'my_resource')#Exports reference
| Side | Exports |
|---|---|
| Client | add, addMany, remove, open, close, isOpen, disable(true|false), + the ox_target / qb-target names above |
| Server | register, unregister, addOption, removeOption, getOptions |
#Full example (by code)
An examples file (examples/examples.lua) ships with the script; it is not loaded by the manifest, copy what you need:
-- Exemples d'options ajoutées PAR CODE (client). À copier dans ton propre script, ce fichier n'est pas chargé par le manifest.
-- Les options sont retirées automatiquement quand ta ressource s'arrête.
local CM = exports['tc-contextmenu']
-- 1. Bouton simple sur les véhicules, avec callback Lua
CM:add({
key = 'veh_lock', -- clé finale : "<ta_ressource>:veh_lock"
label = 'Verrouiller / déverrouiller',
icon = 'lock',
target = { types = { 'vehicle' } },
distance = 5.0,
onSelect = function(ctx)
local lock = GetVehicleDoorLockStatus(ctx.entity)
SetVehicleDoorsLocked(ctx.entity, lock == 2 and 1 or 2)
end,
})
-- 2. Sous-menu + enfants, réservés à un métier
CM:add({ key = 'police', type = 'submenu', label = 'Police', icon = 'shield', target = { types = { 'player' } },
require = { jobs = { police = 0 } } })
CM:add({ parent = 'police', label = 'Fouiller', icon = 'search', target = { types = { 'player' } },
onSelect = function(ctx) TriggerServerEvent('monscript:fouiller', ctx.serverId) end })
CM:add({ parent = 'police', label = 'Menotter', icon = 'lock', target = { types = { 'player' } },
canInteract = function(ctx) return not IsPedCuffed(ctx.entity) end, -- condition dynamique
onSelect = function(ctx) TriggerServerEvent('monscript:menotter', ctx.serverId) end })
-- 3. Libellé dynamique + condition d'objet (vérifiée côté serveur) sur un modèle précis
CM:add({
label = function(ctx) return ('Fouiller la poubelle (%s)'):format(ctx.model) end,
target = { types = { 'object' }, models = { 'prop_bin_01a', 'prop_dumpster_01a' } },
require = { items = { gant = 1 } },
onSelect = function(ctx) print('poubelle', ctx.entity) end,
})
-- 4. Option PERMANENTE créée depuis un script serveur (stockée en base, modifiable avec /gestioncontexte) :
-- exports['tc-contextmenu']:addOption({
-- key = 'pnj_parler', label = 'Parler', icon = 'phone',
-- target = { types = { 'ped' } }, distance = 3.0,
-- action = { type = 'server_event', name = 'monscript:parler', args = { sujet = 'rumeur' } },
-- })