The live link
How Studio and a running game share camera, world, object, animation and UI screen data, and the command link.
The live link connects Studio to a running game through local shared memory. It has no network listener, starts no game thread and writes nothing into game memory. It adds no Activity Host inputs. Connect to a running game covers the steps.
How it attaches
The game side is off by default. core.studio_attach turns it on. See Settings, logs and in-game tools. Only a program in the same Windows session on the same machine can open the mappings.
Attach creates the camera and world mappings. Studio creates the others when it first needs them. The game only opens a mapping that already exists. The game’s existing camera callback publishes into them while Studio keeps a fresh heartbeat. The CUI mapping is the exception: a hook on the UI frame publishes it. See CUI. Detach releases them. The animation hook and the UI frame hook are installed whenever studio_attach is on. They do nothing until Studio opens their mapping.
mapping
carries
version
Local\SunriseStudio.Live.<pid>
the camera frame
1
Local\SunriseStudio.World.<pid>
world and object rows
4
Local\SunriseStudio.Pose.<pid>
animation
5
Local\SunriseStudio.Object.<pid>
the selected object
1
Local\SunriseStudio.Cui.<pid>
open CUI screens, one widget tree, one widget record
1
Local\SunriseStudio.Command.<pid>
commands
1
Studio reports a missing or mismatched bridge with an update and restart note and ignores its data.
What the game sends
surface
data
when
camera
position, forward and up, horizontal field of view, aspect
every camera callback
player
physics position and the controlled handle
every camera callback
world
loaded map root and definition, active scenario, activity package name
every 500 ms, or at once on entering or leaving the world
bubbles
resident and current slice identities
every 500 ms
object rows
identity, handle and generation, class, position, rotation, scale, raw flags, the placed-not-hidden bit
a scan at most every 50 ms
animation
world-space skinning palettes of the owners Studio asks for
at most every 50 ms, while on
selected object
parent, root, attached objects, drawn models, raw datum bytes
once per request
CUI screens
the open screens of both layers, in list order, and each layer’s top screen
at most every 100 ms, only when they change
CUI tree
the widgets of the screen Studio watches
at most every 100 ms, only when they change
CUI widget
one widget’s record
once per request
A placement scan yields after half a millisecond of each game frame. Each row carries its own read time. World changes invalidate unfinished scans and earlier placement data.
Placed and not hidden
The game side has one test, is_placed_and_not_hidden. Its result is a bit on each object row. Studio draws a full model only for rows with the bit set. Other rows are markers. The test reads the datum flags at +4 of the object and of every ancestor up to its root.
condition
datum flags
built
flags 1 and 2 of the object are clear
placed in the world
the root has 0x20: it is linked into spatial cells
not hidden
the object lacks 0x800, and no datum up the chain has 0x400, 0x80 or 4
Rows are filtered before the test.
case
effect
handle, generation or placement have changed
left out and counted as excluded
flag 4 (destroyed) on the object
left out and counted as excluded
the parent chain cannot be read
the bit is unknown; the row is treated as placed
flag 1 (not yet built)
the position is refused, so the marker has no position
The test says nothing about active or visible. No per-object active bit is known. Visibility is a property of each render object, not of the datum. A root with no spatial record never gets 0x20. Whether such an object is ever drawn is unverified.
Placements
A mission scene can hold the same placement once per state. Copies with the same list, entry and placement identity are one game object, and one live row moves all of them. A tuple that still has several candidates is ambiguous and does not move.
Placements hides authored placements the game has not spawned, but only from an exhaustive snapshot: complete, not cut off, and its rows plus its excluded rows equal the registry total. A busy or cut-off registry hides nothing. A placed row whose bit is clear hides its authored copy and draws as a marker.
Only objects more than a centimeter from their authored pose move. A moved static mesh draws with the diagnostic shader, because the game shader path cannot move it. Observed uniform scale replaces the authored scale. Live transforms never enter exports or project edits.
Spawned entities
A class prototype loads only for a spawned row whose bit is set. Other rows share one marker prototype and load nothing. Prototypes load once and share GPU resources. Classes, drawn models and the marker share a limit of 256 prototypes, and a scene shows at most 2048 pooled instances.
The selected object
Selecting a live object sends one request with its handle and generation. The game answers once, on its next camera callback, with one record. Nothing is pushed again. Refresh sends a new request.
field
source
identity, class, flags, placed-not-hidden bit
the object’s datum at answer time
position, rotation, scale
the object’s datum at answer time
parent handle
the object’s datum
root handle, root flags, chain flags
the parent chain at answer time
attached objects
rows of the last scan whose parent is this object, at most 64
drawn models
draws of this owner in the last animation capture, at most 32
raw datum
the 224 bytes of the datum layout the reader knows
Animation
Studio writes an owner filter into the pose control block: one bit per object slot, for the owners it draws a model for, the player and the selection. The game copies a completed skinning palette only for owners in that filter. It never calls the animation evaluator. The palette is already in world space and includes inverse bind transforms.
A part is posed only when its loaded model constants match the captured ones and a matching skinning shader exists. A draw that stops appearing expires after 250 ms. A capture expires after 500 ms. A draw holds at most 512 bones. One capture holds at most 1024 draws and 131,072 palette vectors. Draws match full handles and generations, so a reused slot never inherits an older pose.
CUI
The CUI link mirrors the game’s open UI screens and their widgets. It is read only. It has not run in a game yet.
field
value
mapping
Local\SunriseStudio.Cui.<pid>
magic
0x55435353, ASCII SSCU
version
1
size
460,736 bytes
created by
Studio, on first use
opened by
the game
Studio creates the mapping when the Screens tab, CUI screen sync or the CUI page’s Game state first needs it. It writes the version, size, its process id and the heartbeat, then the magic last. The game writes its own version when it connects, and its process id and a ready flag on every capture. From the mapping it reads only the header, the heartbeat and Studio’s requests.
Where the game reads
The game reads in a hook on its UI frame function. That function runs the UI update, then builds the UI draw list. The hook calls it first, then copies. The copy therefore runs on the thread that just updated the screens and widgets, after the update. The camera callback is not used for CUI. Which thread runs the frame function is unverified.
Every read is a guarded copy. A fault fails that read only. Walks are bounded: at most 32 screens, 8,192 widget rows, and 16,384 visited nodes. No screen or widget pointer is kept past one frame.
What Studio asks
request
target
answer
watch
hierarchy tag, ordinal
the widget tree of that screen, while the watch holds
widget
hierarchy tag, ordinal, node id
one record of that widget
The ordinal picks among open screens with the same hierarchy tag. 0 is the first. Studio writes the target, then a new non-zero request id. The game reads the id, the target, then the id again, and skips a torn read.
Capture and publish
The game captures at most once every 100 ms.
- It checks the header and the heartbeat. A heartbeat older than 3 seconds drops the link.
- It writes
checkedTime. - It walks the open screens. It rewrites the screen section only when its content changed.
- If Studio watches a screen, it walks that tree. It rewrites the tree section only when the rows, the status or the watch id changed.
- If Studio sent a new widget request id, it answers it once.
checkedTime moves on every capture, even when nothing else changes. Studio calls the mirror Stale when checkedTime is older than 2 seconds. Refresh in the inspector sends a new widget request id. Auto sends one 500 ms after each answer while the link is alive. Nothing is pushed again for an answered id.
The tree walks every CUI object under the screen. A row flag marks the objects that are widgets. Only a widget row carries the state word, slots and text hash. Studio never reads a row without the flag as hidden.
Each section is written between two increments of its own sequence number. Studio copies a section only when the number is even, new, and the same after the copy. It tries three times. It copies the tree header first, then only the rows it counts.
A request answers with one status.
status
meaning
complete
the rows or the record are valid
absent
no open screen has that tag and ordinal, or no widget has that node id
unavailable
the screen manager is not ready, or a read faulted
Diagnostics
Studio drops all CUI data while the game’s version differs or is missing.
condition
message
the game wrote another version
CUI bridge version differs. Update Sunrise and restart the game.
the game wrote no version after 5 seconds
CUI bridge unavailable. Update Sunrise and restart the game.
the game’s ready flag is clear
The game has not built its screen list yet.
a fast re-attach still holds the old mapping
CUI link busy; retrying
The last two clear by themselves, so the CUI page shows them as Not ready, not as No link. A bad widget record marks only that record unavailable. It does not change the link status.
Detach sets the heartbeat to 0 and releases the mapping. A minimized Studio stops the heartbeat too. The game drops the link after 3 seconds and connects again within 1 second of the next heartbeat. It then republishes the screens, the watched tree and the last widget answer without a new request.
Command link
Update running game uses the command mapping. It does not need Attach, and it is the one link that changes game state. Studio creates the mapping for one request and releases it after the reply.
It sends one command, reload_mod. The game prepares replacements for the started, bound mission programs owned by that mod or by mods that depend on it. The game answers once, after the mission reaches a safe point. Studio waits up to 30 seconds.
- New source, loaded modules and
on_loadeffects stay private until the whole batch commits. - A preparation or commit failure returns an error and keeps the old programs running.
- An unbound or not yet started mission needs an activity restart.
- A disconnect or timeout cancels a pending request. A publication that has started cannot be undone.
The mapping is 320 bytes, magic 0x4D435353, ASCII SSCM. Studio creates it as new, so a second editor cannot replace a running request. If the game still holds the last mapping, Studio retries for 3 seconds. The game answers with one status.
status
Studio shows
ok
how many running missions reloaded
invalid
the game refused the request
disabled
mission scripting is off in the game
not loaded
the mod did not load in this game session
compile error
a script did not compile; the old program keeps running
failed
the game could not reload the mod
Only scripts reload. The game side may not work with Studio.
Performance
A new placement snapshot copies only its header and the rows it counts. A snapshot refreshes only objects whose pose changed. The game reads object memory in place under a fault guard. The CUI link writes the cost of its last capture to captureMicros. Viewport performance has the Studio frame cap.
