> 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/map-editor-place-anything/exports.md).

# Exports

Four exports, all of them **server-side**: call them from a server script with the player's `source`. There is no client export, so a client that wants the editor triggers an event of its own and the server calls from there.

The editor is a UI another resource can borrow: it places props, hands the list back, and stores nothing of its own unless you asked it to.

## Opening the Editor

```lua
exports.rm_mapeditor:openEditor(source --[[number]], opts --[[table]], cb --[[function]])
```

The callback is required, and it fires exactly once: with the rows when the player is done, or with `nil` when they cancelled, dropped, or the session could not open.

```lua
exports.rm_mapeditor:openEditor(src, {
    origin = shellOrigin,        -- given: results come back as offsets from it
    existing = savedFurniture,   -- the current layout, edited in place
    hidden = savedHides,         -- and the pieces of map it took out of view
    filter = { tags = { 'furniture' } },
    limit = 50,
}, function(result, hidden)
    -- result: rows, or nil when cancelled
    -- hidden: pieces of the map the session took out of view
end)
```

### What Comes Back

A prop row:

```lua
{ model = 'prop_chair_01a', x = 1.5, y = -2.0, z = 0.0, rx = 0.0, ry = 0.0, rz = 90.0,
  solid = true, tint = 3, group = 'Kitchen' }
```

`solid` is false for a prop whose collision was switched off, `tint` is a palette row and absent at 0, `group` is a name and absent for a prop in none. Rotations are degrees, in order 2 (ZXY), the order `SetEntityRotation` wants.

A light row says so:

```lua
{ kind = 'light', x = 1.0, y = 2.0, z = 2.4, rx = -20.0, rz = 90.0, shape = 'spot',
  r = 255, g = 214, b = 170, range = 9.0, intensity = 2.0, angle = 45.0, falloff = 8.0 }
```

And the second argument, the pieces of map the session hid:

```lua
{ model = 1234567890, x = 210.4, y = -1001.2, z = 29.1 }   -- archetype hash
```

{% hint style="warning" %}
Store both halves. A layout is not reproducible from the props alone: some of them stand where the map's own geometry used to, so replaying the props without the hides stands a copy of a wall inside the wall it replaced. Both go back in through `existing` and `hidden`.
{% endhint %}

### Options

| Field      | What                                                                                                           |
| ---------- | -------------------------------------------------------------------------------------------------------------- |
| `origin`   | a `vector3`. Rows come back as offsets from it rather than world coordinates                                   |
| `existing` | rows to open with, edited in place                                                                             |
| `hidden`   | the hides that went with them                                                                                  |
| `limit`    | how many objects this session may place                                                                        |
| `area`     | a zone the session is held to: `{ x, y, z, radius }`, or a polygon `{ points = { vector3, ... }, minZ, maxZ }` |
| `shell`    | build inside an interior, see below                                                                            |
| `filter`   | what the picker offers: `categories`, `excludeCategories`, `tiers`, `tags`, `maxSize`                          |
| `allow`    | what the session may make, see below                                                                           |
| `look`     | `{ hour, weather }` held for everybody in the session                                                          |
| `mode`     | `'inspect'` opens the viewer instead. `openInspector` is the readable way to say it                            |
| `model`    | opens the viewer straight onto one prop                                                                        |

### Building Inside a Shell

```lua
exports.rm_mapeditor:openEditor(src, {
    shell = { model = 'shell_v_ret_ml_store', at = coords, heading = 90.0 },
    existing = savedFurniture,
}, function(result) end)
```

The boundary becomes the building's own box and everything comes back **in the building's frame**, so the same layout stands up in every copy of that shell, at whatever heading each one was spawned at.

A model and a place, never a handle or a network id: a shell is scenery, spawned on each client that needs to see it, so there is usually no network id naming it and the handle that exists belongs to a client. One already standing there is worked inside and left alone; otherwise one goes up for the session and comes down with it.

`margin` widens the box by that many metres at every face (0.5 by default), because a box measured to the millimetre refuses the chair somebody meant to push against the wall.

Standing the result back up is the mirror of it:

```lua
for _, row in ipairs(saved) do
    local rad = math.rad(shellHeading)
    local x = shellCoords.x + row.x * math.cos(rad) - row.y * math.sin(rad)
    local y = shellCoords.y + row.x * math.sin(rad) + row.y * math.cos(rad)
    local prop = CreateObjectNoOffset(joaat(row.model), x, y, shellCoords.z + row.z, false, false, false)
    SetEntityRotation(prop, row.rx, row.ry, row.rz + shellHeading, 2, true)
end
```

### What a Session May Make

Four things this editor does are not a prop standing in a map: a light, a hidden piece of map, a prop's collision switch, and the colour of the light inside a drawable. Each is a call somebody has to keep making, so a caller that stores rows and spawns props itself gets the props and whatever of these it makes the calls for.

So a session says what it offers:

```lua
allow = { runtime = true, lights = true, hide = false, collision = true, lightColor = true }
```

`runtime` is the switch over all four and each flag is under it. **Off by default for a shell session**, because that caller is exactly the one who will stand the layout up somewhere else. The standalone editor gets everything.

## Opening the Viewer

```lua
exports.rm_mapeditor:openInspector(source --[[number]], opts --[[table?]], cb --[[function?]])
```

The same session with nothing to place: the catalogue as a reference, and a click on the world to ask what something is. The callback is optional and is handed nothing, since a session that places nothing has no result, and it fires on close, so you can put your own UI back.

```lua
exports.rm_mapeditor:openInspector(src, { model = 'prop_bench_01a' })
exports.rm_mapeditor:openInspector(src, { tiers = { 'prop' } }, function() end)
```

| Field    | What                                                                                                                      |
| -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `model`  | opens straight onto one prop, by name or hash                                                                             |
| `tiers`  | what the picker browses. The viewer opens on all three, because a room's own surfaces are often the reason for opening it |
| `filter` | the editor's `filter`, the same fields                                                                                    |

## Asking About a Prop

```lua
local row = exports.rm_mapeditor:getPropDetails('prop_bench_01a')   -- name or hash
local name = exports.rm_mapeditor:getPropName(1234567890)           -- hash, signed or not
```

Both are synchronous, read the server's own files, and need no player and no session. Both answer `nil` for a model this catalogue does not carry, which is also how you ask whether it carries one.

`getPropDetails` answers for **every** row the pipeline measured, including the ones the picker does not offer:

|                               |                                                                                                                                                                                                                       |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| measured off the asset        | `dims`, `groundOffset`, `bbmin`, `footprint`, `triangles`, `shaders`, `hasCollision`, `collisionType`, `lights`, `lightTypes`, `emissive`, `alpha`, `decal`, `cloth`, `memoryBytes`, `lodDist`, `ytyp`, `dlc`, `path` |
| decided about it              | `category`, `label`, `tier`, `minBuild`, `offered`                                                                                                                                                                    |
| where the shipped map uses it | `usedWorld`, `usedInterior`, `usedAt`, `usedIn`                                                                                                                                                                       |

`offered` is not the same question as `tier`: a row can be tiered `prop` and still not be offered, because a measurement said it cannot be placed.

`getPropName` takes a hash in either spelling and also takes a name, which is the other use for it: somewhere to send a name of unknown case before comparing it to one of yours.

## Replacing the Commands

Any command can be `false` in `cfg.lua`, and these exports are how a menu, an item or a job script opens the same thing:

```lua
cfg.commands = { editor = false, inspect = false }
```

No permission is asked for on the way through. The command checks an ace because a player typed it; an export was called by a server script that had already decided, and this one opens the editor for the player it names.
