Skip to content

Events, state bags & commands ​

Events ​

Public ​

EventSideArgumentsNotes
np_helicam:missionReportserver localreportFired once when a mission ends. See below
np_helicam:evidenceserver local{ mission, src, t, data }One evidence screenshot. See below
np_helicam:notifyclient netpayloadShows a toast through np_helicam's notify provider. See below
np_helicam:contextMapclient localtakentrue when np_helicam takes the minimap (camera inset or Air Support map), false right after it restored it. See below
np_helicam:fullscreenclient localontrue while the camera or a live feed fills the screen. See below

The server events are local server events (TriggerEvent), so only server scripts can listen with AddEventHandler. They are not net events. The same goes for np_helicam:contextMap and np_helicam:fullscreen on the client.

np_helicam:missionReport ​

lua
AddEventHandler('np_helicam:missionReport', function(report)
  print(('Mission %s by %s, %d events'):format(report.id, report.meta.operator or '?', #report.events))
  exports.my_mdt:AttachAirReport(report.id, report.text)
end)
FieldTypeDescription
idstringMission id, e.g. 261004-2214-3 (UTC date-time + counter)
metatablecallsign, model, operator (player name), operatorCallsign, startedAt, endedAt (Unix time), endReason, durationMs, screenshots
eventstable[]{ kind, text, t, data? }, t = ms since start. data may hold x, y, z, plate, netId, label
tracktable[]{ t, x, y, z, spd }, sampled on the server every Config.Mission.trackIntervalMs
droppednumberEvents trimmed because of Config.Mission.maxEvents
durationMsnumberLength of the mission
distanceMnumberGround distance of the track
countstableEvents per kind, e.g. { lock = 3, bolo = 1 }
textstringThe plain-text report (also used for the webhook and "Copy report")

endReason is 'stop' (R), 'idle' (camera closed longer than Config.Mission.idleEndMs), 'restart' (a new mission started), 'dropped' (operator disconnected) or 'shutdown' (resource stopped). Event kinds are listed in Operations → Mission recording.

Trivial missions don't fire the event: a mission shorter than 10 s with at most one real event (the start, note and end lines don't count) is discarded without a report, event or webhook post.

np_helicam:evidence ​

lua
AddEventHandler('np_helicam:evidence', function(ev)
  -- ev.mission: mission id, ev.src: operator server id, ev.t: ms since mission start
  -- ev.data: 'data:image/jpeg;base64,...' (typically 100-400 KB)
  exports.my_evidence:Store(ev.mission, ev.src, ev.data)
end)

Fired once per screenshot when B is pressed with Config.Mission.screenshots on and screenshot-basic running. np_helicam does not keep or upload the image. If nobody listens, it is gone.

np_helicam:notify ​

lua
TriggerClientEvent('np_helicam:notify', src, {
  tint = 'red',                     -- neutral red orange rust pink olive lilac green blue aqua (amber → orange, grey → neutral)
  icon = 'helicopter',              -- Font Awesome solid icon name, without 'fa-'
  app = 'AIR SUPPORT',              -- small caption, max 32 chars
  title = 'BOLO',                   -- max 96 chars
  message = 'Plate **46EEK572**',   -- max 512 chars, **bold** only
  ttl = 6000,                       -- ms, clamped to 1000-30000
})

The payload is sanitised on the client (control characters, GTA ~ codes and ^n colour codes are removed) and shown through Config.Notify.provider. At least a title or a message is required.

np_helicam:contextMap ​

While the camera is up, the context map moves the minimap to the top right. While the Air Support panel is open, the minimap sits under the panel's map window. Both share one owner of the radar, so the event fires once when the first of them takes the minimap (true) and once after the last one let go and the layout from Config.ContextMap.restore (GTA's default unless you change it) was put back (false). Switching between the camera inset and the panel doesn't fire it. A HUD that places the minimap itself can listen for this event and re-apply its own layout:

lua
AddEventHandler('np_helicam:contextMap', function(taken)
  if not taken then
    MyHud.applyMinimapLayout() -- np_helicam just restored Config.ContextMap.restore
  end
end)

np_hud handles this already: it leaves the minimap alone while np_helicam has it and re-applies its own layout on false. See Configuration → Context map.

To check the state from a resource that starts later, use the client export IsMinimapHeld.

np_helicam:fullscreen ​

true when the operator camera or a ground unit's live feed opens, false when the last of them closes. Both draw their own full-screen overlay, so a HUD in its own NUI frame should hide for it. np_hud does this already.

lua
AddEventHandler('np_helicam:fullscreen', function(on)
  MyHud.setVisible(not on)
end)

To check the state from a resource that starts later, use the client export IsFullscreen.

Internal ​

