# Server

## Events (General)

### SetBodyCamState

* Registers a **server-side event** to manually control a player's bodycam state, typically used in scenarios such as **temporary permission overrides** or **anti-cheat bypasses**.

<details>

<summary>rcore_police:server:SetBodyCamState</summary>

* **Params:**

  | Name       | Type      | Description                                      |
  | ---------- | --------- | ------------------------------------------------ |
  | `playerId` | `number`  | Target playerId which you want to set permission |
  | `state`    | `boolean` | Used for listening for player state.             |
* **Example:**

```lua
AddEventHandler('rcore_police:server:SetBodyCamState', function(playerId, state)
    -- REGISTER PLAYER TEMP PERMISSION
end)
```

</details>

## Exports (Listeners)

### onGroups

* Used for listening for any onGroups actions

<details>

<summary>onGroups</summary>

* **Params:**

  | Name           | Type     | Description                                          |
  | -------------- | -------- | ---------------------------------------------------- |
  | `listenerName` | `string` | Name of the listener to register for onGroups events |
* **Returns:**
  * `string`: Type - current action/task being done
  * `table`: The data of player in that group
* **Example:**

```lua
-- return: type: string, data: table
exports["rcore_police"]:registerListener("onGroups", function(type, data)
    print("Received 'onGroups' event:")
    print("Type:", type)
    print("Data:", json.encode(data))
end)
```

</details>

### onState

* Used for listening for any interaction actions on players

<details>

<summary>onState</summary>

* **Params:**

  | Name           | Type     | Description                                         |
  | -------------- | -------- | --------------------------------------------------- |
  | `listenerName` | `string` | Name of the listener to register for onState events |
* **Returns:**
  * `type`: Current type (string)
  * `action`: Current action (string)
  * `playerId`: Performed state change on playerId (number)
* **Example:**

```lua
-- return: type: string, action: string, playerId: number
exports["rcore_police"]:registerListener("onGroups", function(type, action, playerId)
    print("Received 'onState' event:")
    print("Type:", type)
    print("Action:", action)
    print("Player ID:", playerId)
end)
```

</details>

## Exports (States)

### IsPlayerCuffed

* Used for checking if player is cuffed

<details>

<summary>IsPlayerCuffed</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                        |
  | ---------- | -------- | -------------------------------------------------- |
  | `playerId` | `number` | ID of player which you want to get state of cuffed |
* **Returns:**
  * `boolean`: `true` if player is cuffed, otherwise `false`.
* **Example:**

```lua
-- playerId: number
-- return: boolean
local isCuffed = exports['rcore_police']:IsPlayerCuffed(playerId)

if isCuffed then
    print('Player is cuffed')
else
    print('Player is not cuffed')
end
```

</details>

### IsPlayerEscorted

* Used for checking if player is escorted

<details>

<summary>IsPlayerEscorted</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                        |
  | ---------- | -------- | -------------------------------------------------- |
  | `playerId` | `number` | ID of player which you want to get state of escort |
* **Returns:**
  * `boolean`: `true` if player is escorted, otherwise `false`.
* **Example:**

```lua
-- playerId: number
-- return: boolean
local isEscorted = exports['rcore_police']:IsPlayerEscorted(playerId)

if isEscorted then
    print('Player is escorted')
else
    print('Player is not escorted')
end
```

</details>

### IsPlayerHeadBagged

* Used for checking if player is head bagged

<details>

<summary>IsPlayerHeadBagged</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                          |
  | ---------- | -------- | ---------------------------------------------------- |
  | `playerId` | `number` | ID of player which you want to get state of head bag |
* **Returns:**
  * `boolean`: `true` if player is head bagged, otherwise `false`.
* **Example:**

```lua
-- playerId: number
-- return: boolean
local isHeadBagged = exports['rcore_police']:IsPlayerHeadBagged(playerId)

if isHeadBagged  then
    print('Player is head bagged')
else
    print('Player is not head bagged')
end
```

</details>

## Exports (Actions)

### JailPlayer

* Used for jailing player, it will open Dialog form to put specific player in jail

<details>

<summary>JailPlayer</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                    |
  | ---------- | -------- | ---------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction |
  | `target`   | `number` | ID of player which you want to get jailed      |
* **Returns:**
  * `boolean`: `true` if player is jailed, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isJailed, statusOrErr = exports['rcore_police']:JailPlayer(playerId, target)

if isJailed then
    print('Player is jailed')
else
    print('Player is not jailed an error occurred:', statusOrErr)
end
```

</details>

### SearchPlayer

* Used for searching player, it will try to open search of target player inventory

<details>

<summary>SearchPlayer</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                     |
  | ---------- | -------- | ----------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction  |
  | `target`   | `number` | ID of player which you want to search inventory |
* **Returns:**
  * `boolean`: `true` if player is searched, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isSearched, statusOrErr = exports['rcore_police']:SearchPlayer(playerId, target)

if isSearched then
    print('Player is searched')
else
    print('Player is not searched an error occurred:', statusOrErr)
end
```

