> For the complete documentation index, see [llms.txt](https://jiffyjrdevelopment.gitbook.io/jiffyjrdevelopmentdocs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jiffyjrdevelopment.gitbook.io/jiffyjrdevelopmentdocs/jiffy-jr-development-docs/jiffy-metal-detectors-docs/changelog.md).

# Changelog

Hooks let you override or extend the script's built-in auto-detection without editing encrypted core files. Two unencrypted files in the `editable/` folder are provided for this purpose.

| File                        | Purpose                                                         |
| --------------------------- | --------------------------------------------------------------- |
| `editable/client_hooks.lua` | Override notifications, progress bars, and target zones         |
| `editable/server_hooks.lua` | Override dispatch, inventory scanning, and server notifications |

{% hint style="info" %}
All hooks are `nil` by default. Only implement the ones you need. Leaving a hook unset keeps the built-in auto-detection active for that system.
{% endhint %}

### Client Hooks

#### Hooks.Notify

Overrides the client notification system. Called whenever the script notifies the local player.

| Parameter       | Description                            |
| --------------- | -------------------------------------- |
| `msg` (string)  | The notification message               |
| `type` (string) | `'primary'`, `'success'`, or `'error'` |

```lua
-- Example: okokNotify
function Hooks.Notify(msg, type)
    local t = type == 'error' and 'error' or type == 'success' and 'success' or 'info'
    exports['okokNotify']:Alert('Metal Detector', msg, 5000, t)
end
```

#### Hooks.ProgressBar

Overrides the progress bar shown during sabotage and repair actions.

| Parameter             | Description                                              |
| --------------------- | -------------------------------------------------------- |
| `label` (string)      | Text displayed on the bar                                |
| `duration` (number)   | Duration in milliseconds                                 |
| `onFinish` (function) | Call this when the bar completes — do NOT call on cancel |

```lua
-- Example: export-based progress bar
function Hooks.ProgressBar(label, duration, onFinish)
    local cancelled = exports['my_progressbar']:Progress({
        label    = label,
        duration = duration,
    })
    if not cancelled then onFinish() end
end
```

#### Hook.AddTarget/Hooks.RemoveTarget

Overrides the target zone system. If you implement `AddTarget` you must also implement `RemoveTarget` — the script calls both as a pair when detectors are created and destroyed.

```
-- Example: qtarget
function Hooks.AddTarget(detector)
    local id = tostring(detector.id)
    local z  = detector.zone or Config.DefaultZone
    local c  = detector.coords
    exports['qtarget']:AddBoxZone('jiffy_md_' .. id,
        vector3(c.x, c.y, c.z + (z.zOffset or 1.0)),
        math.max(z.width or 1.35, 1.2), math.max(z.length or 1.1, 1.2),
        { name='jiffy_md_'..id, heading=detector.heading or 0.0 },
        { options = {
            { icon='fas fa-bolt',  label='Disable Detector',
              action=function() TriggerServerEvent('jiffy_md:server:precheckSabotage', id) end },
            { icon='fas fa-tools', label='Repair Detector',
              action=function() TriggerServerEvent('jiffy_md:server:precheckRepair', id) end },
        }, distance = Config.Target.distance or 2.0 })
end

function Hooks.RemoveTarget(id)
    exports['qtarget']:RemoveZone('jiffy_md_' .. tostring(id))
end

```

### Server Hooks

#### Hooks.Dispatch

Overrides the dispatch system. Called on full alarms only — not on soft or permit alerts. If set, the built-in ps-dispatch / cd\_dispatch / qs-dispatch detection is skipped.

| Parameter          | Description                                                      |
| ------------------ | ---------------------------------------------------------------- |
| `detector` (table) | Full detector object including coords, name, and settings        |
| `details` (string) | Detected item summary, e.g. `"weapon_pistol [weapons]"`          |
| `jobs` (table)     | List of job name strings to alert, e.g. `{'police', 'security'}` |

```
-- Example: core_dispatch
function Hooks.Dispatch(detector, details, jobs)
    local c = detector.coords
    TriggerEvent('core_dispatch:server:CreateDispatchCall', {
        job_table = jobs,
        coords    = { x=c.x, y=c.y, z=c.z },
        title     = 'Metal Detector Alarm',
        message   = ('Triggered at %s'):format(detector.name or 'Unknown'),
        icon      = 'fas fa-shield-alt',
        color     = '#e74c3c',
    })
end

```

#### Hooks.OnAlarm

Fires alongside the built-in alarm logic — it does not replace it. Use this to add extra behavior like custom logging or webhooks without disabling dispatch or notifications.

| Parameter          | Description                                         |
| ------------------ | --------------------------------------------------- |
| `src` (number)     | Server ID of the player who triggered the alarm     |
| `detector` (table) | Full detector object                                |
| `found` (table)    | List of `{ name, category }` for each detected item |
| `soft` (boolean)   | `true` = soft/permit alert, `false` = real alarm    |

```
function Hooks.OnAlarm(src, detector, found, soft)
    if soft then return end
    TriggerEvent('myLogger:weaponDetected', {
        player   = GetPlayerName(src),
        detector = detector.name,
        items    = found,
    })
end

```

#### Hooks.ScanInventory

Replaces the built-in inventory scan entirely. Use this if your inventory resource is not auto-detected. Must return a table of `{ name, category }` for each found item, or `{}` if nothing is found.

```
function Hooks.ScanInventory(src, detector)
    local found = {}
    local items = exports['my_inventory']:GetPlayerItems(src) or {}
    for _, item in pairs(items) do
        if item.name:find('weapon_') then
            found[#found+1] = { name=item.name, category='weapons' }
        end
    end
    return found
end

```

#### Hooks.ServerNotify

Overrides server-side player notifications. Use this if your notify resource uses a different event name than what the script expects.

```
function Hooks.ServerNotify(src, msg, type)
    if src == 0 then print('[jiffy_md] ' .. msg); return end
    TriggerClientEvent('myNotify:send', src, { message=msg, type=type, duration=5000 })
end

```
