โšกHooks

The runner exposes a set of hooks that let you inject custom logic into the lab lifecycle without modifying core files. All hooks are optional โ€” pass them as the third argument to LabProcessRunner.Register() on the client side, or use the standalone server-side functions described below.


Client hooks

Hooks are passed as a table when registering the lab:

LabProcessRunner.Register('heroin', Config.LabHeroin, {
    onEnter         = function(labType) ... end,
    onExit          = function(labType) ... end,
    onReset         = function() ... end,
    onStageComplete = function(stageId, result) ... end,
})

onEnter(labType)

Called immediately after the runner creates all interaction points, every time a player enters a lab of this type.

Use cases:

  • Load custom props / IPLs specific to the lab

  • Query the server for pre-existing state (e.g. which plants were already harvested)

  • Start a custom thread that runs while inside

onEnter = function(labType)
    -- Ask the server which plants are already taken
    local takenPlants = lib.callback.await('origen_gang:labs:weed:getTakenPlants', false)
    for _, idx in ipairs(takenPlants or {}) do
        RemovePlantProp(idx)  -- your custom function
    end
end,

onExit(labType)

Called after the runner removes all interaction points and resets the production state, every time a player exits a lab of this type.

Use cases:

  • Delete custom props spawned on onEnter

  • Cancel any custom threads

  • Clean up client-side state


onReset()

Called by the runner whenever the production cycle is forcibly reset โ€” on exit, on player unload (origen:Client:OnPlayerUnload), and on resource stop.

Use cases:

  • Detach props attached to the ped during a stage (e.g. the meth lab tray prop attached to the hand during grab_tray)

  • Clear any HUD overlays tied to a production cycle

`onReset` is always called before `onExit`. The production state (`stage`, `runTimers`, etc.) is already cleared when your hook runs.


onStageComplete(stageId, result)

Called after the runner finishes processing a stage (progress bar complete, server callback returned success, items delivered). Runs for every stage including the last.

Argument
Type
Description

stageId

string

The ID of the stage that just completed

result

table

The raw server callback response for this stage

result fields (what the server returned):

Field
Present on
Description

success

always

true

timers

first stage only

Effective timers after upgrade modifiers

modifiers

first stage only

{ process_time_mult, output_bonus_pct }

outputs

last stage

Final items delivered (with bonus applied)

bonus_triggered

last stage

true if the output bonus activated

Use cases:

  • Attach / detach props in sync with stage transitions

  • Trigger a custom sound or particle effect on stage complete

  • Show a custom HUD element based on remaining stages


Lifecycle events (client)

The runner listens to these resource-level events automatically for every registered lab. You can also listen to them from your own lab files for custom logic:

Event
When it fires

origen:Lab:OnEnter

Player is teleported inside the lab (arg: labType)

origen:Lab:OnExit

Player exits the lab (arg: labType)

origen:Client:OnPlayerUnload

Player disconnects / character unloads


Server-side lifecycle

The server has no hook table parameter โ€” instead it exposes functions and exports you can call from other scripts:

LabProcessRunner.ResetPlayerState(labType, source)

Force-resets the production state of a single player for a specific lab type. Use this when a script interrupts production externally (e.g. a raid eject).


LabProcessRunner.ResetAllForSource(source)

Clears production state for a player across all registered lab types. Called automatically on exit and playerDropped โ€” use it if you eject a player programmatically.


LabProcessRunner.GetPlayerState(labType, source) โ†’ table | nil

Returns the current in-memory production state for a player in a specific lab type:

Field
Description

stage

Current stage ID, or nil if between cycles

lab_id

DB ID of the lab instance the player is in

timers

Effective timers (post-modifier) computed at cycle start

modifiers

{ process_time_mult, output_bonus_pct }

last_done

os.time() of when the last cycle completed (used for cooldown)


exports('GetPlayerLabState', ...) โ†’ table | nil

Returns which lab a player is currently inside (set by the enter/exit callbacks in server/labs.lua):

This is what all lab server files use to validate "is this player actually in the right lab?".


Per-lab reset exports

Each built-in lab registers its own named reset export for external compatibility:

Export
Lab

MethLabResetPlayerState(source)

Meth

WeedLabResetPlayerState(source)

Weed

CokeLabResetPlayerState(source)

Coke

Custom labs you add should follow the same pattern:


Full hook example โ€” meth tray prop

The meth lab uses onStageComplete and onReset to attach a physical tray prop to the player's hand between stages grab_tray and smash:

Last updated