</details>

### Escort

* Used for setting/unsetting escort to target player

<details>

<summary>Escort</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                    |
  | ---------- | -------- | ---------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction |
  | `target`   | `number` | ID of player which you want to get escorted    |
* **Returns:**
  * `boolean`: `true` if player is escorted, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isEscorted, statusOrErr = exports['rcore_police']:Escort(playerId, target)

if isEscorted then
    print('Player is escorted')
else
    print('Player is not escorted')
end
```

</details>

### Zipties

* Used for setting/unsetting Zipties to target player

<details>

<summary>Zipties</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                    |
  | ---------- | -------- | ---------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction |
  | `target`   | `number` | ID of player which you want to set zipties     |
* **Returns:**
  * `boolean`: `true` if player is ziptied, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isZiptied, statusOrErr = exports['rcore_police']:Zipties(playerId, target)

if isZiptied then
    print('Player is ziptied')
else
    print('Player is not ziptied')
end
```

</details>

### Handcuff

* Used for setting/unsetting Handcuff to target player

<details>

<summary>Handcuff</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                    |
  | ---------- | -------- | ---------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction |
  | `target`   | `number` | ID of player which you want to set handcuffs   |
* **Returns:**
  * `boolean`: `true` if player is handcuffs, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isCuffed, statusOrErr = exports['rcore_police']:Handcuff(playerId, target)

if isCuffed then
    print('Player is handcuffed')
else
    print('Player is not handcuffed')
end
```

</details>

### PutPlayerInVehicle

* Used for PutPlayerInVehicle target player into nearby vehicle seat

<details>

<summary>PutPlayerInVehicle</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                     |
  | ---------- | -------- | ----------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction  |
  | `target`   | `number` | ID of player which you want to set into vehicle |
* **Returns:**
  * `boolean`: `true` if player is set into vehicle, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isInVehicle, statusOrErr = exports['rcore_police']:PutPlayerInVehicle(playerId, target)

if isInVehicle then
    print('Player is in vehicle')
else
    print('Player is not in vehicle')
end
```

</details>

### TakePlayerFromVehicle

* Used for TakePlayerFromVehicle target player from nearby vehicle

<details>

<summary>TakePlayerFromVehicle</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                     |
  | ---------- | -------- | ----------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction  |
  | `target`   | `number` | ID of player which you want to get from vehicle |
* **Returns:**
  * `boolean`: `true` if player is outside of vehicle, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isFromVehicle, statusOrErr = exports['rcore_police']:TakePlayerFromVehicle(playerId, target)

if isFromVehicle then
    print('Player is not in vehicle')
else
    print('Player is in vehicle')
end
```

</details>

### RemoveHandcuff

* Used for removing handcuffs/zipties from target player

<details>

<summary>RemoveHandcuff</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name       | Type     | Description                                             |
  | ---------- | -------- | ------------------------------------------------------- |
  | `playerId` | `number` | ID of player which is starting the interaction          |
  | `target`   | `number` | ID of player which you want to remove handcuffs/zipties |
* **Returns:**
  * `boolean`: `true` if player handcuffs/zipties are removed, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- playerId: number
-- target: number
-- return: boolean, string
local isRemovedCuffs, statusOrErr = exports['rcore_police']:RemoveHandcuff(playerId, target)

if isRemovedCuffs then
    print('Player is free')
else
    print('Player not free')
end
```

</details>

### ForceUncuff

* Used for removing zipties/cuffs

<details>

<summary>ForceUncuff</summary>

* **Type:** `boolean`
* **Default value::** `false`
* **Params:**

  | Name     | Type     | Description                                             |
  | -------- | -------- | ------------------------------------------------------- |
  | `target` | `number` | ID of player which you want to remove handcuffs/zipties |
* **Returns:**
  * `boolean`: `true` if player handcuffs/zipties are removed, otherwise `false`.
  * `string`: Status code or error message
* **Example:**

```lua
-- target: number
-- return: boolean, string
local isRemovedCuffs, statusOrErr = exports['rcore_police']:ForceUncuff(target)

if isRemovedCuffs then
    print('Player is free')
else
    print('Player not free')
end
```

</details>

## Exports (General)

### GetPoliceOnline

* Used for getting all police officers online

<details>

<summary>GetPoliceOnline</summary>

* **Type:** `number`
* **Default value::** `0`
* **Returns:**
  * `number`: Number of officers online, by default returns 0 when not any online
* **Example:**

