Context
The sdk-commands preview server broadcasts file-change events over WebSocket using two protocols:
- Legacy JSON (
__LEGACY__updateScene): text frames "update" + {"type": "SCENE_UPDATE", "payload": {"sceneId", "sceneType"}}
- Protobuf
WsSceneMessage (decentraland/sdk/development/local_development.proto): binary frames with updateScene / updateModel variants
Godot only understands the legacy protocol: godot/src/logic/preview_websocket.gd parses each packet as UTF-8 text → JSON and matches "SCENE_UPDATE" only; binary protobuf frames fail the JSON parse and are silently dropped.
decentraland/js-sdk-toolchain#1502 initially removed the legacy broadcast (which silently broke hot-reload here) — it now keeps it, but only until Godot and Bevy migrate (decentraland/bevy-explorer#1020 is the matching issue).
Task
- Handle binary frames on the preview WebSocket: decode
WsSceneMessage (proto already available via @dcl/protocol; the Rust side could decode in lib/ where prost bindings live, or GDScript can receive it from a Rust helper).
- Map
updateScene → the existing scene_update signal (sceneId). Keep the JSON path as fallback for older CLIs.
- Optional follow-up: use the
updateModel variant (per-file hash/src/change-type) for model-level hot-swap instead of full scene reloads.
Context
The sdk-commands preview server broadcasts file-change events over WebSocket using two protocols:
__LEGACY__updateScene): text frames"update"+{"type": "SCENE_UPDATE", "payload": {"sceneId", "sceneType"}}WsSceneMessage(decentraland/sdk/development/local_development.proto): binary frames withupdateScene/updateModelvariantsGodot only understands the legacy protocol:
godot/src/logic/preview_websocket.gdparses each packet as UTF-8 text → JSON and matches"SCENE_UPDATE"only; binary protobuf frames fail the JSON parse and are silently dropped.decentraland/js-sdk-toolchain#1502 initially removed the legacy broadcast (which silently broke hot-reload here) — it now keeps it, but only until Godot and Bevy migrate (decentraland/bevy-explorer#1020 is the matching issue).
Task
WsSceneMessage(proto already available via @dcl/protocol; the Rust side could decode inlib/where prost bindings live, or GDScript can receive it from a Rust helper).updateScene→ the existingscene_updatesignal (sceneId). Keep the JSON path as fallback for older CLIs.updateModelvariant (per-file hash/src/change-type) for model-level hot-swap instead of full scene reloads.