Skip to main content
Declared with capabilities.transform = true. One function, and no ctx argument.

The contract

string
Your own localId, not the namespaced id.
table
{ pos = {x,y,z}, ang = {p,y,r} }, plain finite numbers.

Position and orientation only

Deliberately not update. An adapter that can move a turret must not thereby be believed able to rewrite a job definition. Changing an object’s domain properties is properties, and it is bounded differently.

An unknown id must be refused, loudly

Return false plus a non-empty reason. Returning nil, or true, is a contract failure.
This is the check a first adapter most often gets wrong. Blueprints will ask about ids that cannot exist, and an adapter that shrugs makes a group move report success while moving nothing.

Returning true and moving nothing

Also a contract failure, and it is checked by reading the position back, not by trusting your return value. If a write cannot land, say so:

You may adjust the placement

Blueprints’ own NPC adapter drops an NPC to the floor after a move, so a relocated NPC settles deterministically instead of falling. A zone adapter might snap to a grid. That is allowed, and it is why the contract asserts the horizontal position exactly and treats a vertical adjustment as a note rather than a failure. Encoding “unless you ground your objects” into the SDK would put one engine’s placement convention into everybody’s contract.

Declaring how much orientation you honour

ApplyTransform itself takes no declaration. Orientation is declared from PrepareMaterialize, and from PrepareProperties if you declare properties:
If your domain honours less than a full orientation, say so there. Blueprints then clamps the same way when it plans, previews and verifies, instead of reporting a perfectly placed object as mis-rotated on axes nothing ever wrote.
An NPC-like adapter that writes yaw only but declares "full" will have every object reported as mis-rotated on two axes after a restore, and the operator has no way to tell whether the tool or the server is broken.
See Capabilities.

Entity-backed domains

If your objects are entities, most of the hard parts here are already solved. Blueprints’ own adapters move an entity and its physics object together (setting only the entity leaves collision at the old position), preserve the frozen state across the move so a group move never unfreezes somebody’s build, clear momentum so a moved prop does not carry old velocity, and refuse a destination outside the world. If you are writing an entity-backed adapter, do all of that. Getting any one of them wrong looks like a Blueprints bug from the outside.