```lua
-- return: number
local policeOnline = exports['rcore_police']:GetPoliceOnline()

if policeOnline then
    print('Online units: ', retval)
end
```

</details>

### CreateInvoiceByServer

> ⚠️ **Warning:** This export is **not** a replacement for your invoice system. It is a hook over the rcore\_police invoice system when using the standalone bridge or a supported invoice system.

> ℹ️ **Configuration:** The distribution of invoice payments depends on the `InvoiceSystem.WhenInvoiceSentBalanceToAllDepartmentJobs` setting in your config:
>
> * **`true`**: The invoice amount will be split equally among all department society accounts
> * **`false`**: Only the issuing job's society account receives the money

* Used for creating an invoice for a player directly from the server-side (e.g., for automated billing systems, admin commands, or integration with other resources)

<details>

<summary>CreateInvoiceByServer</summary>

* **Params:**

  | Name       | Type     | Description                                          |
  | ---------- | -------- | ---------------------------------------------------- |
  | `targetId` | `number` | Player ID of the user who should receive the invoice |
  | `amount`   | `number` | The amount the player should pay                     |
  | `metadata` | `table`  | Additional data containing `job` and `reason`        |
* **Metadata Table:**

  | Name     | Type      | Description                                                                                                                                                                                                                                 |
  | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `job`    | `string?` | The job/department issuing the invoice (e.g., "police", "taxi"). Must be a valid department group defined in your configuration with an existing society account. If not provided, all department groups are used or defaults to `"police"` |
  | `reason` | `string`  | The reason for the invoice                                                                                                                                                                                                                  |
* **Returns:**
  * `boolean`: `true` if the invoice was created successfully, otherwise `false`
* **Example:**

```lua
-- Basic usage: Issue a speeding ticket
local success = exports["rcore_police"]:CreateInvoiceByServer(targetPlayerId, 500, {
    job = "police",
    reason = "Speeding violation - 120 km/h in a 50 km/h zone"
})

if success then
    print("Invoice created successfully")
else
    print("Failed to create invoice")
end
```

```lua
-- Example: Admin command to issue a fine
RegisterCommand("issuefine", function(source, args, rawCommand)
    local targetId = tonumber(args[1])
    local amount = tonumber(args[2])
    local reason = table.concat(args, " ", 3)

    if not targetId or not amount or not reason then
        print("Usage: /issuefine [playerId] [amount] [reason]")
        return
    end

    local success = exports["rcore_police"]:CreateInvoiceByServer(targetId, amount, {
        job = "police",
        reason = reason
    })

    if success then
        print(string.format("Fine of $%d issued to player %d for: %s", amount, targetId, reason))
    else
        print("Failed to issue fine")
    end
end, true) -- restricted to admins
```

</details>

### GetBodyCamPlayers

<details>

<summary>GetBodyCamPlayers</summary>

* **Type:** `(table, string)`
* **Returns:**
  * `table` - Array of active bodycam players
  * `string` - Status code (`"OK"` or `"EMPTY"`)
* **Return Structure:**

```lua
{
    [1] = {
        playerId = 1,                    -- Server player ID
        playerCoords = vector3(x, y, z), -- Player coordinates
        officerName = "John Doe",        -- Character name
        location = ""                    -- Location string
    },
    [2] = { ... }
}
```

* **Example:**

```lua
---@return table retval         -- Array of bodycam player data
---@return string statusCode    -- "OK" | "EMPTY"
local retval, statusCode = exports["rcore_police"]:GetBodyCamPlayers()

if statusCode == "OK" then
    for _, bodycam in ipairs(retval) do
        print("Officer:", bodycam.officerName, "ID:", bodycam.playerId)
    end
end
```

</details>

***

### SpectateBodycam

<details>

<summary>SpectateBodycam</summary>

* **Type:** `(boolean, string)`
* **Parameters:**
  * `playerId` (number) - The player who will spectate
  * `officerPlayerId` (number) - The officer whose bodycam to spectate
* **Returns:**
  * `boolean` - Success state
  * `string` - Status code (`"OK"`, `"INVALID_PLAYER_ID"`, `"INVALID_OFFICER_ID"`, `"SAME_PLAYER"`, `"NO_ACTIVE_BODYCAM"`)
* **Example:**

```lua
---@param playerId number        -- Player who will spectate
---@param officerPlayerId number -- Officer with active bodycam
---@return boolean retval        -- Success state
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID" | "INVALID_OFFICER_ID" | "SAME_PLAYER" | "NO_ACTIVE_BODYCAM"
local retval, statusCode = exports["rcore_police"]:SpectateBodycam(playerId, officerPlayerId)
```

</details>

***

### ActivateOfficerBodycam

<details>

<summary>ActivateOfficerBodycam</summary>

* **Type:** `(void)`
* **Parameters:**
  * `playerId` (number) - The officer player ID to activate bodycam for
