> For the complete documentation index, see [llms.txt](https://docs.rainmad.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rainmad.com/resources/3d-interactive-minigames-bundle/reference/exports-and-commands.md).

# Exports & Commands

Every minigame is exposed as a single export, and the resource ships three commands for placement and testing. Everything else (hooks, hack points, state) is driven from `cfg.lua` and `data/saved_minigames.lua`.

***

### Exports

#### Signature

```lua
local ok = exports['rm_3dminigames']:<minigameName>(opts)
```

The call blocks the current thread until the player finishes, fails, or cancels the minigame. `ok` is `true` on success, `false` on anything else. Wrap it in a coroutine or thread if you need to keep other work running.

#### `opts`

Every field is optional.

| Field           | Type   | Notes                                                              |
| --------------- | ------ | ------------------------------------------------------------------ |
| `placement`     | string | `'screen'` (default), `'prop'`, `'monitor'`                        |
| `difficulty`    | string | `'easy'`, `'medium'`, `'hard'`. Falls back to `cfg.<name>.default` |
| `preset`        | string | Prop preset key. Defaults to the placement type                    |
| `_targetEntity` | entity | Required for `placement = 'monitor'` outside a hack point          |
| any other       | any    | Passed straight to the React component as props                    |

The difficulty preset is merged into `opts` first, then your call-site values override on top, then the meta keys are stripped off. See Configuration.

#### Example

```lua
CreateThread(function()
    local success = exports['rm_3dminigames']:untangle({
        difficulty = 'hard',
        timeLimit  = 25,
        placement  = 'screen',
    })

    if success then
        TriggerServerEvent('mypack:server:openVault')
    else
        exports.ox_lib:notify({ type = 'error', description = 'Hack failed.' })
    end
end)
```

#### Full minigame list

```
untangle, colorMatch, rhythmArrows, mathChallenge, pathTracing,
portScanner, dataStreamCapture, terminalHack, firewallBreach, ipTracer,
wireMatching, laserGrid, sequenceBreaker, vaultDrill, packetInterceptor,
cipherWheel, keycardReassembly, powerGrid, chemicalBalance,
fingerprintTrace, dataMatcher, flashPad, frequencyMatch, motionDetector,
cctvSweep, dnaSplicer, signalDescrambler, spinnerLock, wireSnip,
slidingPuzzle, dataConduit, circuitPulse, vaultCombination
```

See Minigames for a description of each one.

***

### Commands

#### `/create_minigame`

Opens an `ox_lib` dialog, spawns a preview prop, attaches a gizmo so you can slide and rotate the prop into place, then writes the point to `data/saved_minigames.lua`.

Fields in the dialog:

| Field      | Notes                                                            |
| ---------- | ---------------------------------------------------------------- |
| Label      | Short identifier for the point. Shows up in server logs          |
| Hack Type  | Preset from `cfg.hacks.types` (fingerprint, laptop, tablet, ...) |
| Minigame   | Which minigame runs on E                                         |
| Difficulty | `easy` / `medium` / `hard`, or blank for the cfg default         |

Left-click empty space to confirm placement. Escape cancels and deletes the preview.

**Access:** admin-gated. See Configuration.

***

#### `/remove_minigame`

Deletes the nearest hack point within 3 metres of the player, removes it from `data/saved_minigames.lua`, and despawns the entity if it was networked. Prints a notify with the label of the removed point.

**Access:** admin-gated.

***

#### `/test_minigame`

Runs a minigame right now, no hack point required.

```
/test_minigame <placement> <name> [difficulty]
```

| Argument   | Notes                                |
| ---------- | ------------------------------------ |
| placement  | `screen` or `prop`                   |
| name       | One of the minigame names above      |
| difficulty | Optional, `easy` / `medium` / `hard` |

Example:

```
/test_minigame screen untangle hard
```

The result (`true` / `false`) is printed to the F8 console. `monitor` placement is intentionally excluded here because it needs an existing world entity, use `/create_minigame` to test that.

**Access:** admin-gated.

***

### State bags

Networked hack types (`laptop_open`, `monitor`) tag their spawned entity with a state bag named `rmHackPoint`. It carries the hack type, coordinates, minigame name and hook overrides. Other resources can read it, but should not write to it:

```lua
local sb = Entity(ent).state.rmHackPoint
if sb and sb.hackType == 'monitor' then
    -- this monitor is a hack point
end
```

{% hint style="warning" %}
Setting this state bag from another resource will confuse the hack-point system. Read only.
{% endhint %}

***

### Events

The resource ships a small handful of net events. All are internal, so do not fire them from other scripts unless you know what you are doing.

| Event                                    | Direction | Purpose                                       |
| ---------------------------------------- | --------- | --------------------------------------------- |
| `rm_3dminigames:server:spawnHackPoint`   | c → s     | Networked spawn from `/create_minigame`       |
| `rm_3dminigames:server:persistHackPoint` | c → s     | Local spawn, server just persists             |
| `rm_3dminigames:server:removeHackPoint`  | c → s     | Delete nearest point                          |
| `rm_3dminigames:client:removeResult`     | s → c     | Feedback for the remove command               |
| `rm_3dminigames:client:removeLocalNear`  | s → c     | Broadcast so every client drops a local point |

Server-side identity check callback:

| Callback                        | Returns                            |
| ------------------------------- | ---------------------------------- |
| `rm_3dminigames:server:isAdmin` | `true` if the caller is authorised |

***

### Localisation

Locale JSON files live in `locales/`. `en.json` ships as the reference. Add another file next to it named after the locale code and translate the values only. Load it in `cfg.lua`:

```lua
lib.locale('de')   -- loads locales/de.json
```

Keep `%d`, `%s` and `{name}`-style placeholders in the same order as the English file. They are filled in at runtime.