These are used between np_helicam's own client and server. Don't trigger or rely on them. Every client → server event is rate-limited and validated on the server.

EventDirectionPurpose
np_helicam:rpc:req / np_helicam:rpc:resclient ↔ serverRequest / response transport for client actions (markers, BOLO check, mission, feed, share, orbit request, units, air:sub, auth)
np_helicam:cam:stateclient → serverOperator's gimbal state, ≤ 5 Hz. The server writes helicam_cam
np_helicam:cam:statusclient → serverOperator's 1 Hz status summary. Kept in server memory
np_helicam:light:stateclient → serverSearchlight state, ≤ 10 Hz. The server writes helicam_light
np_helicam:airUnitsserver → client(list, ended): every live air unit, about 1 Hz, to ground units with the Air Support panel open
np_helicam:airStatusserver → client(netId, status | nil): status of the heli a ground unit is watching
np_helicam:authserver → clientThe player's role flags after a job or duty change
np_helicam:markersserver → clientFull marker list after every change
np_helicam:unitsserver → client(list, ended): friendly unit positions (with veh for units in a vehicle, used for the radar blip), to subscribers only. ended = true when the server dropped the subscription (role lost)
np_helicam:crewShareserver → clientA lock shared by a crew mate

The client also listens to framework events to refresh its role: QBCore:Client:OnPlayerLoaded, QBCore:Client:OnJobUpdate, QBCore:Client:SetDuty, qbx_core:client:playerLoggedIn, esx:playerLoaded, esx:setJob.

State bags ​

Clients write no state bags. The operator sends rate-limited events to the server. The server checks that the sender has the air role and sits in a camera seat of a whitelisted helicopter, cleans the payload, and writes the bag itself. This also makes the copilot's camera and light work, because only the entity's network owner (usually the pilot) could write its bags.

All bags are entity bags on the helicopter, replicated to every client in scope.

BagWritten byRateContent
helicam_camserver≤ 5 Hz, threshold-gatedCamera gimbal only: { on, op, rx, rz, fov, vision, palette }
helicam_lightserver≤ 10 Hz, threshold-gatedSearchlight: { on, dx, dy, dz, lux, beam?, strobe? }. See Searchlight sync
helicam_viewersserveron changeNumber of ground units watching the feed

There is no helicam_status bag any more. See Air unit status.

helicam_cam ​

FieldDescription
ontrue while the camera is up and the operator shares the feed
opOperator's server id, set by the server
rx, rzCamera pitch and heading in degrees (rotation order 2)
fovField of view in degrees
vision0 normal, 1 night vision, 2 FLIR
paletteThermal palette id

The bag deliberately carries no target, position lock or aim point, because it replicates to everyone in scope.

One owner per heli. The first crew member whose camera sends a state owns the bag. A second operator in the same heli doesn't overwrite it. When the owner closes the camera, turns Share feed off or leaves, the bag goes off, and the next crew member to send takes it over.

Air unit status ​

The operator's status (mode, vision, zoom, light, fuel, street and zone, the target with model, plate, colour, speed, heading and position, and the aim point) is not replicated. The server keeps the latest one per heli in memory and pushes it only to:

  • ground units with the Air Support panel open (np_helicam:airUnits, about 1 Hz, with every live air unit and its server-side position), and
  • the heli's feed viewers (np_helicam:airStatus).

The callsign and operator id in the status are set by the server, not taken from the client.

Cleanup ​

When the camera closes or the operator turns Share feed off, the server sets helicam_cam to { on = false } and drops the status. Every second the server releases feeds whose owner left the seat, lost the air role, disconnected, or whose heli is gone, and ends their viewers' feeds. A 10 s sweep also switches off any lit helicam_light or live helicam_cam bag whose owner is no longer valid. On resource stop, the server turns off every bag it wrote.

Commands ​

CommandWhoDescription
/bolo add <plate> <reason...>Config.Bolo.commandJobs role (default bolo), or the server consoleAdd a BOLO. The callsign is stored as by
/bolo remove <plate>sameRemove a BOLO
/bolo listsameThe 10 newest BOLOs (and how many more) as a toast, or printed in the console

The command is not ACE-restricted. The role check is the gate, so it works with job-based permissions. One /bolo per 2 s per player. The registry holds at most 500 BOLOs; the oldest is dropped.

Key mapping commands ​

These are registered as commands so they can be bound in FiveM's key settings. They are listed with their default keys under Controls:

helicam, helicam_vision, helicam_palette, helicam_overlay, helicam_lock, helicam_heat, helicam_mark, helicam_record, helicam_bookmark, helicam_share, helicam_light, helicam_luxup, helicam_luxdown, helicam_beam, helicam_strobe, helicam_hover, helicam_settings, helicam_air.

np_* FiveM resources