* **Returns:**
  * `void` - Toggles bodycam state (activates if inactive, deactivates if active)
* **Example:**

```lua
---@param playerId number -- Officer player ID
exports["rcore_police"]:ActivateOfficerBodycam(playerId)
```

</details>

***

### DeactivateOfficerBodycam

<details>

<summary>DeactivateOfficerBodycam</summary>

* **Type:** `(void)`
* **Parameters:**
  * `playerId` (number) - The officer player ID to deactivate bodycam for
* **Returns:**
  * `void` - Toggles bodycam state (activates if inactive, deactivates if active)
* **Example:**

```lua
---@param playerId number -- Officer player ID
exports["rcore_police"]:DeactivateOfficerBodycam(playerId)
```

</details>

***

### GetActiveTackles

<details>

<summary>GetActiveTackles</summary>

* **Type:** `(table, string)`
* **Returns:**
  * `table` - Registry of active tackles
  * `string` - Status code (`"OK"` or `"EMPTY"`)
* **Return Structure:**

```lua
{
    [1] = {
        initiator = 1,           -- Server player ID of the cop doing the tackle
        target = 2,              -- Server player ID of the person being tackled
        startTime = 123456789    -- GetGameTimer() when tackle started
    },
    [2] = { ... }
}
```

* **Example:**

```lua
---@return table retval         -- TackleRegistry table
---@return string statusCode    -- "OK" | "EMPTY"
local retval, statusCode = exports["rcore_police"]:GetActiveTackles()

if statusCode == "OK" then
    for tackleId, tackle in pairs(retval) do
        print("Tackle #" .. tackleId .. ": Cop " .. tackle.initiator .. " tackling " .. tackle.target)
    end
end
```

</details>

***

### IsTackled

<details>

<summary>IsTackled</summary>

* **Type:** `(boolean, string)`
* **Parameters:**
  * `playerId` (number) - The player ID to check
* **Returns:**
  * `boolean` - Whether the player is currently tackled
  * `string` - Status code (`"OK"` or `"INVALID_PLAYER_ID"`)
* **Example:**

```lua
---@param playerId number        -- Player ID to check
---@return boolean retval        -- Is player tackled
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID"
local retval, statusCode = exports["rcore_police"]:IsTackled(playerId)

if retval then
    print("Player is currently tackled!")
end
```

</details>

***

### GetPlayerTackleInfo

<details>

<summary>GetPlayerTackleInfo</summary>

* **Type:** `(table|nil, string)`
* **Parameters:**
  * `playerId` (number) - The player ID to get tackle info for
* **Returns:**
  * `table|nil` - Tackle info object or nil if not tackled
  * `string` - Status code (`"OK"`, `"INVALID_PLAYER_ID"`, `"NOT_TACKLED"`, `"TACKLE_NOT_FOUND"`)
* **Return Structure:**

```lua
{
    tackleId = 1,            -- Unique tackle identifier
    role = "initiator",      -- "initiator" (cop) or "target" (tackled player)
    initiator = 1,           -- Server player ID of the cop doing the tackle
    target = 2,              -- Server player ID of the person being tackled
    startTime = 123456789    -- GetGameTimer() when tackle started
}
```

* **Example:**

```lua
---@param playerId number        -- Player ID to get info for
---@return table|nil retval      -- Tackle info object
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID" | "NOT_TACKLED" | "TACKLE_NOT_FOUND"
local retval, statusCode = exports["rcore_police"]:GetPlayerTackleInfo(playerId)

if retval then
    print("Role:", retval.role)
    print("Initiator:", retval.initiator)
    print("Target:", retval.target)
    print("Duration:", GetGameTimer() - retval.startTime, "ms")
end
```

</details>

***

### RemoveTackleByPlayer

<details>

<summary>RemoveTackleByPlayer</summary>

* **Type:** `(boolean, string)`
* **Parameters:**
  * `playerId` (number) - The player ID involved in the tackle
  * `skipClientReset` (boolean, optional) - Skip sending client reset events
* **Returns:**
  * `boolean` - Success state
  * `string` - Status code (`"OK"`, `"INVALID_PLAYER_ID"`, `"NOT_TACKLED"`, `"TACKLE_NOT_FOUND"`)
* **Example:**

```lua
---@param playerId number        -- Player ID to remove tackle for
---@param skipClientReset boolean? -- Optional: skip client reset
---@return boolean retval        -- Success state
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID" | "NOT_TACKLED" | "TACKLE_NOT_FOUND"
local retval, statusCode = exports["rcore_police"]:RemoveTackleByPlayer(playerId)

if retval then
    print("Tackle removed successfully!")
else
    print("Failed to remove tackle:", statusCode)
end
```

</details>
