# Engine iterations

Every Virtual Matter world runs on one engine iteration, such as iteration076. An
iteration is a release branch of the engine: within one iteration a world picks up
newer builds as they ship, and those keep the Lua API the same. Moving to a new
iteration can change the Lua API, the shaders and the network protocol, so a world
only moves when its maker, or the platform with notice, moves it.

## See which iteration a world runs

- The project page shows the editor's iteration next to Engine, and each play server's
  iteration on its own row. A warning appears when they differ, or when the running
  engine is still on an older build than the one the world is set to.
- `npx virtualmatter status` prints the same, and so does the `play_server_status`
  MCP tool.
- In Lua, `AE:GetVersion()` returns the running engine's version: 76.x is iteration076.
- The boot log names it on its first lines: `Version (Major.Minor.Revision.Build): 76.0...`
  and `Git branch: release/iteration076`.

## Move a world

1. On the project page, press Update next to Engine and pick the build. Leave "Also
   update base prefabs" on unless you changed the SDK's own scripts: it refreshes the
   stock SDK files to the new iteration and saves your files to GitHub first.
2. The editor restarts on the new iteration. Check `npx virtualmatter errors` and the
   boot log, and play it.
3. Publish (Update play servers, or `npx virtualmatter publish`). This moves the play
   servers to the editor's iteration too: until then they keep running the old one.

To try an iteration without risking the live world, remix the project (Remix on its
page), move the copy, and test there. The original and its play servers stay where they
are.

When the platform moves worlds to a new iteration, the maker is told before it happens:
on the project page, in `npx virtualmatter status`, and by email.

The desktop app plays worlds of its own iteration only. `npx virtualmatter open`
downloads the client that matches the world, and keeps one client per iteration.

## iteration076

Changes since iteration073 (iteration075 lived for a few days in between; the only API
difference from 075 is the sky). A world moving from 073 hits the first group straight
away, usually inside `pcall`, where the failure is silent.

Moved or now takes an Asset instead of a path:

- `VoxelData.receiveTransform` moved to `Object.receiveTransform` (on the object, not
  its voxel component). Writing an unknown field on an engine object throws.
- `Audio:PlaySound` and `Audio:PlaySoundRelative` take a sound Asset, not a path string.
- `Object:AddScript` takes a LuaFile Asset, not a file name.
- `Server:PreloadVDRsForPrefab` takes a prefab Asset, not a name.
- `UI:AddWindow` takes a name or a Lua Asset, not the old save flag.
- `VoxelEdit.imageColor` and `VoxelEdit.imageNormal` accept an Asset or AssetLink;
  `VoxelEdit:GetImageResource` is gone.

Removed:

- The `Sky` component and `Object:AddSkybox`. The sky is now set on the client:
  `Client:SetSky`, `Client:SetSkyLook`, `Client:SetSunDirection`, `Client:SetSkyEnabled`,
  `Client:ClearSky` and the matching getters.
- `Script.file`, `Object.voxelRenderer`, `Object.preserveOnLuaReset`.
- `Scene:CreateMaterial`, `Scene.voxelDataResourceTemplateSizeThreshold`.
- Init mode: `Server:EnterInitMode`, `Server:EnterLiveMode`, `Server:IsInitMode`,
  `Client:IsInitMode`, and `Client:ConnectToServer`.
- `Client.platform` and `Client.sysInfo`.
- `UI:SaveUI`, `UI.showUI`, `Widget.save`, `Window.noHide` and the Window asset list
  (`Window:AddAsset`, `Window:GetAsset`, `Window:GetAssets` and the rest).
- The `Mat3x4` type.
- The debug triggers `TriggerCrash`, `TriggerCriticalError`, `TriggerException`.

Changed behaviour:

- `Scene:CloneObject(obj, name, setSaveToFalse)`: the third argument used to be
  `keepPrefabLink`.
- `Server:SaveToPlayScene(enterSession)` takes an argument.
- `Scene:GetObjectByName`, `Scene:GetObjectById`, `Scene:GetActiveCamera` and
  `UI:CloneWidget` can return nil; `Scene:MoveObject` and its siblings return whether
  the move happened.
- Brush and voxel-edit callbacks receive more: `OnFinished` gets the result info,
  `VoxelEdit.onError` gets the reason and the op count, `VoxelEdit.onFinished` gets a status.
- `UI:LoadUI()` takes no path; `UI:AddWidget` lost its save argument.

New: shader errors (`Client:GetShaderErrors`, `Client:RequestReloadShaders`,
`Client:SetVPuzzleShaderDefines`), Lua GC mode (`AE:SetLuaGCMode`), video and vsync modes,
`Vox:flushEdits` and `Vox:pendingEdits`, `OpBase:Batch`, script metadata
(`AE:GetScriptMetadata`), `Client:IsInitialAssetSyncDone`, and the `util.whenAssetsReady`
and `util.whenAssetsSynced` helpers for assets a client is still downloading.

Shaders: a world's own copies under `Shaders/` override the engine's by asset id. At
boot the engine refreshes copies you never edited and keeps edited ones, logging one
line: `Montage shader overrides ... maker-edited kept`. An edited copy keeps working
only if it still matches the engine's inputs, so diff your edited shaders against the
new iteration's stock ones after a move.

Network: a 076 client speaks a newer scene and voxel stream protocol than 073, so a
desktop app of one iteration cannot join a world of the other.
