For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

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.

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:

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:

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

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

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:

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:

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

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.

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

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:

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.