@fps-games/editor 0.1.5-beta.5 → 0.1.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-bridge/capabilities/assets.d.ts +8 -0
- package/dist/agent-bridge/capabilities/assets.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/assets.js +226 -0
- package/dist/agent-bridge/capabilities/assets.js.map +1 -0
- package/dist/agent-bridge/capabilities/editor-state.d.ts +5 -0
- package/dist/agent-bridge/capabilities/editor-state.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/editor-state.js +72 -0
- package/dist/agent-bridge/capabilities/editor-state.js.map +1 -0
- package/dist/agent-bridge/capabilities/host-lifecycle.d.ts +4 -0
- package/dist/agent-bridge/capabilities/host-lifecycle.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/host-lifecycle.js +87 -0
- package/dist/agent-bridge/capabilities/host-lifecycle.js.map +1 -0
- package/dist/agent-bridge/capabilities/prefabs.d.ts +5 -0
- package/dist/agent-bridge/capabilities/prefabs.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/prefabs.js +735 -0
- package/dist/agent-bridge/capabilities/prefabs.js.map +1 -0
- package/dist/agent-bridge/capabilities/scene-objects.d.ts +9 -0
- package/dist/agent-bridge/capabilities/scene-objects.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/scene-objects.js +394 -0
- package/dist/agent-bridge/capabilities/scene-objects.js.map +1 -0
- package/dist/agent-bridge/capabilities/selection.d.ts +5 -0
- package/dist/agent-bridge/capabilities/selection.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/selection.js +57 -0
- package/dist/agent-bridge/capabilities/selection.js.map +1 -0
- package/dist/agent-bridge/capabilities/shadows.d.ts +5 -0
- package/dist/agent-bridge/capabilities/shadows.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/shadows.js +1876 -0
- package/dist/agent-bridge/capabilities/shadows.js.map +1 -0
- package/dist/agent-bridge/capabilities/transform.d.ts +5 -0
- package/dist/agent-bridge/capabilities/transform.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/transform.js +162 -0
- package/dist/agent-bridge/capabilities/transform.js.map +1 -0
- package/dist/agent-bridge/capabilities/ui-regions.d.ts +4 -0
- package/dist/agent-bridge/capabilities/ui-regions.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/ui-regions.js +168 -0
- package/dist/agent-bridge/capabilities/ui-regions.js.map +1 -0
- package/dist/agent-bridge/capabilities/viewport.d.ts +5 -0
- package/dist/agent-bridge/capabilities/viewport.d.ts.map +1 -0
- package/dist/agent-bridge/capabilities/viewport.js +407 -0
- package/dist/agent-bridge/capabilities/viewport.js.map +1 -0
- package/dist/agent-bridge/capability-sources.d.ts +6 -0
- package/dist/agent-bridge/capability-sources.d.ts.map +1 -0
- package/dist/agent-bridge/capability-sources.js +26 -0
- package/dist/agent-bridge/capability-sources.js.map +1 -0
- package/dist/agent-bridge/diagnostics.d.ts +12 -0
- package/dist/agent-bridge/diagnostics.d.ts.map +1 -0
- package/dist/agent-bridge/diagnostics.js +45 -0
- package/dist/agent-bridge/diagnostics.js.map +1 -0
- package/dist/agent-bridge/index.d.ts +5 -0
- package/dist/agent-bridge/index.d.ts.map +1 -0
- package/dist/agent-bridge/index.js +5 -0
- package/dist/agent-bridge/index.js.map +1 -0
- package/dist/agent-bridge/register.d.ts +4 -0
- package/dist/agent-bridge/register.d.ts.map +1 -0
- package/dist/agent-bridge/register.js +908 -0
- package/dist/agent-bridge/register.js.map +1 -0
- package/dist/agent-bridge/shared.d.ts +189 -0
- package/dist/agent-bridge/shared.d.ts.map +1 -0
- package/dist/agent-bridge/shared.js +39 -0
- package/dist/agent-bridge/shared.js.map +1 -0
- package/dist/agent-bridge/source-types.d.ts +90 -0
- package/dist/agent-bridge/source-types.d.ts.map +1 -0
- package/dist/agent-bridge/source-types.js +2 -0
- package/dist/agent-bridge/source-types.js.map +1 -0
- package/dist/build-info.json +17 -17
- package/dist/local-editor-agent-actions.d.ts +8 -1
- package/dist/local-editor-agent-actions.d.ts.map +1 -1
- package/dist/local-editor-agent-actions.js +171 -12
- package/dist/local-editor-agent-actions.js.map +1 -1
- package/dist/local-editor-agent-bridge-transport.d.ts +95 -0
- package/dist/local-editor-agent-bridge-transport.d.ts.map +1 -0
- package/dist/local-editor-agent-bridge-transport.js +340 -0
- package/dist/local-editor-agent-bridge-transport.js.map +1 -0
- package/dist/local-editor-agent-bridge.d.ts +2 -0
- package/dist/local-editor-agent-bridge.d.ts.map +1 -0
- package/dist/local-editor-agent-bridge.js +2 -0
- package/dist/local-editor-agent-bridge.js.map +1 -0
- package/dist/local-editor-agent-context.d.ts +29 -1
- package/dist/local-editor-agent-context.d.ts.map +1 -1
- package/dist/local-editor-agent-context.js +403 -0
- package/dist/local-editor-agent-context.js.map +1 -1
- package/dist/local-editor-harness.d.ts +128 -6
- package/dist/local-editor-harness.d.ts.map +1 -1
- package/dist/local-editor-harness.js +2730 -151
- package/dist/local-editor-harness.js.map +1 -1
- package/dist/local-editor-marker-graph.d.ts +92 -0
- package/dist/local-editor-marker-graph.d.ts.map +1 -0
- package/dist/local-editor-marker-graph.js +1432 -0
- package/dist/local-editor-marker-graph.js.map +1 -0
- package/dist/local-editor-performance-stats.js +1 -1
- package/dist/local-editor-performance-stats.js.map +1 -1
- package/dist/playable-babylon-facade.d.ts +2 -2
- package/dist/playable-babylon-facade.d.ts.map +1 -1
- package/dist/playable-babylon-facade.js +1 -1
- package/dist/playable-babylon-facade.js.map +1 -1
- package/dist/playable-babylon-rendering.js +20 -0
- package/dist/playable-babylon-rendering.js.map +1 -1
- package/dist/playable-local-editor-host.d.ts +57 -7
- package/dist/playable-local-editor-host.d.ts.map +1 -1
- package/dist/playable-local-editor-host.js +25 -1
- package/dist/playable-local-editor-host.js.map +1 -1
- package/dist/playable-sdk.d.ts +4 -2
- package/dist/playable-sdk.d.ts.map +1 -1
- package/dist/playable-sdk.js +2 -1
- package/dist/playable-sdk.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.d.ts.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.js +6 -4
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.d.ts.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.js +103 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.d.ts.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.js +330 -27
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.d.ts.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js +159 -0
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js +8 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts +53 -2
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js +1 -0
- package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js.map +1 -1
- package/node_modules/@fps-games/babylon-renderer/package.json +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/camera-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js +11 -0
- package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts +3 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js +114 -18
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +3 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +3 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.js +3 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts +52 -0
- package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js +1395 -0
- package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js +4 -65
- package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts +28 -0
- package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js +235 -0
- package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts +37 -0
- package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js +451 -0
- package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js +14 -3
- package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js +20 -4
- package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts +3 -6
- package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js +4 -37
- package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +74 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.js +641 -52
- package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts +11 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js +113 -29
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts +13 -1
- package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js +543 -3
- package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/package.json +5 -5
- package/node_modules/@fps-games/editor-browser/dist/index.d.ts +8 -2
- package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/index.js +4 -0
- package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts +5 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js +23 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js +76 -9
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js +3 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.d.ts +21 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.js +75 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +2 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +326 -72
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.d.ts +5 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.js +92 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts +4 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js +22 -7
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts +4 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +24 -11
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js +7 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +4 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +1471 -29
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts +70 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js +171 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js +2 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +9 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +301 -3
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +12 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +13 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +6 -4
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +1501 -122
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/package.json +3 -3
- package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts +18 -0
- package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/agent-bridge.js +102 -0
- package/node_modules/@fps-games/editor-core/dist/agent-bridge.js.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/index.d.ts +1 -0
- package/node_modules/@fps-games/editor-core/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/index.js +1 -0
- package/node_modules/@fps-games/editor-core/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts +3 -1
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js +1 -0
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js.map +1 -1
- package/node_modules/@fps-games/editor-core/package.json +2 -2
- package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.js +9 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.d.ts +6 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js +89 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.d.ts +18 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.js +121 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts +4 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.d.ts +27 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.js +782 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.d.ts +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.js +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.d.ts +80 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.js +600 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.d.ts +51 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.js +2 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js +17 -3
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js +2 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts +3 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js +48 -20
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js +2 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/types.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts +97 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js +1143 -8
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts +145 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js +24 -9
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts +6 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js +31 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/index.js +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts +82 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js +396 -22
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.js +0 -3
- package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.d.ts +29 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.js +143 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js +3 -7
- package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js +6 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts +2 -10
- package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js +107 -11
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js +4 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.js +19 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js +19 -3
- package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.d.ts +1 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js +0 -14
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.d.ts +1 -7
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.js +3 -32
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js +82 -63
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts +7 -23
- package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.d.ts +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.js +996 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.js +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.d.ts +152 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.js +2 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js +44 -2
- package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js +244 -12
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js +216 -67
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js +7 -4
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.js +45 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js +2 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.d.ts +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.js +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.d.ts +21 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.js +158 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.d.ts +5 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.js +83 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.d.ts +35 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.js +363 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.d.ts +105 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.js +6 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js +44 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.d.ts +26 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.js +105 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.js.map +1 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js +3 -0
- package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js.map +1 -1
- package/node_modules/@fps-games/editor-playable-sdk/package.json +3 -3
- package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts +1127 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.js +2180 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.js.map +1 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts +68 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js +23 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js.map +1 -0
- package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts +57 -3
- package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-protocol/dist/agent.js.map +1 -1
- package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +21 -0
- package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-protocol/dist/index.js +3 -0
- package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts +128 -0
- package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js +2 -0
- package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js.map +1 -0
- package/node_modules/@fps-games/editor-protocol/package.json +1 -1
- package/package.json +8 -8
|
@@ -1,18 +1,65 @@
|
|
|
1
|
-
import { createEditorSession, createInspectorRegistry, DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_VIEWPORT_TOOL_STATE, createEmptyEditorViewportSpatialOverlayState, cloneEditorTransformSnapshot as cloneCoreEditorTransformSnapshot, composeEditorTransformMatrix, editorTransformMatricesAlmostEqual, cloneEditorViewportToolState, cloneEditorViewportSpatialOverlayState, aggregateInspectorObjectsToMultiObject, createInspectorEditPayload, compareInspectorSections, computeEditorTransformActionTargets, mergeInspectorSections, isEditorTransformTrsSnapshot, normalizeEditorTransformConstraint, readEditorTransformPosition, resolveEditorSelectionCommand, serializedMultiObjectToInspectorObject, serializedObjectToInspectorObject, validateSceneGraphDelete, validateSceneGraphDrop, validateSceneGraphGroupSelection, validateSceneGraphMove, validateSceneGraphRename, } from '@fps-games/editor-core';
|
|
1
|
+
import { createEditorSession, createEditorAgentBridge, createInspectorRegistry, DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_VIEWPORT_TOOL_STATE, createEmptyEditorViewportSpatialOverlayState, cloneEditorTransformSnapshot as cloneCoreEditorTransformSnapshot, composeEditorTransformMatrix, editorTransformMatricesAlmostEqual, cloneEditorViewportToolState, cloneEditorViewportSpatialOverlayState, aggregateInspectorObjectsToMultiObject, createInspectorEditPayload, compareInspectorSections, computeEditorTransformActionTargets, mergeInspectorSections, isEditorTransformTrsSnapshot, normalizeEditorTransformConstraint, readEditorTransformPosition, resolveEditorSelectionCommand, serializedMultiObjectToInspectorObject, serializedObjectToInspectorObject, validateSceneGraphDelete, validateSceneGraphDrop, validateSceneGraphGroupSelection, validateSceneGraphMove, validateSceneGraphRename, } from '@fps-games/editor-core';
|
|
2
|
+
import {} from '@fps-games/editor-protocol';
|
|
2
3
|
import { createLocalEditorBrowserUi, toTransformOperationPolicyStatusLabel, } from '@fps-games/editor-browser';
|
|
3
4
|
import { createBabylonEnvironmentTextureController, createBabylonDefaultPostProcessPipelineController, } from '@fps-games/babylon-renderer';
|
|
4
|
-
import { createBabylonEditorProjection, createBabylonEditorWorld, createBabylonProjectionSelectionController, createBabylonSceneCameraPreviewController, createBabylonSceneViewCameraController, createBabylonSceneViewInputController, createBabylonSceneViewMeasurementController, createBabylonSceneViewSpatialOverlayController, createBabylonEditorShadowPreviewController, createBabylonTransformGizmoController, createBabylonEditorPerformanceMonitor, focusEditorViewportSelection, } from '@fps-games/editor-babylon';
|
|
5
|
+
import { createBabylonEditorProjection, createBabylonEditorMarkerOverlayController, createBabylonMarkerOverlayProjectionAdapter, createBabylonEditorWorld, createBabylonPrefabComparisonPreviewController, createBabylonProjectionSelectionController, createBabylonSceneCameraPreviewController, createBabylonSceneViewCameraController, createBabylonSceneViewInputController, createBabylonSceneViewMeasurementController, createBabylonSceneViewSpatialOverlayController, createBabylonEditorShadowPreviewController, createBabylonTransformGizmoController, createBabylonEditorPerformanceMonitor, focusEditorViewportSelection, } from '@fps-games/editor-babylon';
|
|
5
6
|
import { createLocalEditorSceneRenderScheduler, } from './local-editor-scene-render-scheduler.js';
|
|
6
7
|
import { createPlayableBabylonOutlineInspectorSection, createPlayableBabylonOutlineInspectorSeedPatchValue, isPlayableBabylonOutlineInspectorPatchPath, } from './playable-babylon-outline-inspector.js';
|
|
7
8
|
import { createLocalEditorViewportRenderCoordinator, } from './local-editor-viewport-render-coordinator.js';
|
|
8
9
|
import { createLocalEditorSceneViewInteractionRuntime, } from './local-editor-scene-view-interaction-runtime.js';
|
|
9
10
|
import { cloneLocalEditorPerformanceStats, countLocalEditorAuthoredObjects, createLocalEditorPerformanceStats, LOCAL_EDITOR_PERFORMANCE_MONITOR_REASON, } from './local-editor-performance-stats.js';
|
|
11
|
+
import { registerLocalEditorAgentBridgeCapabilities } from './local-editor-agent-bridge.js';
|
|
12
|
+
import { createLocalEditorAgentBridgeCapabilitySources, } from './agent-bridge/capability-sources.js';
|
|
13
|
+
import { createDisabledLocalEditorAgentBridgeTransportStatus, createLocalEditorAgentBridgeWebSocketTransportFromQuery, } from './local-editor-agent-bridge-transport.js';
|
|
14
|
+
import { createMarkerGraphHierarchyItems, createMarkerGraphInspectorObject, createMarkerGraphRootInspectorObject, createMarkerPanelState, createMarkerRelationCommand, createMarkerRelationCreateManyCommand, createMarkerRelationDeleteConnectedCommand, createMarkerRelationReverseCommand, createMarkerGraphPatchFromInspectorEdit, findSpatialMarkerById, getSpatialMarkerDirectRelations, isMarkerGraphHierarchyId, isMarkerGraphHierarchyRootRowId, isSpatialMarkerBackedByHierarchyRow, isSpatialMarkerHierarchyVisible, readMarkerGraphHierarchyMarkerIdForGraph, readSpatialMarkerIdFromHierarchySelection, } from './local-editor-marker-graph.js';
|
|
10
15
|
const BATCH_EDIT_REQUIRES_MULTI_PATCH_REASON = 'Batch edit requires multi-property patch support.';
|
|
11
16
|
const LARGE_SELECTION_THRESHOLD = 200;
|
|
12
17
|
const LARGE_SHADOW_MODE_BATCH_THRESHOLD = 200;
|
|
13
18
|
const EDITOR_PROJECTION_IDLE_BEFORE_RUN_GAME_TIMEOUT_MS = 1500;
|
|
14
19
|
const EDITOR_WORLD_DISPOSE_BOUNDARY_DELAY_MS = 500;
|
|
15
20
|
const RENDERING_ACTION_PROGRESS_MIN_VISIBLE_MS = 1000;
|
|
21
|
+
const EMPTY_EDITOR_SELECTION = { selectedIds: [], activeId: null };
|
|
22
|
+
const MARKER_RELATION_HIGHLIGHT_RENDER_REASON = 'marker-relation-highlight';
|
|
23
|
+
const PREFAB_STAGE_STUDIO_WORLD_APPEARANCE = {
|
|
24
|
+
sky: {
|
|
25
|
+
preset: 'atmospheric',
|
|
26
|
+
topColor: { r: 0.68, g: 0.82, b: 0.9 },
|
|
27
|
+
horizonColor: { r: 0.98, g: 0.98, b: 0.93 },
|
|
28
|
+
bottomColor: { r: 0.44, g: 0.54, b: 0.53 },
|
|
29
|
+
cloudColor: { r: 1, g: 0.97, b: 0.86 },
|
|
30
|
+
cloudStrength: 0.1,
|
|
31
|
+
sunColor: { r: 1, g: 0.93, b: 0.72 },
|
|
32
|
+
sunDirection: { x: -0.24, y: 0.28, z: -0.93 },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
const PREFAB_STAGE_STUDIO_ENVIRONMENT = {
|
|
36
|
+
textureUrl: 'https://assets.babylonjs.com/environments/studio.env',
|
|
37
|
+
intensity: 1,
|
|
38
|
+
rotationY: 0,
|
|
39
|
+
};
|
|
40
|
+
const PREFAB_STAGE_COMPARISON_PREVIEW_DEFINITIONS = [{
|
|
41
|
+
id: 'mesh-clone',
|
|
42
|
+
label: 'Mesh Clone',
|
|
43
|
+
mode: 'meshClone',
|
|
44
|
+
nodeIdSuffix: 'compare-clone',
|
|
45
|
+
}, {
|
|
46
|
+
id: 'instanced-mesh',
|
|
47
|
+
label: 'InstanceMesh',
|
|
48
|
+
mode: 'instancedMesh',
|
|
49
|
+
nodeIdSuffix: 'compare-instance',
|
|
50
|
+
}];
|
|
51
|
+
function createDefaultMarkerGraphVisibilityState() {
|
|
52
|
+
return {
|
|
53
|
+
rootVisible: true,
|
|
54
|
+
hiddenMarkerIds: new Set(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function createEmptyMarkerCreateReservations() {
|
|
58
|
+
return {
|
|
59
|
+
ids: new Set(),
|
|
60
|
+
labels: new Set(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
16
63
|
export function createLocalEditorHarness(options) {
|
|
17
64
|
const root = options.root ?? document.body;
|
|
18
65
|
const state = {
|
|
@@ -31,6 +78,16 @@ export function createLocalEditorHarness(options) {
|
|
|
31
78
|
grid: null,
|
|
32
79
|
gridVisible: true,
|
|
33
80
|
projection: null,
|
|
81
|
+
previewVisibility: {
|
|
82
|
+
overrides: {},
|
|
83
|
+
isolatedObjectIds: [],
|
|
84
|
+
},
|
|
85
|
+
markerOverlay: null,
|
|
86
|
+
markerGraphVisibility: createDefaultMarkerGraphVisibilityState(),
|
|
87
|
+
activeMarkerRelationId: null,
|
|
88
|
+
markerRelationPick: null,
|
|
89
|
+
markerRelationHighlightContinuous: false,
|
|
90
|
+
markerCreateReservations: createEmptyMarkerCreateReservations(),
|
|
34
91
|
shadowPreview: null,
|
|
35
92
|
environmentTexture: null,
|
|
36
93
|
postProcess: null,
|
|
@@ -45,6 +102,7 @@ export function createLocalEditorHarness(options) {
|
|
|
45
102
|
sceneViewMeasurement: null,
|
|
46
103
|
sceneViewSpatialOverlay: null,
|
|
47
104
|
selectionController: null,
|
|
105
|
+
prefabComparisonPreview: null,
|
|
48
106
|
sceneRenderScheduler: null,
|
|
49
107
|
viewportRenderCoordinator: null,
|
|
50
108
|
sceneFrameStats: null,
|
|
@@ -62,6 +120,7 @@ export function createLocalEditorHarness(options) {
|
|
|
62
120
|
viewportTools: cloneEditorViewportToolState(DEFAULT_EDITOR_VIEWPORT_TOOL_STATE),
|
|
63
121
|
viewportMeasurement: createEmptyViewportMeasurement(),
|
|
64
122
|
viewportSpatialOverlay: createEmptyEditorViewportSpatialOverlayState(),
|
|
123
|
+
prefabStage: null,
|
|
65
124
|
duplicateDrag: null,
|
|
66
125
|
activeTransformPreview: null,
|
|
67
126
|
armedPlacement: null,
|
|
@@ -72,6 +131,10 @@ export function createLocalEditorHarness(options) {
|
|
|
72
131
|
statusDetails: '',
|
|
73
132
|
renderingAction: null,
|
|
74
133
|
summary: '',
|
|
134
|
+
agentBridge: createEditorAgentBridge(),
|
|
135
|
+
unregisterAgentBridgeCapabilities: null,
|
|
136
|
+
agentBridgeTransport: null,
|
|
137
|
+
agentBridgeStatus: createDisabledLocalEditorAgentBridgeTransportStatus(),
|
|
75
138
|
};
|
|
76
139
|
let harness;
|
|
77
140
|
const ui = createLocalEditorBrowserUi({
|
|
@@ -116,6 +179,14 @@ export function createLocalEditorHarness(options) {
|
|
|
116
179
|
if (handleBrowserAssetAction(state, options, input))
|
|
117
180
|
harness.render();
|
|
118
181
|
},
|
|
182
|
+
onExitPrefabStage: () => {
|
|
183
|
+
if (exitPrefabStage(state, options))
|
|
184
|
+
harness.render();
|
|
185
|
+
},
|
|
186
|
+
onSelectPrefabStageItem: (itemId) => {
|
|
187
|
+
if (selectPrefabStageItemWithPreviewSync(state, options, itemId))
|
|
188
|
+
harness.render();
|
|
189
|
+
},
|
|
119
190
|
onSelectHierarchyItem: (input) => {
|
|
120
191
|
selectItem(state, options, input, harness.render);
|
|
121
192
|
},
|
|
@@ -123,6 +194,14 @@ export function createLocalEditorHarness(options) {
|
|
|
123
194
|
if (patchHierarchyItemEnabled(state, options, input))
|
|
124
195
|
harness.render();
|
|
125
196
|
},
|
|
197
|
+
onMarkerTypeAction: (input) => {
|
|
198
|
+
if (patchMarkerTypeCatalog(state, options, input))
|
|
199
|
+
harness.render();
|
|
200
|
+
},
|
|
201
|
+
onMarkerRelationAction: (input) => {
|
|
202
|
+
if (patchMarkerRelation(state, options, input))
|
|
203
|
+
harness.render();
|
|
204
|
+
},
|
|
126
205
|
onSelectionCommand: (command) => {
|
|
127
206
|
dispatchSelectionCommand(state, options, command, harness.render);
|
|
128
207
|
},
|
|
@@ -140,6 +219,12 @@ export function createLocalEditorHarness(options) {
|
|
|
140
219
|
harness.render();
|
|
141
220
|
}
|
|
142
221
|
: undefined,
|
|
222
|
+
onSceneGraphCreateMarker: options.documentAdapter.createMarkerGraphPatch
|
|
223
|
+
? (intent) => {
|
|
224
|
+
if (createSceneGraphMarker(state, options, intent))
|
|
225
|
+
harness.render();
|
|
226
|
+
}
|
|
227
|
+
: undefined,
|
|
143
228
|
onSceneGraphDelete: (intent) => {
|
|
144
229
|
if (deleteSceneGraphNodes(state, options, intent))
|
|
145
230
|
harness.render();
|
|
@@ -181,6 +266,10 @@ export function createLocalEditorHarness(options) {
|
|
|
181
266
|
if (patched || state.status !== previousStatus)
|
|
182
267
|
harness.render();
|
|
183
268
|
},
|
|
269
|
+
onInspectorAction: (input) => {
|
|
270
|
+
if (handleInspectorAction(state, options, input))
|
|
271
|
+
harness.render();
|
|
272
|
+
},
|
|
184
273
|
onRenderingPropertyChange: options.documentAdapter.onRenderingPropertyChange
|
|
185
274
|
? (input) => {
|
|
186
275
|
void applyRenderingPropertyChange(state, options, input)
|
|
@@ -201,7 +290,7 @@ export function createLocalEditorHarness(options) {
|
|
|
201
290
|
}
|
|
202
291
|
: undefined,
|
|
203
292
|
onTransformToolChange: (tool) => {
|
|
204
|
-
commitEditorStateChange(state, harness.render, 'transform-tool-change', () => {
|
|
293
|
+
commitEditorStateChange(state, options, harness.render, 'transform-tool-change', () => {
|
|
205
294
|
state.transformTool = tool;
|
|
206
295
|
state.transformConstraint = normalizeTransformConstraint(tool, state.transformConstraint);
|
|
207
296
|
}, {
|
|
@@ -209,21 +298,21 @@ export function createLocalEditorHarness(options) {
|
|
|
209
298
|
});
|
|
210
299
|
},
|
|
211
300
|
onTransformSpaceChange: (space) => {
|
|
212
|
-
commitEditorStateChange(state, harness.render, 'transform-space-change', () => {
|
|
301
|
+
commitEditorStateChange(state, options, harness.render, 'transform-space-change', () => {
|
|
213
302
|
state.transformSpace = space;
|
|
214
303
|
}, {
|
|
215
304
|
syncTransformArtifacts: true,
|
|
216
305
|
});
|
|
217
306
|
},
|
|
218
307
|
onTransformConstraintChange: (constraint) => {
|
|
219
|
-
commitEditorStateChange(state, harness.render, 'transform-constraint-change', () => {
|
|
308
|
+
commitEditorStateChange(state, options, harness.render, 'transform-constraint-change', () => {
|
|
220
309
|
state.transformConstraint = normalizeTransformConstraint(state.transformTool, constraint);
|
|
221
310
|
}, {
|
|
222
311
|
syncTransformArtifacts: true,
|
|
223
312
|
});
|
|
224
313
|
},
|
|
225
314
|
onTransformSnapEnabledChange: (enabled) => {
|
|
226
|
-
commitEditorStateChange(state, harness.render, 'transform-operation-settings-change', () => {
|
|
315
|
+
commitEditorStateChange(state, options, harness.render, 'transform-operation-settings-change', () => {
|
|
227
316
|
state.transformOperationSettings = updateTransformOperationSettings(state.transformOperationSettings, {
|
|
228
317
|
snap: {
|
|
229
318
|
...state.transformOperationSettings.snap,
|
|
@@ -239,7 +328,7 @@ export function createLocalEditorHarness(options) {
|
|
|
239
328
|
const value = normalizePositiveStep(input.value);
|
|
240
329
|
if (value == null)
|
|
241
330
|
return;
|
|
242
|
-
commitEditorStateChange(state, harness.render, 'transform-operation-settings-change', () => {
|
|
331
|
+
commitEditorStateChange(state, options, harness.render, 'transform-operation-settings-change', () => {
|
|
243
332
|
const snap = { ...state.transformOperationSettings.snap };
|
|
244
333
|
if (input.kind === 'move')
|
|
245
334
|
snap.moveStep = value;
|
|
@@ -254,7 +343,7 @@ export function createLocalEditorHarness(options) {
|
|
|
254
343
|
});
|
|
255
344
|
},
|
|
256
345
|
onPlacementModeChange: (mode) => {
|
|
257
|
-
commitEditorStateChange(state, harness.render, 'placement-mode-change', () => {
|
|
346
|
+
commitEditorStateChange(state, options, harness.render, 'placement-mode-change', () => {
|
|
258
347
|
state.transformOperationSettings = updateTransformOperationSettings(state.transformOperationSettings, {
|
|
259
348
|
placementMode: normalizePlacementMode(mode),
|
|
260
349
|
});
|
|
@@ -270,7 +359,7 @@ export function createLocalEditorHarness(options) {
|
|
|
270
359
|
harness.render();
|
|
271
360
|
},
|
|
272
361
|
onViewportViewPresetChange: (preset) => {
|
|
273
|
-
if (setViewportViewPreset(state, preset))
|
|
362
|
+
if (setViewportViewPreset(state, options, preset))
|
|
274
363
|
harness.render();
|
|
275
364
|
},
|
|
276
365
|
onViewportProjectionModeChange: (mode) => {
|
|
@@ -281,6 +370,10 @@ export function createLocalEditorHarness(options) {
|
|
|
281
370
|
if (setViewportOverlaySettings(state, settings))
|
|
282
371
|
harness.render();
|
|
283
372
|
},
|
|
373
|
+
onMarkerViewportVisibilityChange: (visible) => {
|
|
374
|
+
if (setMarkerViewportVisibility(state, options, visible))
|
|
375
|
+
harness.render();
|
|
376
|
+
},
|
|
284
377
|
onViewportUtilityToolChange: (tool) => {
|
|
285
378
|
if (setViewportUtilityTool(state, tool))
|
|
286
379
|
harness.render();
|
|
@@ -301,8 +394,20 @@ export function createLocalEditorHarness(options) {
|
|
|
301
394
|
setLocalEditorPerformanceMonitorOpen(state, open);
|
|
302
395
|
updateLocalEditorPerformanceStats(state, stats => ui.updatePerformanceStats?.(stats));
|
|
303
396
|
},
|
|
397
|
+
...{
|
|
398
|
+
onPrefabComparisonPreviewLayoutChange: () => {
|
|
399
|
+
harness.render();
|
|
400
|
+
},
|
|
401
|
+
onPrefabComparisonPreviewInteraction: (input) => {
|
|
402
|
+
if (!state.prefabStage)
|
|
403
|
+
return;
|
|
404
|
+
if (state.prefabComparisonPreview?.adjustView(input)) {
|
|
405
|
+
requestEditorSceneFrame(state, 'prefab-comparison-preview-interaction');
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
},
|
|
304
409
|
onFocusSelection: () => {
|
|
305
|
-
if (focusSelectedProjection(state))
|
|
410
|
+
if (focusSelectedProjection(state, options))
|
|
306
411
|
harness.render();
|
|
307
412
|
},
|
|
308
413
|
onCancelEditorIntent: () => {
|
|
@@ -333,11 +438,12 @@ export function createLocalEditorHarness(options) {
|
|
|
333
438
|
};
|
|
334
439
|
harness = {
|
|
335
440
|
render() {
|
|
336
|
-
syncSceneCameraPreview(state, options);
|
|
337
441
|
syncViewportCameraState(state);
|
|
338
442
|
syncViewportMeasurementState(state);
|
|
339
|
-
syncViewportSpatialOverlay(state);
|
|
443
|
+
syncViewportSpatialOverlay(state, options);
|
|
340
444
|
ui.update(createUiState(state, options));
|
|
445
|
+
syncPrefabComparisonPreviewSurfaces(state, ui);
|
|
446
|
+
syncSceneCameraPreview(state, options);
|
|
341
447
|
},
|
|
342
448
|
notifyViewportRevealed(reason = 'viewport-revealed') {
|
|
343
449
|
state.viewportRenderCoordinator?.requestRevealFrame(reason);
|
|
@@ -351,6 +457,9 @@ export function createLocalEditorHarness(options) {
|
|
|
351
457
|
getHostServices() {
|
|
352
458
|
return options.hostServices ?? null;
|
|
353
459
|
},
|
|
460
|
+
getAgentBridge() {
|
|
461
|
+
return state.agentBridge;
|
|
462
|
+
},
|
|
354
463
|
getWorkingDocument() {
|
|
355
464
|
return state.session?.getState().workingDocument ?? null;
|
|
356
465
|
},
|
|
@@ -412,6 +521,10 @@ export function createLocalEditorHarness(options) {
|
|
|
412
521
|
const preparedDocument = options.documentAdapter.prepareDocument?.(document, assets) ?? document;
|
|
413
522
|
state.assets = assets;
|
|
414
523
|
state.source = source;
|
|
524
|
+
state.markerGraphVisibility = createDefaultMarkerGraphVisibilityState();
|
|
525
|
+
state.activeMarkerRelationId = null;
|
|
526
|
+
state.markerRelationHighlightContinuous = false;
|
|
527
|
+
state.markerCreateReservations = createEmptyMarkerCreateReservations();
|
|
415
528
|
state.session = createEditorSession({
|
|
416
529
|
source: source ?? undefined,
|
|
417
530
|
persistedDocument: preparedDocument,
|
|
@@ -425,7 +538,8 @@ export function createLocalEditorHarness(options) {
|
|
|
425
538
|
ui.updatePreview(previewState);
|
|
426
539
|
else
|
|
427
540
|
ui.update(createUiState(state, options));
|
|
428
|
-
|
|
541
|
+
syncPrefabComparisonPreviewSurfaces(state, ui);
|
|
542
|
+
}, stats => ui.updateSceneFrameStats?.(stats), stats => ui.updatePerformanceStats?.(stats), () => ui.getPrefabComparisonPreviewSurfaces?.() ?? []);
|
|
429
543
|
state.mode = 'editor';
|
|
430
544
|
state.summary = loadedSource?.summary ?? summarizeDocument(options, preparedDocument, source);
|
|
431
545
|
state.status = `GameWorld disposed; EditorWorld active; assets=${assets.length}`;
|
|
@@ -499,11 +613,102 @@ export function createLocalEditorHarness(options) {
|
|
|
499
613
|
await runGameFromEditor('discard');
|
|
500
614
|
},
|
|
501
615
|
dispose() {
|
|
616
|
+
state.agentBridgeTransport?.dispose();
|
|
617
|
+
state.agentBridgeTransport = null;
|
|
618
|
+
state.unregisterAgentBridgeCapabilities?.();
|
|
619
|
+
state.unregisterAgentBridgeCapabilities = null;
|
|
502
620
|
disposeEditorWorld(state);
|
|
503
621
|
state.session = null;
|
|
504
622
|
ui.dispose();
|
|
505
623
|
},
|
|
506
624
|
};
|
|
625
|
+
const agentBridgeCapabilitySourceOperations = {
|
|
626
|
+
createAssetFromAssetId: (assetId, createOptions) => harness.createAssetFromAssetId(assetId, createOptions),
|
|
627
|
+
getPrefabStage: () => summarizeAgentBridgePrefabStage(state, options),
|
|
628
|
+
getPrefabStageDetails: () => summarizeAgentBridgePrefabStageDetails(state, options),
|
|
629
|
+
openPrefabStage: (input) => {
|
|
630
|
+
const previousStage = summarizeAgentBridgePrefabStage(state, options);
|
|
631
|
+
const opened = enterPrefabStage(state, options, {
|
|
632
|
+
actionId: 'asset.edit-prefab',
|
|
633
|
+
assetId: input.assetId,
|
|
634
|
+
browserAssetId: input.browserAssetId,
|
|
635
|
+
assetKind: 'prefab',
|
|
636
|
+
});
|
|
637
|
+
const stage = summarizeAgentBridgePrefabStage(state, options);
|
|
638
|
+
if (!opened || !stage)
|
|
639
|
+
return null;
|
|
640
|
+
const alreadyOpen = isSameAgentBridgePrefabStage(previousStage, stage);
|
|
641
|
+
return {
|
|
642
|
+
opened: !alreadyOpen,
|
|
643
|
+
alreadyOpen,
|
|
644
|
+
prefab: createAgentBridgePrefabSummaryFromStage(stage),
|
|
645
|
+
stage,
|
|
646
|
+
status: state.status,
|
|
647
|
+
};
|
|
648
|
+
},
|
|
649
|
+
exitPrefabStage: () => {
|
|
650
|
+
const previousStage = summarizeAgentBridgePrefabStage(state, options);
|
|
651
|
+
const exited = exitPrefabStage(state, options);
|
|
652
|
+
return {
|
|
653
|
+
exited,
|
|
654
|
+
wasOpen: !!previousStage,
|
|
655
|
+
...(previousStage ? { previousStage } : {}),
|
|
656
|
+
status: exited ? state.status : 'No Prefab stage is open.',
|
|
657
|
+
};
|
|
658
|
+
},
|
|
659
|
+
selectPrefabStageItem: itemId => selectPrefabStageItemWithPreviewSync(state, options, itemId),
|
|
660
|
+
runPrefabStageAssetAction: input => patchBrowserAssetAction(state, options, input),
|
|
661
|
+
getHierarchy: () => createUiState(state, options).hierarchy,
|
|
662
|
+
dispatchSelectionCommand: (command, shouldRenderUi = false) => dispatchSelectionCommand(state, options, command, shouldRenderUi ? () => harness.render() : undefined),
|
|
663
|
+
focusProjectionNode: objectId => frameViewportProjectionNode(state, objectId),
|
|
664
|
+
focusSelectedProjection: () => frameSelectedViewportProjection(state, options),
|
|
665
|
+
syncViewportCameraState: () => syncViewportCameraState(state),
|
|
666
|
+
requestSceneFrame: reason => requestEditorSceneFrame(state, reason),
|
|
667
|
+
cloneTransformSnapshot: transform => cloneEditorTransformSnapshot(transform),
|
|
668
|
+
cancelActiveOperation: () => cancelActiveOperation(state),
|
|
669
|
+
withProjectionImpact,
|
|
670
|
+
resolveProjectionImpact,
|
|
671
|
+
createReprojectProjectionImpact,
|
|
672
|
+
createTransformProjectionImpact,
|
|
673
|
+
createKnownCreatedReprojectProjectionImpact,
|
|
674
|
+
createDeletedNodeProjectionImpact,
|
|
675
|
+
reprojectProjectionForChangedIds: (document, changedIds) => reprojectProjectionForChangedIds(state, options, document, changedIds),
|
|
676
|
+
syncProjectionForChangedIds: (document, changedIds) => syncProjectionForChangedIds(state, options, document, changedIds),
|
|
677
|
+
rebuildProjectionFromDocument: (document, selection) => rebuildProjectionFromDocument(state, options, document, selection),
|
|
678
|
+
sanitizeSelection: (document, selection) => sanitizeSelection(state, options, document, selection),
|
|
679
|
+
summarizeDocument: (document, source) => summarizeDocument(options, document, source),
|
|
680
|
+
invalidateStaticShadowArtifact: () => {
|
|
681
|
+
if (!state.shadowPreview?.invalidateStaticProjectedArtifact)
|
|
682
|
+
return false;
|
|
683
|
+
state.shadowPreview.invalidateStaticProjectedArtifact();
|
|
684
|
+
requestEditorSceneFrame(state, 'agent-shadow-static-invalidate');
|
|
685
|
+
return true;
|
|
686
|
+
},
|
|
687
|
+
getShadowPreviewDebugInfo: () => state.shadowPreview?.getDebugInfo?.() ?? null,
|
|
688
|
+
setShadowDebugOverlay: (items) => {
|
|
689
|
+
const overlayIds = state.projection?.setShadowDebugOverlay?.(items) ?? [];
|
|
690
|
+
requestEditorSceneFrame(state, 'agent-shadow-debug-overlay-set');
|
|
691
|
+
return overlayIds;
|
|
692
|
+
},
|
|
693
|
+
clearShadowDebugOverlay: () => {
|
|
694
|
+
const cleared = state.projection?.clearShadowDebugOverlay?.() ?? false;
|
|
695
|
+
if (cleared)
|
|
696
|
+
requestEditorSceneFrame(state, 'agent-shadow-debug-overlay-clear');
|
|
697
|
+
return cleared;
|
|
698
|
+
},
|
|
699
|
+
resolvePrefabStageProjectionNodeId: (nodeId) => {
|
|
700
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument;
|
|
701
|
+
return document ? resolvePrefabStageProjectionNodeIdForNode(state, options, document, nodeId) : null;
|
|
702
|
+
},
|
|
703
|
+
runRenderingAction: actionId => applyRenderingAction(state, options, { actionId }, () => harness.render()),
|
|
704
|
+
};
|
|
705
|
+
state.unregisterAgentBridgeCapabilities = registerLocalEditorAgentBridgeCapabilities(state.agentBridge, createLocalEditorAgentBridgeCapabilitySources(state, options, () => harness.render(), () => runExclusive(state, harness.render, () => harness.enterEditor()), agentBridgeCapabilitySourceOperations));
|
|
706
|
+
state.agentBridgeTransport = createLocalEditorAgentBridgeWebSocketTransportFromQuery(state.agentBridge, {
|
|
707
|
+
onStatusChange: agentBridgeStatus => {
|
|
708
|
+
state.agentBridgeStatus = agentBridgeStatus;
|
|
709
|
+
harness.render();
|
|
710
|
+
},
|
|
711
|
+
});
|
|
507
712
|
harness.render();
|
|
508
713
|
return harness;
|
|
509
714
|
}
|
|
@@ -533,6 +738,13 @@ export function mergeLocalEditorHarnessInspectorComponentSections(input) {
|
|
|
533
738
|
}),
|
|
534
739
|
};
|
|
535
740
|
}
|
|
741
|
+
function isAgentBridgeObjectSelectable(options, document, objectId, hierarchyItems) {
|
|
742
|
+
const inHierarchy = hierarchyItems.some(item => item.id === objectId);
|
|
743
|
+
const hasProjectionNode = !!options.documentAdapter.getProjectionNode(document, objectId);
|
|
744
|
+
if (!inHierarchy && !hasProjectionNode)
|
|
745
|
+
return false;
|
|
746
|
+
return isNodeSelectableInDocument(options, document, objectId);
|
|
747
|
+
}
|
|
536
748
|
function normalizeTransformConstraint(tool, constraint) {
|
|
537
749
|
return normalizeEditorTransformConstraint(tool, constraint) ?? 'axis';
|
|
538
750
|
}
|
|
@@ -568,7 +780,16 @@ function normalizePlacementMode(mode) {
|
|
|
568
780
|
return mode === 'ground' || mode === 'surface' ? mode : 'off';
|
|
569
781
|
}
|
|
570
782
|
function normalizeViewportViewPreset(preset) {
|
|
571
|
-
return preset === 'top'
|
|
783
|
+
return preset === 'top'
|
|
784
|
+
|| preset === 'bottom'
|
|
785
|
+
|| preset === 'front'
|
|
786
|
+
|| preset === 'back'
|
|
787
|
+
|| preset === 'left'
|
|
788
|
+
|| preset === 'right'
|
|
789
|
+
|| preset === 'iso'
|
|
790
|
+
|| preset === 'threeQuarterTop'
|
|
791
|
+
? preset
|
|
792
|
+
: 'perspective';
|
|
572
793
|
}
|
|
573
794
|
function normalizeViewportProjectionMode(mode) {
|
|
574
795
|
return mode === 'orthographic' ? 'orthographic' : 'perspective';
|
|
@@ -599,7 +820,7 @@ function cloneViewportMeasurement(measurement) {
|
|
|
599
820
|
label: measurement.label ? { ...measurement.label } : null,
|
|
600
821
|
};
|
|
601
822
|
}
|
|
602
|
-
function setViewportViewPreset(state, preset) {
|
|
823
|
+
function setViewportViewPreset(state, options, preset) {
|
|
603
824
|
if (state.sceneCameraPreviewEnabled) {
|
|
604
825
|
state.status = 'Viewport view unavailable during Scene Camera preview';
|
|
605
826
|
state.statusTone = 'warning';
|
|
@@ -608,8 +829,8 @@ function setViewportViewPreset(state, preset) {
|
|
|
608
829
|
return true;
|
|
609
830
|
}
|
|
610
831
|
const nextPreset = normalizeViewportViewPreset(preset);
|
|
611
|
-
const target = resolveViewportPresetTarget(state);
|
|
612
|
-
const radius = resolveViewportPresetRadius(state);
|
|
832
|
+
const target = resolveViewportPresetTarget(state, options);
|
|
833
|
+
const radius = resolveViewportPresetRadius(state, options);
|
|
613
834
|
const changed = state.sceneViewCamera?.setViewPreset(nextPreset, { target, radius }) ?? false;
|
|
614
835
|
if (!changed)
|
|
615
836
|
return false;
|
|
@@ -667,6 +888,25 @@ function setViewportOverlaySettings(state, settings) {
|
|
|
667
888
|
state.statusDetails = '';
|
|
668
889
|
return true;
|
|
669
890
|
}
|
|
891
|
+
function setMarkerViewportVisibility(state, options, visible) {
|
|
892
|
+
const nextVisible = visible !== false;
|
|
893
|
+
if ((state.viewportTools.markersVisible ?? true) === nextVisible)
|
|
894
|
+
return false;
|
|
895
|
+
state.viewportTools = {
|
|
896
|
+
...state.viewportTools,
|
|
897
|
+
markersVisible: nextVisible,
|
|
898
|
+
};
|
|
899
|
+
state.status = nextVisible ? 'Marker view shown' : 'Marker view hidden';
|
|
900
|
+
state.statusTone = 'default';
|
|
901
|
+
state.statusToneStatus = state.status;
|
|
902
|
+
state.statusDetails = nextVisible
|
|
903
|
+
? 'Marker overlays and relation lines are visible in the editor viewport.'
|
|
904
|
+
: 'Marker overlays and relation lines are temporarily hidden in the editor viewport.';
|
|
905
|
+
state.editorStateRevision += 1;
|
|
906
|
+
syncCurrentSelectionToSceneArtifacts(state, options, 'marker-viewport-visibility', state.editorStateRevision);
|
|
907
|
+
requestEditorSceneFrame(state, 'marker-viewport-visibility');
|
|
908
|
+
return true;
|
|
909
|
+
}
|
|
670
910
|
function setViewportUtilityTool(state, tool) {
|
|
671
911
|
const nextTool = tool === 'measure-distance' ? 'measure-distance' : 'none';
|
|
672
912
|
state.viewportTools = {
|
|
@@ -769,18 +1009,18 @@ function formatViewportMeasurementDistance(value) {
|
|
|
769
1009
|
const rounded = Math.abs(value) < 0.005 ? 0 : value;
|
|
770
1010
|
return rounded.toFixed(2).replace(/\.?0+$/, '');
|
|
771
1011
|
}
|
|
772
|
-
function resolveViewportPresetTarget(state) {
|
|
773
|
-
const selection = state
|
|
774
|
-
const activeId = selection
|
|
775
|
-
if (!activeId || selection
|
|
1012
|
+
function resolveViewportPresetTarget(state, options) {
|
|
1013
|
+
const selection = getCurrentPreviewSelection(state, options);
|
|
1014
|
+
const activeId = selection.activeId;
|
|
1015
|
+
if (!activeId || selection.selectedIds.length !== 1)
|
|
776
1016
|
return null;
|
|
777
1017
|
const bounds = state.projection?.getSelectionBounds([activeId]) ?? null;
|
|
778
1018
|
return bounds?.center ?? null;
|
|
779
1019
|
}
|
|
780
|
-
function resolveViewportPresetRadius(state) {
|
|
781
|
-
const selection = state
|
|
782
|
-
const activeId = selection
|
|
783
|
-
if (!activeId || selection
|
|
1020
|
+
function resolveViewportPresetRadius(state, options) {
|
|
1021
|
+
const selection = getCurrentPreviewSelection(state, options);
|
|
1022
|
+
const activeId = selection.activeId;
|
|
1023
|
+
if (!activeId || selection.selectedIds.length !== 1)
|
|
784
1024
|
return undefined;
|
|
785
1025
|
const bounds = state.projection?.getSelectionBounds([activeId]) ?? null;
|
|
786
1026
|
if (!bounds)
|
|
@@ -801,7 +1041,7 @@ function validateTransformActionSelection(state, action) {
|
|
|
801
1041
|
? { ok: true }
|
|
802
1042
|
: { ok: false, message: 'Distribute needs at least 3 selected objects' };
|
|
803
1043
|
}
|
|
804
|
-
async function createEditorWorld(state, options, renderUi, renderPreviewUi, updateSceneFrameStats, updatePerformanceStats) {
|
|
1044
|
+
async function createEditorWorld(state, options, renderUi, renderPreviewUi, updateSceneFrameStats, updatePerformanceStats, getPrefabComparisonPreviewSurfaces) {
|
|
805
1045
|
disposeEditorWorld(state);
|
|
806
1046
|
const render = (reason = 'editor-world-update') => {
|
|
807
1047
|
renderUi();
|
|
@@ -816,9 +1056,9 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
816
1056
|
const babylon = await options.worldAdapter.loadBabylon();
|
|
817
1057
|
const engine = options.worldAdapter.createEngine(babylon, canvas);
|
|
818
1058
|
const document = state.session?.getState().workingDocument;
|
|
819
|
-
const initialAppearance =
|
|
1059
|
+
const initialAppearance = resolveEffectiveLocalEditorWorldAppearance(state, options, document);
|
|
820
1060
|
const initialAppearanceKey = serializeLocalEditorWorldAppearance(initialAppearance);
|
|
821
|
-
const initialRendering =
|
|
1061
|
+
const initialRendering = resolveEffectiveLocalEditorWorldRendering(state, options, document);
|
|
822
1062
|
const initialRenderingKey = serializeLocalEditorWorldRendering(initialRendering);
|
|
823
1063
|
const world = createBabylonEditorWorld({
|
|
824
1064
|
engine,
|
|
@@ -834,6 +1074,8 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
834
1074
|
const performanceMonitor = createBabylonEditorPerformanceMonitor(world.scene);
|
|
835
1075
|
const sceneRenderScheduler = createLocalEditorSceneRenderScheduler((frame) => {
|
|
836
1076
|
state.sceneViewInteraction?.updateFrame(frame);
|
|
1077
|
+
syncPrefabComparisonPreviewSurfaces(state, { getPrefabComparisonPreviewSurfaces });
|
|
1078
|
+
state.prefabComparisonPreview?.prepareFrame();
|
|
837
1079
|
world.render();
|
|
838
1080
|
}, {
|
|
839
1081
|
onStatsChange(stats) {
|
|
@@ -867,19 +1109,46 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
867
1109
|
selectionEdgesPrewarm: options.world?.selectionEdgesPrewarm,
|
|
868
1110
|
logger: console,
|
|
869
1111
|
onProjectionReady(event) {
|
|
870
|
-
|
|
1112
|
+
if (state.prefabStage) {
|
|
1113
|
+
syncPrefabStageSelectionToProjection(state, options, `prefab-stage-projection-${event.nodeId}-ready-selection`);
|
|
1114
|
+
focusPrefabStagePreviewProjection(state, `prefab-stage-projection-${event.nodeId}-ready-focus`);
|
|
1115
|
+
scheduleProjectionShadowPreviewRebuild(state, `prefab-stage-projection-${event.nodeId}-ready-shadow`);
|
|
1116
|
+
viewportRenderCoordinator.invalidateScene(`prefab-stage-projection-${event.nodeId}-ready`);
|
|
1117
|
+
renderUi();
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
syncCurrentSelectionToSceneArtifacts(state, options, `projection-${event.nodeId}-ready-selection`);
|
|
871
1121
|
scheduleProjectionShadowPreviewRebuild(state, `projection-${event.nodeId}-ready-shadow`);
|
|
872
1122
|
viewportRenderCoordinator.invalidateScene(`projection-${event.nodeId}-ready`);
|
|
873
1123
|
},
|
|
874
1124
|
onProjectionBatchSettled(event) {
|
|
875
|
-
|
|
1125
|
+
if (state.prefabStage) {
|
|
1126
|
+
syncPrefabStageSelectionToProjection(state, options, `prefab-stage-projection-batch-${event.batchId}-settled-selection`);
|
|
1127
|
+
focusPrefabStagePreviewProjection(state, `prefab-stage-projection-batch-${event.batchId}-settled-focus`);
|
|
1128
|
+
scheduleProjectionShadowPreviewRebuild(state, `prefab-stage-projection-batch-${event.batchId}-settled`);
|
|
1129
|
+
renderUi();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
syncCurrentSelectionToSceneArtifacts(state, options, `projection-batch-${event.batchId}-settled-selection`);
|
|
876
1133
|
scheduleProjectionShadowPreviewRebuild(state, `projection-batch-${event.batchId}-settled`);
|
|
877
1134
|
},
|
|
878
1135
|
});
|
|
879
|
-
const
|
|
1136
|
+
const prefabComparisonPreview = createBabylonPrefabComparisonPreviewController({
|
|
880
1137
|
babylon,
|
|
881
1138
|
scene: world.scene,
|
|
1139
|
+
editorCamera: world.camera,
|
|
882
1140
|
projection,
|
|
1141
|
+
getSkyBackdrop: () => world.skyBackdrop,
|
|
1142
|
+
});
|
|
1143
|
+
const markerOverlay = createBabylonEditorMarkerOverlayController({
|
|
1144
|
+
babylon,
|
|
1145
|
+
scene: world.scene,
|
|
1146
|
+
});
|
|
1147
|
+
const markerAwareProjection = createBabylonMarkerOverlayProjectionAdapter(projection, markerOverlay);
|
|
1148
|
+
const gizmo = createBabylonTransformGizmoController({
|
|
1149
|
+
babylon,
|
|
1150
|
+
scene: world.scene,
|
|
1151
|
+
projection: markerAwareProjection,
|
|
883
1152
|
initialTool: state.transformTool,
|
|
884
1153
|
initialSpace: state.transformSpace,
|
|
885
1154
|
documentCapabilities: options.transformDocumentCapabilities,
|
|
@@ -897,6 +1166,8 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
897
1166
|
},
|
|
898
1167
|
onDragUpdate(event) {
|
|
899
1168
|
updateActiveTransformPreview(state, event);
|
|
1169
|
+
syncMarkerOverlayToSceneArtifacts(state, options, state.session?.getState().selection ?? { selectedIds: [], activeId: null });
|
|
1170
|
+
state.gizmo?.refreshSelection();
|
|
900
1171
|
preview('gizmo-drag-update');
|
|
901
1172
|
},
|
|
902
1173
|
onDragEnd(event) {
|
|
@@ -931,24 +1202,48 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
931
1202
|
renderUi();
|
|
932
1203
|
},
|
|
933
1204
|
onDuplicateDragStart(input) {
|
|
1205
|
+
if (state.prefabStage) {
|
|
1206
|
+
state.status = 'Duplicate drag is not available in Prefab Stage';
|
|
1207
|
+
state.statusTone = 'warning';
|
|
1208
|
+
state.statusToneStatus = state.status;
|
|
1209
|
+
state.statusDetails = 'Use prefab.node.createFromAsset or prefab.node.createPrimitive to add prefab nodes.';
|
|
1210
|
+
renderUi();
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
934
1213
|
return beginDuplicateDrag(state, options, input);
|
|
935
1214
|
},
|
|
936
1215
|
});
|
|
937
|
-
gizmo.setOperationSettings(state
|
|
1216
|
+
gizmo.setOperationSettings(getScopedTransformOperationSettings(state));
|
|
938
1217
|
gizmo.setConstraint(state.transformConstraint);
|
|
939
1218
|
const selectionController = createBabylonProjectionSelectionController({
|
|
940
1219
|
scene: world.scene,
|
|
941
1220
|
canvas,
|
|
942
|
-
projection,
|
|
1221
|
+
projection: markerAwareProjection,
|
|
943
1222
|
getTool: () => state.transformTool,
|
|
944
|
-
getSelection: () => state.
|
|
945
|
-
|
|
946
|
-
|
|
1223
|
+
getSelection: () => state.prefabStage
|
|
1224
|
+
? getCurrentPrefabStageProjectionSelection(state, options)
|
|
1225
|
+
: state.session?.getSelection() ?? EMPTY_EDITOR_SELECTION,
|
|
1226
|
+
isSelectable: (nodeId) => state.prefabStage
|
|
1227
|
+
? isPrefabStageProjectionSelectable(state, options, nodeId)
|
|
1228
|
+
: isDocumentNodeSelectable(state, options, nodeId),
|
|
1229
|
+
isLocked: (nodeId) => state.prefabStage
|
|
1230
|
+
? !isPrefabStageProjectionSelectable(state, options, nodeId)
|
|
1231
|
+
: isDocumentNodeLocked(state, options, nodeId),
|
|
947
1232
|
isOperationBlocked: () => state.gizmo?.getState().dragPhase === 'dragging',
|
|
948
1233
|
onSelectionCommand(command) {
|
|
1234
|
+
if (state.prefabStage) {
|
|
1235
|
+
if (dispatchPrefabStageProjectionSelectionCommand(state, options, command))
|
|
1236
|
+
render();
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
949
1239
|
dispatchSelectionCommand(state, options, command, render);
|
|
950
1240
|
},
|
|
951
1241
|
onFocusIntent(nodeId) {
|
|
1242
|
+
if (state.prefabStage) {
|
|
1243
|
+
if (focusPrefabStageProjectionNode(state, options, nodeId, 'prefab-stage-preview-focus-intent'))
|
|
1244
|
+
render();
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
952
1247
|
if (focusProjectionNode(state, nodeId))
|
|
953
1248
|
render();
|
|
954
1249
|
},
|
|
@@ -967,7 +1262,7 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
967
1262
|
isGizmoDragCandidate: (event) => gizmo.isGizmoDragCandidate(event),
|
|
968
1263
|
isBoxSelectCandidate: (event) => selectionController.isBoxSelectionCandidate(event),
|
|
969
1264
|
isViewPlaneMoveCandidate: (event) => gizmo.isViewPlaneMoveCandidate(event),
|
|
970
|
-
isPlacementCandidate: () => isPlacementArmed(state),
|
|
1265
|
+
isPlacementCandidate: () => !state.prefabStage && isPlacementArmed(state),
|
|
971
1266
|
isMeasurementCandidate: () => state.viewportTools.activeUtilityTool === 'measure-distance',
|
|
972
1267
|
onPointerIntentStart(event) {
|
|
973
1268
|
sceneViewInteraction.beginPointerIntent(event.state.intent);
|
|
@@ -1100,6 +1395,7 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
1100
1395
|
},
|
|
1101
1396
|
});
|
|
1102
1397
|
const environmentTexture = createBabylonEnvironmentTextureController(world.scene, initialRendering.environment ?? null);
|
|
1398
|
+
world.refreshSkyBackdrop();
|
|
1103
1399
|
const postProcess = createBabylonDefaultPostProcessPipelineController(world.scene, [world.camera], initialRendering.postProcess ?? null, { name: 'editorDefaultPostProcessPipeline' });
|
|
1104
1400
|
const resize = () => {
|
|
1105
1401
|
engine.resize?.();
|
|
@@ -1110,7 +1406,9 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
1110
1406
|
state.engine = engine;
|
|
1111
1407
|
state.world = world;
|
|
1112
1408
|
state.grid = grid;
|
|
1113
|
-
state.projection =
|
|
1409
|
+
state.projection = markerAwareProjection;
|
|
1410
|
+
state.prefabComparisonPreview = prefabComparisonPreview;
|
|
1411
|
+
state.markerOverlay = markerOverlay;
|
|
1114
1412
|
state.shadowPreview = shadowPreview;
|
|
1115
1413
|
state.environmentTexture = environmentTexture;
|
|
1116
1414
|
state.postProcess = postProcess;
|
|
@@ -1130,13 +1428,15 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
|
|
|
1130
1428
|
state.worldRenderingKey = initialRenderingKey;
|
|
1131
1429
|
state.resizeHandler = resize;
|
|
1132
1430
|
if (document) {
|
|
1133
|
-
projection.projectNodes(options
|
|
1431
|
+
projection.projectNodes(resolveCurrentEditorProjectionNodes(state, options, document));
|
|
1432
|
+
applyPreviewVisibilityStateToProjection(state);
|
|
1134
1433
|
scheduleProjectionShadowPreviewRebuild(state, 'editor-world-initial-projection-shadow');
|
|
1135
1434
|
}
|
|
1136
|
-
syncCurrentSelectionToSceneArtifacts(state, 'editor-world-initial-selection');
|
|
1435
|
+
syncCurrentSelectionToSceneArtifacts(state, options, 'editor-world-initial-selection');
|
|
1137
1436
|
viewportRenderCoordinator.requestFrame('editor-world-created');
|
|
1138
1437
|
}
|
|
1139
1438
|
function disposeEditorWorld(state) {
|
|
1439
|
+
clearPrefabStageForEditorTeardown(state);
|
|
1140
1440
|
state.activeTransformPreview = null;
|
|
1141
1441
|
state.sceneViewInteraction?.dispose();
|
|
1142
1442
|
state.sceneViewInteraction = null;
|
|
@@ -1157,6 +1457,12 @@ function disposeEditorWorld(state) {
|
|
|
1157
1457
|
state.sceneViewInput = null;
|
|
1158
1458
|
state.selectionController?.dispose();
|
|
1159
1459
|
state.selectionController = null;
|
|
1460
|
+
state.prefabComparisonPreview?.dispose();
|
|
1461
|
+
state.prefabComparisonPreview = null;
|
|
1462
|
+
if (state.markerRelationHighlightContinuous) {
|
|
1463
|
+
state.viewportRenderCoordinator?.endContinuous(MARKER_RELATION_HIGHLIGHT_RENDER_REASON);
|
|
1464
|
+
state.markerRelationHighlightContinuous = false;
|
|
1465
|
+
}
|
|
1160
1466
|
if (state.performanceMonitorOpen) {
|
|
1161
1467
|
state.viewportRenderCoordinator?.endContinuous(LOCAL_EDITOR_PERFORMANCE_MONITOR_REASON);
|
|
1162
1468
|
}
|
|
@@ -1179,6 +1485,8 @@ function disposeEditorWorld(state) {
|
|
|
1179
1485
|
};
|
|
1180
1486
|
state.gizmo?.dispose();
|
|
1181
1487
|
state.gizmo = null;
|
|
1488
|
+
state.markerOverlay?.dispose();
|
|
1489
|
+
state.markerOverlay = null;
|
|
1182
1490
|
if (state.projectionShadowPreviewRebuildFrame !== null) {
|
|
1183
1491
|
window.cancelAnimationFrame(state.projectionShadowPreviewRebuildFrame);
|
|
1184
1492
|
state.projectionShadowPreviewRebuildFrame = null;
|
|
@@ -1204,6 +1512,16 @@ function disposeEditorWorld(state) {
|
|
|
1204
1512
|
state.world = null;
|
|
1205
1513
|
state.engine = null;
|
|
1206
1514
|
}
|
|
1515
|
+
function clearPrefabStageForEditorTeardown(state) {
|
|
1516
|
+
const stage = state.prefabStage;
|
|
1517
|
+
if (!stage)
|
|
1518
|
+
return;
|
|
1519
|
+
state.prefabStage = null;
|
|
1520
|
+
setGridVisibleForEditorContext(state, stage.restoreGridVisible, 'prefab-stage-editor-teardown-grid');
|
|
1521
|
+
state.sceneCameraPreviewEnabled = stage.restoreSceneCameraPreviewEnabled;
|
|
1522
|
+
if (!stage.restoreSceneCameraPreviewEnabled)
|
|
1523
|
+
state.sceneCameraPreview?.setActive(false);
|
|
1524
|
+
}
|
|
1207
1525
|
async function waitForEditorProjectionIdleBeforeRunGame(state) {
|
|
1208
1526
|
const projection = state.projection;
|
|
1209
1527
|
if (!projection)
|
|
@@ -1267,10 +1585,31 @@ function requestEditorSceneFrame(state, reason) {
|
|
|
1267
1585
|
function requestEditorPreviewFrame(state, options, renderPreviewUi, reason) {
|
|
1268
1586
|
syncViewportCameraState(state);
|
|
1269
1587
|
syncViewportMeasurementState(state);
|
|
1270
|
-
syncViewportSpatialOverlay(state);
|
|
1588
|
+
syncViewportSpatialOverlay(state, options);
|
|
1271
1589
|
renderPreviewUi(createUiPreviewState(state, options));
|
|
1272
1590
|
requestEditorSceneFrame(state, reason);
|
|
1273
1591
|
}
|
|
1592
|
+
function syncPrefabComparisonPreviewSurfaces(state, ui) {
|
|
1593
|
+
const controller = state.prefabComparisonPreview;
|
|
1594
|
+
if (!controller)
|
|
1595
|
+
return;
|
|
1596
|
+
if (!state.prefabStage) {
|
|
1597
|
+
if (controller.clear())
|
|
1598
|
+
requestEditorSceneFrame(state, 'prefab-comparison-preview-clear');
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const surfaces = ui.getPrefabComparisonPreviewSurfaces?.() ?? [];
|
|
1602
|
+
const changed = controller.sync(surfaces.map(toBabylonPrefabComparisonPreviewSurface));
|
|
1603
|
+
if (changed)
|
|
1604
|
+
requestEditorSceneFrame(state, 'prefab-comparison-preview-sync');
|
|
1605
|
+
}
|
|
1606
|
+
function toBabylonPrefabComparisonPreviewSurface(surface) {
|
|
1607
|
+
return {
|
|
1608
|
+
previewId: surface.previewId,
|
|
1609
|
+
projectionNodeId: surface.projectionNodeId,
|
|
1610
|
+
rect: surface.rect,
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1274
1613
|
function updateActiveTransformPreview(state, event) {
|
|
1275
1614
|
const activeId = event.activeId ?? event.nodeId ?? event.targetIds[0] ?? null;
|
|
1276
1615
|
if (!activeId) {
|
|
@@ -1351,13 +1690,29 @@ function selectItem(state, options, input, renderUi) {
|
|
|
1351
1690
|
return dispatchSelectionCommand(state, options, command, renderUi);
|
|
1352
1691
|
}
|
|
1353
1692
|
function createBrowserHierarchyContextActions(state, options) {
|
|
1354
|
-
return (options
|
|
1693
|
+
return createHierarchyContextActionRegistrations(state, options).map((registration) => ({
|
|
1355
1694
|
id: registration.id,
|
|
1356
1695
|
label: registration.label,
|
|
1357
1696
|
shortcut: registration.shortcut,
|
|
1358
1697
|
danger: registration.danger,
|
|
1359
1698
|
placement: registration.placement,
|
|
1360
1699
|
separatorBefore: registration.separatorBefore,
|
|
1700
|
+
children: (browserContext) => {
|
|
1701
|
+
const context = createHarnessHierarchyContextActionContext(state, options, browserContext);
|
|
1702
|
+
if (!context)
|
|
1703
|
+
return [];
|
|
1704
|
+
const children = typeof registration.children === 'function'
|
|
1705
|
+
? registration.children(context)
|
|
1706
|
+
: registration.children ?? [];
|
|
1707
|
+
return children.map(child => ({
|
|
1708
|
+
id: child.id,
|
|
1709
|
+
label: child.label,
|
|
1710
|
+
shortcut: child.shortcut,
|
|
1711
|
+
danger: child.danger,
|
|
1712
|
+
disabled: () => child.disabled?.(context) ?? false,
|
|
1713
|
+
payload: () => child.payload?.(context),
|
|
1714
|
+
}));
|
|
1715
|
+
},
|
|
1361
1716
|
visible: (browserContext) => {
|
|
1362
1717
|
const context = createHarnessHierarchyContextActionContext(state, options, browserContext);
|
|
1363
1718
|
if (!context)
|
|
@@ -1372,6 +1727,40 @@ function createBrowserHierarchyContextActions(state, options) {
|
|
|
1372
1727
|
},
|
|
1373
1728
|
}));
|
|
1374
1729
|
}
|
|
1730
|
+
function createHierarchyContextActionRegistrations(state, options) {
|
|
1731
|
+
return [
|
|
1732
|
+
createPrefabFromGameObjectHierarchyContextAction(state, options),
|
|
1733
|
+
...(options.hierarchy?.contextActions ?? []),
|
|
1734
|
+
];
|
|
1735
|
+
}
|
|
1736
|
+
function createPrefabFromGameObjectHierarchyContextAction(state, options) {
|
|
1737
|
+
return {
|
|
1738
|
+
id: 'asset.create-prefab-from-game-object',
|
|
1739
|
+
label: 'Create Prefab',
|
|
1740
|
+
placement: 'after-create',
|
|
1741
|
+
visible: (context) => (!state.prefabStage
|
|
1742
|
+
&& !!options.documentAdapter.createAssetActionPatch
|
|
1743
|
+
&& context.targetIds.length === 1
|
|
1744
|
+
&& context.activeId === context.targetIds[0]
|
|
1745
|
+
&& !!context.projectionNode?.asset),
|
|
1746
|
+
disabled: (context) => {
|
|
1747
|
+
if (context.targetIds.length !== 1 || !context.activeId)
|
|
1748
|
+
return 'Select exactly one model-backed GameObject.';
|
|
1749
|
+
if (!context.projectionNode?.asset)
|
|
1750
|
+
return 'Only model-backed GameObjects can be converted to Prefab assets.';
|
|
1751
|
+
return false;
|
|
1752
|
+
},
|
|
1753
|
+
run: (context) => patchBrowserAssetAction(state, options, {
|
|
1754
|
+
actionId: 'asset.create-prefab-from-game-object',
|
|
1755
|
+
assetId: undefined,
|
|
1756
|
+
browserAssetId: undefined,
|
|
1757
|
+
assetKind: 'prefab',
|
|
1758
|
+
}, {
|
|
1759
|
+
activeId: context.activeId,
|
|
1760
|
+
selectedIds: context.targetIds,
|
|
1761
|
+
}),
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1375
1764
|
function createHarnessHierarchyContextActionContext(state, options, browserContext, payload) {
|
|
1376
1765
|
const document = state.session?.getState().workingDocument ?? null;
|
|
1377
1766
|
if (!document)
|
|
@@ -1409,17 +1798,22 @@ function createBrowserContextForCustomAction(state, options, action) {
|
|
|
1409
1798
|
};
|
|
1410
1799
|
}
|
|
1411
1800
|
function runHierarchyCustomContextAction(state, options, action) {
|
|
1412
|
-
const registration = options.hierarchy?.contextActions?.find(candidate => candidate.id === action.id);
|
|
1413
|
-
if (!registration)
|
|
1414
|
-
return false;
|
|
1415
1801
|
const browserContext = createBrowserContextForCustomAction(state, options, action);
|
|
1416
1802
|
const context = browserContext
|
|
1417
1803
|
? createHarnessHierarchyContextActionContext(state, options, browserContext, action.payload)
|
|
1418
1804
|
: null;
|
|
1419
1805
|
if (!context)
|
|
1420
1806
|
return false;
|
|
1807
|
+
const registration = createHierarchyContextActionRegistrations(state, options)
|
|
1808
|
+
.find(candidate => candidate.id === action.id);
|
|
1809
|
+
if (!registration)
|
|
1810
|
+
return false;
|
|
1421
1811
|
try {
|
|
1422
|
-
|
|
1812
|
+
const result = registration.run(context);
|
|
1813
|
+
if (isLocalEditorHarnessPatchResult(result)) {
|
|
1814
|
+
return applyHierarchyContextActionPatch(state, options, result, registration.label);
|
|
1815
|
+
}
|
|
1816
|
+
return result === true;
|
|
1423
1817
|
}
|
|
1424
1818
|
catch (error) {
|
|
1425
1819
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1431,6 +1825,55 @@ function runHierarchyCustomContextAction(state, options, action) {
|
|
|
1431
1825
|
return true;
|
|
1432
1826
|
}
|
|
1433
1827
|
}
|
|
1828
|
+
function isLocalEditorHarnessPatchResult(value) {
|
|
1829
|
+
return !!value
|
|
1830
|
+
&& typeof value === 'object'
|
|
1831
|
+
&& 'patch' in value;
|
|
1832
|
+
}
|
|
1833
|
+
function applyHierarchyContextActionPatch(state, options, patch, fallbackLabel) {
|
|
1834
|
+
const document = state.session?.getState().workingDocument;
|
|
1835
|
+
if (state.mode !== 'editor' || !state.session || !document)
|
|
1836
|
+
return false;
|
|
1837
|
+
cancelActiveOperation(state);
|
|
1838
|
+
const label = patch.label ?? fallbackLabel;
|
|
1839
|
+
const projectionImpact = resolveProjectionImpact(patch, patch.createdId
|
|
1840
|
+
? createKnownCreatedReprojectProjectionImpact({
|
|
1841
|
+
createdNodeIds: [patch.createdId],
|
|
1842
|
+
reprojectIds: patch.reprojectIds,
|
|
1843
|
+
})
|
|
1844
|
+
: patch.reprojectIds?.length
|
|
1845
|
+
? createReprojectProjectionImpact(patch.reprojectIds)
|
|
1846
|
+
: patch.changedIds?.length
|
|
1847
|
+
? createReprojectProjectionImpact(patch.changedIds)
|
|
1848
|
+
: patch.changedId
|
|
1849
|
+
? createReprojectProjectionImpact([patch.changedId])
|
|
1850
|
+
: undefined);
|
|
1851
|
+
const result = state.session.dispatch({
|
|
1852
|
+
type: 'document.patch',
|
|
1853
|
+
label,
|
|
1854
|
+
patch: patch.patch,
|
|
1855
|
+
targetId: patch.createdId ?? patch.changedId ?? undefined,
|
|
1856
|
+
...withProjectionImpact(projectionImpact),
|
|
1857
|
+
});
|
|
1858
|
+
if (!result.documentChanged) {
|
|
1859
|
+
state.status = `${label} unchanged`;
|
|
1860
|
+
return true;
|
|
1861
|
+
}
|
|
1862
|
+
const selectionId = patch.createdId ?? patch.changedId ?? null;
|
|
1863
|
+
let selection = result.selection;
|
|
1864
|
+
if (selectionId && isNodeSelectableInDocument(options, result.workingDocument, selectionId)) {
|
|
1865
|
+
selection = state.session.dispatch({
|
|
1866
|
+
type: 'selection.replace',
|
|
1867
|
+
selectedIds: [selectionId],
|
|
1868
|
+
activeId: selectionId,
|
|
1869
|
+
label: `Select ${selectionId}`,
|
|
1870
|
+
}).selection;
|
|
1871
|
+
}
|
|
1872
|
+
rebuildProjectionFromDocument(state, options, result.workingDocument, selection);
|
|
1873
|
+
state.summary = summarizeDocument(options, result.workingDocument, state.session.getSource());
|
|
1874
|
+
state.status = label;
|
|
1875
|
+
return true;
|
|
1876
|
+
}
|
|
1434
1877
|
function handleContextAction(state, options, action) {
|
|
1435
1878
|
if (action.region !== 'hierarchy')
|
|
1436
1879
|
return false;
|
|
@@ -1446,7 +1889,7 @@ function handleContextAction(state, options, action) {
|
|
|
1446
1889
|
label: 'Select Context Target',
|
|
1447
1890
|
})
|
|
1448
1891
|
: false;
|
|
1449
|
-
return focusSelectedProjection(state) || selectionChanged;
|
|
1892
|
+
return focusSelectedProjection(state, options) || selectionChanged;
|
|
1450
1893
|
}
|
|
1451
1894
|
if (action.action === 'rename')
|
|
1452
1895
|
return false;
|
|
@@ -1465,6 +1908,14 @@ function handleContextAction(state, options, action) {
|
|
|
1465
1908
|
name: action.name,
|
|
1466
1909
|
});
|
|
1467
1910
|
}
|
|
1911
|
+
if (action.action === 'create-marker') {
|
|
1912
|
+
return createSceneGraphMarker(state, options, {
|
|
1913
|
+
parentId: action.parentId ?? null,
|
|
1914
|
+
activeId: action.activeId ?? null,
|
|
1915
|
+
markerType: action.markerType,
|
|
1916
|
+
name: action.name,
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1468
1919
|
if (action.action === 'delete') {
|
|
1469
1920
|
return deleteSceneGraphNodes(state, options, {
|
|
1470
1921
|
ids: action.targetIds,
|
|
@@ -1488,6 +1939,9 @@ function handleContextAction(state, options, action) {
|
|
|
1488
1939
|
function dispatchSelectionCommand(state, options, command, renderUi) {
|
|
1489
1940
|
if (state.mode !== 'editor')
|
|
1490
1941
|
return false;
|
|
1942
|
+
if (state.markerRelationPick) {
|
|
1943
|
+
return consumeMarkerRelationPickSelectionCommand(state, options, command, renderUi);
|
|
1944
|
+
}
|
|
1491
1945
|
cancelActiveOperation(state);
|
|
1492
1946
|
const session = state.session;
|
|
1493
1947
|
if (!session)
|
|
@@ -1499,16 +1953,109 @@ function dispatchSelectionCommand(state, options, command, renderUi) {
|
|
|
1499
1953
|
if (!changed)
|
|
1500
1954
|
return false;
|
|
1501
1955
|
if (renderUi) {
|
|
1502
|
-
commitEditorStateChange(state, renderUi, 'selection-command', () => { }, {
|
|
1956
|
+
commitEditorStateChange(state, options, renderUi, 'selection-command', () => { }, {
|
|
1503
1957
|
syncSelectionArtifacts: selection,
|
|
1504
1958
|
});
|
|
1505
1959
|
}
|
|
1506
1960
|
else {
|
|
1507
1961
|
state.editorStateRevision += 1;
|
|
1508
|
-
syncSelectionToProjection(state, selection, 'selection-command', state.editorStateRevision);
|
|
1962
|
+
syncSelectionToProjection(state, options, selection, 'selection-command', state.editorStateRevision);
|
|
1963
|
+
}
|
|
1964
|
+
return true;
|
|
1965
|
+
}
|
|
1966
|
+
function consumeMarkerRelationPickSelectionCommand(state, options, command, renderUi) {
|
|
1967
|
+
const pick = state.markerRelationPick;
|
|
1968
|
+
if (!pick?.active)
|
|
1969
|
+
return false;
|
|
1970
|
+
const document = state.session?.getState().workingDocument ?? null;
|
|
1971
|
+
const graph = document ? options.documentAdapter.getMarkerGraph?.(document) ?? null : null;
|
|
1972
|
+
if (!document || !graph) {
|
|
1973
|
+
updateMarkerRelationPickWarning(state, '当前文档没有 marker graph。');
|
|
1974
|
+
if (renderUi)
|
|
1975
|
+
renderUi();
|
|
1976
|
+
return true;
|
|
1977
|
+
}
|
|
1978
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
1979
|
+
const targetId = readMarkerRelationPickTargetId(command);
|
|
1980
|
+
if (!targetId) {
|
|
1981
|
+
updateMarkerRelationPickWarning(state, '没有拾取到有效端点,请点击标记或场景对象。');
|
|
1982
|
+
if (renderUi)
|
|
1983
|
+
renderUi();
|
|
1984
|
+
return true;
|
|
1985
|
+
}
|
|
1986
|
+
const endpoint = resolveMarkerRelationPickEndpoint(graph, hierarchy, targetId);
|
|
1987
|
+
if (!endpoint) {
|
|
1988
|
+
updateMarkerRelationPickWarning(state, `暂不支持的关系端点:${targetId}`);
|
|
1989
|
+
if (renderUi)
|
|
1990
|
+
renderUi();
|
|
1991
|
+
return true;
|
|
1992
|
+
}
|
|
1993
|
+
if (!pick.from) {
|
|
1994
|
+
const status = `关系拾取中:${formatMarkerRelationPickEndpointLabel(endpoint, graph, hierarchy)} 已作为起点,请点击终点。`;
|
|
1995
|
+
state.markerRelationPick = {
|
|
1996
|
+
...pick,
|
|
1997
|
+
from: endpoint,
|
|
1998
|
+
status,
|
|
1999
|
+
statusTone: 'success',
|
|
2000
|
+
};
|
|
2001
|
+
state.status = status;
|
|
2002
|
+
state.statusTone = 'success';
|
|
2003
|
+
state.statusToneStatus = state.status;
|
|
2004
|
+
state.statusDetails = '关系拾取会消费下一次有效视口点击,不改变当前选择。';
|
|
2005
|
+
if (renderUi)
|
|
2006
|
+
renderUi();
|
|
2007
|
+
return true;
|
|
2008
|
+
}
|
|
2009
|
+
const handled = patchMarkerRelation(state, options, {
|
|
2010
|
+
action: 'create',
|
|
2011
|
+
type: pick.type ?? '',
|
|
2012
|
+
fromKind: pick.from.kind,
|
|
2013
|
+
fromId: pick.from.id,
|
|
2014
|
+
toKind: endpoint.kind,
|
|
2015
|
+
toId: endpoint.id,
|
|
2016
|
+
directed: pick.directed,
|
|
2017
|
+
});
|
|
2018
|
+
if (handled && state.markerRelationPick) {
|
|
2019
|
+
state.markerRelationPick = {
|
|
2020
|
+
...state.markerRelationPick,
|
|
2021
|
+
status: state.status,
|
|
2022
|
+
statusTone: state.statusTone,
|
|
2023
|
+
};
|
|
1509
2024
|
}
|
|
2025
|
+
if (renderUi)
|
|
2026
|
+
renderUi();
|
|
1510
2027
|
return true;
|
|
1511
2028
|
}
|
|
2029
|
+
function readMarkerRelationPickTargetId(command) {
|
|
2030
|
+
if (command.type === 'selection.clear' || command.type === 'selection.remove')
|
|
2031
|
+
return null;
|
|
2032
|
+
return command.activeId?.trim() || command.selectedIds[command.selectedIds.length - 1]?.trim() || null;
|
|
2033
|
+
}
|
|
2034
|
+
function resolveMarkerRelationPickEndpoint(graph, hierarchy, targetId) {
|
|
2035
|
+
const markerId = readSpatialMarkerIdFromHierarchySelection(graph, targetId, hierarchy);
|
|
2036
|
+
if (markerId && findSpatialMarkerById(graph, markerId)) {
|
|
2037
|
+
return { kind: 'marker', id: markerId };
|
|
2038
|
+
}
|
|
2039
|
+
const hierarchyItem = hierarchy.find(item => item.id === targetId) ?? null;
|
|
2040
|
+
if (!hierarchyItem)
|
|
2041
|
+
return null;
|
|
2042
|
+
if (hierarchyItem.role === 'marker' || hierarchyItem.role === 'group' || hierarchyItem.role === 'root')
|
|
2043
|
+
return null;
|
|
2044
|
+
return { kind: 'scene-object', id: targetId };
|
|
2045
|
+
}
|
|
2046
|
+
function updateMarkerRelationPickWarning(state, status) {
|
|
2047
|
+
if (state.markerRelationPick) {
|
|
2048
|
+
state.markerRelationPick = {
|
|
2049
|
+
...state.markerRelationPick,
|
|
2050
|
+
status,
|
|
2051
|
+
statusTone: 'warning',
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
state.status = status;
|
|
2055
|
+
state.statusTone = 'warning';
|
|
2056
|
+
state.statusToneStatus = state.status;
|
|
2057
|
+
state.statusDetails = status;
|
|
2058
|
+
}
|
|
1512
2059
|
function renameSceneGraphNode(state, options, intent) {
|
|
1513
2060
|
const document = state.session?.getState().workingDocument;
|
|
1514
2061
|
if (state.mode !== 'editor' || !state.session || !document)
|
|
@@ -1524,7 +2071,10 @@ function renameSceneGraphNode(state, options, intent) {
|
|
|
1524
2071
|
state.status = `Rename rejected: ${intent.id}`;
|
|
1525
2072
|
return true;
|
|
1526
2073
|
}
|
|
1527
|
-
const
|
|
2074
|
+
const session = state.session;
|
|
2075
|
+
if (!session)
|
|
2076
|
+
return false;
|
|
2077
|
+
const result = session.dispatch({
|
|
1528
2078
|
type: 'document.patch',
|
|
1529
2079
|
label: patch.label ?? `Rename ${intent.id}`,
|
|
1530
2080
|
patch: patch.patch,
|
|
@@ -1536,7 +2086,7 @@ function renameSceneGraphNode(state, options, intent) {
|
|
|
1536
2086
|
return true;
|
|
1537
2087
|
}
|
|
1538
2088
|
rebuildProjectionFromDocument(state, options, result.workingDocument, result.selection);
|
|
1539
|
-
state.summary = summarizeDocument(options, result.workingDocument,
|
|
2089
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
1540
2090
|
state.status = patch.label ?? `Renamed ${intent.id}`;
|
|
1541
2091
|
return true;
|
|
1542
2092
|
}
|
|
@@ -1550,7 +2100,10 @@ function createSceneGraphGroup(state, options, intent) {
|
|
|
1550
2100
|
state.status = 'Create empty rejected';
|
|
1551
2101
|
return true;
|
|
1552
2102
|
}
|
|
1553
|
-
const
|
|
2103
|
+
const session = state.session;
|
|
2104
|
+
if (!session)
|
|
2105
|
+
return false;
|
|
2106
|
+
const result = session.dispatch({
|
|
1554
2107
|
type: 'document.patch',
|
|
1555
2108
|
label: patch.label ?? 'Create Empty',
|
|
1556
2109
|
patch: patch.patch,
|
|
@@ -1572,7 +2125,7 @@ function createSceneGraphGroup(state, options, intent) {
|
|
|
1572
2125
|
}).selection;
|
|
1573
2126
|
}
|
|
1574
2127
|
rebuildProjectionFromDocument(state, options, result.workingDocument, selection);
|
|
1575
|
-
state.summary = summarizeDocument(options, result.workingDocument,
|
|
2128
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
1576
2129
|
state.status = patch.label ?? (createdId ? `Created empty ${createdId}` : 'Created empty');
|
|
1577
2130
|
return true;
|
|
1578
2131
|
}
|
|
@@ -1615,6 +2168,182 @@ function createSceneGraphPrimitive(state, options, intent) {
|
|
|
1615
2168
|
state.status = patch.label ?? (createdId ? `Created ${intent.shape} ${createdId}` : `Created ${intent.shape}`);
|
|
1616
2169
|
return true;
|
|
1617
2170
|
}
|
|
2171
|
+
function createSceneGraphMarker(state, options, intent) {
|
|
2172
|
+
const document = state.session?.getState().workingDocument;
|
|
2173
|
+
if (state.mode !== 'editor' || !state.session || !document)
|
|
2174
|
+
return false;
|
|
2175
|
+
cancelActiveOperation(state);
|
|
2176
|
+
const markerType = intent.markerType?.trim() ?? '';
|
|
2177
|
+
const markerTypes = options.documentAdapter.getMarkerTypeCatalog?.(document) ?? [];
|
|
2178
|
+
const markerTypeDefinition = markerType
|
|
2179
|
+
? markerTypes.find(definition => definition.type === markerType) ?? null
|
|
2180
|
+
: null;
|
|
2181
|
+
if (markerType && !markerTypeDefinition) {
|
|
2182
|
+
state.status = `Create marker rejected: unknown marker type ${markerType}`;
|
|
2183
|
+
state.statusTone = 'warning';
|
|
2184
|
+
state.statusToneStatus = state.status;
|
|
2185
|
+
return true;
|
|
2186
|
+
}
|
|
2187
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
2188
|
+
const parentId = resolveCreateMarkerParentId(hierarchy, intent.parentId ?? null);
|
|
2189
|
+
const marker = createSceneGraphMarkerNode(state, options, document, intent, markerTypeDefinition);
|
|
2190
|
+
state.markerCreateReservations.ids.add(marker.id);
|
|
2191
|
+
state.markerCreateReservations.labels.add(marker.label);
|
|
2192
|
+
const patch = options.documentAdapter.createMarkerGraphPatch?.(document, {
|
|
2193
|
+
type: 'marker.create-box',
|
|
2194
|
+
marker,
|
|
2195
|
+
parentId,
|
|
2196
|
+
});
|
|
2197
|
+
if (!patch) {
|
|
2198
|
+
state.markerCreateReservations.ids.delete(marker.id);
|
|
2199
|
+
state.markerCreateReservations.labels.delete(marker.label);
|
|
2200
|
+
state.status = `Create marker rejected: ${marker.label}`;
|
|
2201
|
+
state.statusTone = 'warning';
|
|
2202
|
+
state.statusToneStatus = state.status;
|
|
2203
|
+
return true;
|
|
2204
|
+
}
|
|
2205
|
+
const result = state.session.dispatch({
|
|
2206
|
+
type: 'document.patch',
|
|
2207
|
+
label: patch.label ?? `Create marker ${marker.label}`,
|
|
2208
|
+
patch: patch.patch,
|
|
2209
|
+
targetId: patch.createdId ?? patch.changedId ?? marker.id,
|
|
2210
|
+
...withProjectionImpact(resolveProjectionImpact(patch, createKnownCreatedReprojectProjectionImpact({
|
|
2211
|
+
createdNodeIds: [patch.createdId ?? patch.changedId ?? marker.id],
|
|
2212
|
+
reprojectIds: patch.changedIds,
|
|
2213
|
+
}))),
|
|
2214
|
+
});
|
|
2215
|
+
if (!result.documentChanged) {
|
|
2216
|
+
state.markerCreateReservations.ids.delete(marker.id);
|
|
2217
|
+
state.markerCreateReservations.labels.delete(marker.label);
|
|
2218
|
+
state.status = `Create marker unchanged: ${marker.label}`;
|
|
2219
|
+
state.statusTone = 'warning';
|
|
2220
|
+
state.statusToneStatus = state.status;
|
|
2221
|
+
return true;
|
|
2222
|
+
}
|
|
2223
|
+
const createdId = patch.createdId ?? patch.changedId ?? marker.id;
|
|
2224
|
+
releaseReflectedMarkerCreateReservation(state, options, result.workingDocument, marker, createdId);
|
|
2225
|
+
let selection = result.selection;
|
|
2226
|
+
if (createdId && isNodeSelectableInDocument(options, result.workingDocument, createdId)) {
|
|
2227
|
+
selection = state.session.dispatch({
|
|
2228
|
+
type: 'selection.replace',
|
|
2229
|
+
selectedIds: [createdId],
|
|
2230
|
+
activeId: createdId,
|
|
2231
|
+
label: 'Select Created Marker',
|
|
2232
|
+
}).selection;
|
|
2233
|
+
}
|
|
2234
|
+
rebuildProjectionFromDocument(state, options, result.workingDocument, selection);
|
|
2235
|
+
state.summary = summarizeDocument(options, result.workingDocument, state.session.getSource());
|
|
2236
|
+
state.status = patch.label ?? `Created marker ${marker.label}`;
|
|
2237
|
+
state.statusTone = 'success';
|
|
2238
|
+
state.statusToneStatus = state.status;
|
|
2239
|
+
state.statusDetails = '';
|
|
2240
|
+
return true;
|
|
2241
|
+
}
|
|
2242
|
+
function releaseReflectedMarkerCreateReservation(state, options, document, marker, createdId) {
|
|
2243
|
+
const reflectedIds = new Set([
|
|
2244
|
+
marker.id,
|
|
2245
|
+
...(createdId ? [createdId] : []),
|
|
2246
|
+
]);
|
|
2247
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
2248
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
2249
|
+
const markerReflected = hierarchy.some(item => reflectedIds.has(item.id))
|
|
2250
|
+
|| (graph?.markers ?? []).some(candidate => reflectedIds.has(candidate.id));
|
|
2251
|
+
if (!markerReflected)
|
|
2252
|
+
return;
|
|
2253
|
+
state.markerCreateReservations.ids.delete(marker.id);
|
|
2254
|
+
state.markerCreateReservations.labels.delete(marker.label);
|
|
2255
|
+
}
|
|
2256
|
+
function createSceneGraphMarkerNode(state, options, document, intent, markerTypeDefinition) {
|
|
2257
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
2258
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
2259
|
+
const existingIds = new Set([
|
|
2260
|
+
...hierarchy.map(item => item.id),
|
|
2261
|
+
...(graph?.markers ?? []).map(marker => marker.id),
|
|
2262
|
+
...state.markerCreateReservations.ids,
|
|
2263
|
+
]);
|
|
2264
|
+
const markerType = markerTypeDefinition?.type ?? intent.markerType?.trim() ?? '';
|
|
2265
|
+
const baseLabel = intent.name?.trim() || markerTypeDefinition?.label || 'Marker';
|
|
2266
|
+
const id = createUniqueMarkerId(existingIds, markerType || baseLabel);
|
|
2267
|
+
const label = createUniqueMarkerLabel(new Set([
|
|
2268
|
+
...hierarchy.map(item => item.label),
|
|
2269
|
+
...state.markerCreateReservations.labels,
|
|
2270
|
+
]), baseLabel, id, markerType);
|
|
2271
|
+
const geometry = createInitialMarkerGeometry(state, markerTypeDefinition?.kind);
|
|
2272
|
+
return {
|
|
2273
|
+
id,
|
|
2274
|
+
kind: normalizeMarkerNodeKind(markerTypeDefinition?.kind),
|
|
2275
|
+
markerType,
|
|
2276
|
+
label,
|
|
2277
|
+
geometry,
|
|
2278
|
+
...(markerTypeDefinition?.defaultTags?.length ? { tags: [...markerTypeDefinition.defaultTags] } : {}),
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
function createInitialMarkerGeometry(state, markerKind) {
|
|
2282
|
+
const defaultScale = createDefaultMarkerScale(markerKind);
|
|
2283
|
+
const selection = state.session?.getState().selection ?? { selectedIds: [], activeId: null };
|
|
2284
|
+
const bounds = selection.selectedIds.length > 0
|
|
2285
|
+
? state.projection?.getSelectionBounds(selection.selectedIds) ?? null
|
|
2286
|
+
: null;
|
|
2287
|
+
const center = bounds?.center ?? { x: 0, y: defaultScale.y / 2, z: 0 };
|
|
2288
|
+
if (!isRegionMarkerKind(markerKind)) {
|
|
2289
|
+
return {
|
|
2290
|
+
kind: 'point',
|
|
2291
|
+
coordinateSpace: 'world',
|
|
2292
|
+
position: { ...center },
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
const size = bounds && isRegionMarkerKind(markerKind)
|
|
2296
|
+
? normalizeMarkerBoxSize(bounds.size)
|
|
2297
|
+
: defaultScale;
|
|
2298
|
+
return {
|
|
2299
|
+
kind: 'box',
|
|
2300
|
+
coordinateSpace: 'world',
|
|
2301
|
+
center: { ...center },
|
|
2302
|
+
size: { ...size },
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
function createDefaultMarkerScale(markerKind) {
|
|
2306
|
+
return isRegionMarkerKind(markerKind)
|
|
2307
|
+
? { x: 4, y: 1, z: 4 }
|
|
2308
|
+
: { x: 0.5, y: 0.5, z: 0.5 };
|
|
2309
|
+
}
|
|
2310
|
+
function normalizeMarkerNodeKind(kind) {
|
|
2311
|
+
return kind?.trim() || 'point';
|
|
2312
|
+
}
|
|
2313
|
+
function isRegionMarkerKind(kind) {
|
|
2314
|
+
return (kind?.trim() || 'point') === 'region';
|
|
2315
|
+
}
|
|
2316
|
+
function createUniqueMarkerId(existingIds, markerType) {
|
|
2317
|
+
const base = sanitizeMarkerIdPart(markerType) || 'marker';
|
|
2318
|
+
if (!existingIds.has(base))
|
|
2319
|
+
return base;
|
|
2320
|
+
let index = 2;
|
|
2321
|
+
while (existingIds.has(`${base}-${index}`))
|
|
2322
|
+
index += 1;
|
|
2323
|
+
return `${base}-${index}`;
|
|
2324
|
+
}
|
|
2325
|
+
function createUniqueMarkerLabel(existingLabels, baseLabel, id, markerType) {
|
|
2326
|
+
const trimmed = baseLabel.trim() || markerType || id;
|
|
2327
|
+
if (!existingLabels.has(trimmed))
|
|
2328
|
+
return trimmed;
|
|
2329
|
+
let index = 2;
|
|
2330
|
+
while (existingLabels.has(`${trimmed} ${index}`))
|
|
2331
|
+
index += 1;
|
|
2332
|
+
return `${trimmed} ${index}`;
|
|
2333
|
+
}
|
|
2334
|
+
function sanitizeMarkerIdPart(value) {
|
|
2335
|
+
return value
|
|
2336
|
+
.trim()
|
|
2337
|
+
.toLowerCase()
|
|
2338
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
2339
|
+
.replace(/^-+|-+$/g, '');
|
|
2340
|
+
}
|
|
2341
|
+
function resolveCreateMarkerParentId(hierarchy, parentId) {
|
|
2342
|
+
if (!parentId)
|
|
2343
|
+
return null;
|
|
2344
|
+
const parent = hierarchy.find(item => item.id === parentId) ?? null;
|
|
2345
|
+
return parent?.canHaveChildren === true && parent.role !== 'marker' ? parent.id : null;
|
|
2346
|
+
}
|
|
1618
2347
|
function deleteSceneGraphNodes(state, options, intent) {
|
|
1619
2348
|
const document = state.session?.getState().workingDocument;
|
|
1620
2349
|
if (state.mode !== 'editor' || !state.session || !document)
|
|
@@ -1866,7 +2595,12 @@ function groupSceneGraphSelection(state, options, intent) {
|
|
|
1866
2595
|
return true;
|
|
1867
2596
|
}
|
|
1868
2597
|
function sanitizeSelection(state, options, document, selection) {
|
|
1869
|
-
const
|
|
2598
|
+
const documentHierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
2599
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
2600
|
+
const hierarchy = graph
|
|
2601
|
+
? createMarkerGraphHierarchyItems(documentHierarchy, graph, createMarkerGraphHierarchyVisibility(state))
|
|
2602
|
+
: documentHierarchy;
|
|
2603
|
+
const selectedIds = selection.selectedIds.filter(id => isAgentBridgeObjectSelectable(options, document, id, hierarchy));
|
|
1870
2604
|
const activeId = selection.activeId && selectedIds.includes(selection.activeId)
|
|
1871
2605
|
? selection.activeId
|
|
1872
2606
|
: selectedIds[selectedIds.length - 1] ?? null;
|
|
@@ -1880,7 +2614,7 @@ function sanitizeSelection(state, options, document, selection) {
|
|
|
1880
2614
|
});
|
|
1881
2615
|
return result?.selection ?? { selectedIds, activeId };
|
|
1882
2616
|
}
|
|
1883
|
-
function commitEditorStateChange(state, renderUi, reason, mutate, options = {}) {
|
|
2617
|
+
function commitEditorStateChange(state, harnessOptions, renderUi, reason, mutate, options = {}) {
|
|
1884
2618
|
const beforeRevision = state.editorStateRevision;
|
|
1885
2619
|
mutate();
|
|
1886
2620
|
const revision = beforeRevision + 1;
|
|
@@ -1890,7 +2624,7 @@ function commitEditorStateChange(state, renderUi, reason, mutate, options = {})
|
|
|
1890
2624
|
const selection = typeof options.syncSelectionArtifacts === 'boolean'
|
|
1891
2625
|
? state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null }
|
|
1892
2626
|
: options.syncSelectionArtifacts;
|
|
1893
|
-
syncSelectionToProjection(state, selection, reason, revision);
|
|
2627
|
+
syncSelectionToProjection(state, harnessOptions, selection, reason, revision);
|
|
1894
2628
|
}
|
|
1895
2629
|
else if (options.syncTransformOperationArtifacts) {
|
|
1896
2630
|
syncTransformOperationSettingsToSceneArtifacts(state, reason, revision);
|
|
@@ -1900,15 +2634,288 @@ function commitEditorStateChange(state, renderUi, reason, mutate, options = {})
|
|
|
1900
2634
|
}
|
|
1901
2635
|
return revision;
|
|
1902
2636
|
}
|
|
1903
|
-
function syncSelectionToProjection(state, selection, reason = 'projection-selection', revision = state.editorStateRevision) {
|
|
2637
|
+
function syncSelectionToProjection(state, options, selection, reason = 'projection-selection', revision = state.editorStateRevision) {
|
|
1904
2638
|
if (!beginSceneArtifactSync(state, reason, revision))
|
|
1905
2639
|
return;
|
|
1906
|
-
state.
|
|
1907
|
-
state.
|
|
2640
|
+
const projectedSelection = state.prefabStage ? EMPTY_EDITOR_SELECTION : selection;
|
|
2641
|
+
state.projection?.syncSelection(projectedSelection);
|
|
2642
|
+
syncMarkerOverlayToSceneArtifacts(state, options, projectedSelection);
|
|
2643
|
+
state.gizmo?.setSelection(projectedSelection);
|
|
1908
2644
|
syncTransformGizmoToSceneArtifacts(state, reason, revision, false);
|
|
1909
2645
|
}
|
|
1910
|
-
function syncCurrentSelectionToSceneArtifacts(state, reason = 'projection-selection-current', revision = state.editorStateRevision) {
|
|
1911
|
-
syncSelectionToProjection(state, state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null }, reason, revision);
|
|
2646
|
+
function syncCurrentSelectionToSceneArtifacts(state, options, reason = 'projection-selection-current', revision = state.editorStateRevision) {
|
|
2647
|
+
syncSelectionToProjection(state, options, state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null }, reason, revision);
|
|
2648
|
+
}
|
|
2649
|
+
function syncMarkerOverlayToSceneArtifacts(state, options, selection) {
|
|
2650
|
+
const overlay = state.markerOverlay;
|
|
2651
|
+
if (!overlay)
|
|
2652
|
+
return;
|
|
2653
|
+
const document = state.session?.getState().workingDocument ?? null;
|
|
2654
|
+
const input = document
|
|
2655
|
+
? createMarkerOverlayInput(state, options, document, selection, createMarkerGraphHierarchyVisibility(state))
|
|
2656
|
+
: { markers: [] };
|
|
2657
|
+
const changed = overlay.sync(input);
|
|
2658
|
+
syncMarkerRelationHighlightRenderLoop(state, input);
|
|
2659
|
+
if (changed)
|
|
2660
|
+
requestEditorSceneFrame(state, 'marker-overlay-sync');
|
|
2661
|
+
}
|
|
2662
|
+
function syncMarkerRelationHighlightRenderLoop(state, input) {
|
|
2663
|
+
const shouldRun = (input.relations ?? []).some(relation => relation.active === true);
|
|
2664
|
+
if (shouldRun === state.markerRelationHighlightContinuous)
|
|
2665
|
+
return;
|
|
2666
|
+
state.markerRelationHighlightContinuous = shouldRun;
|
|
2667
|
+
if (shouldRun) {
|
|
2668
|
+
if (canUseContinuousViewportRenderLoop()) {
|
|
2669
|
+
state.viewportRenderCoordinator?.beginContinuous(MARKER_RELATION_HIGHLIGHT_RENDER_REASON);
|
|
2670
|
+
}
|
|
2671
|
+
else {
|
|
2672
|
+
state.viewportRenderCoordinator?.requestFrame(MARKER_RELATION_HIGHLIGHT_RENDER_REASON);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
else {
|
|
2676
|
+
state.viewportRenderCoordinator?.endContinuous(MARKER_RELATION_HIGHLIGHT_RENDER_REASON);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
function canUseContinuousViewportRenderLoop() {
|
|
2680
|
+
if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function')
|
|
2681
|
+
return true;
|
|
2682
|
+
if (typeof window.cancelAnimationFrame !== 'function')
|
|
2683
|
+
return true;
|
|
2684
|
+
let completedSynchronously = false;
|
|
2685
|
+
const frameId = window.requestAnimationFrame(() => {
|
|
2686
|
+
completedSynchronously = true;
|
|
2687
|
+
});
|
|
2688
|
+
window.cancelAnimationFrame(frameId);
|
|
2689
|
+
return !completedSynchronously;
|
|
2690
|
+
}
|
|
2691
|
+
function createMarkerOverlayInput(state, options, document, selection, visibility) {
|
|
2692
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
2693
|
+
if (!graph)
|
|
2694
|
+
return { markers: [] };
|
|
2695
|
+
if (state.viewportTools.markersVisible === false)
|
|
2696
|
+
return { markers: [], relations: [] };
|
|
2697
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
2698
|
+
const fullHierarchy = createMarkerGraphHierarchyItems(hierarchy, graph, visibility);
|
|
2699
|
+
const selectedIds = new Set(selection.selectedIds);
|
|
2700
|
+
const markerTypeLabels = new Map((options.documentAdapter.getMarkerTypeCatalog?.(document) ?? []).map(definition => [definition.type, definition.label]));
|
|
2701
|
+
const activeMarkerId = selection.activeId
|
|
2702
|
+
? readSpatialMarkerIdFromHierarchySelection(graph, selection.activeId, hierarchy)
|
|
2703
|
+
: null;
|
|
2704
|
+
return {
|
|
2705
|
+
activeMarkerRowId: selection.activeId,
|
|
2706
|
+
selectedMarkerRowIds: selection.selectedIds,
|
|
2707
|
+
markers: fullHierarchy
|
|
2708
|
+
.filter(item => item.role === 'marker')
|
|
2709
|
+
.map((item) => {
|
|
2710
|
+
const markerId = readSpatialMarkerIdFromHierarchySelection(graph, item.id, hierarchy);
|
|
2711
|
+
const marker = markerId ? findSpatialMarkerById(graph, markerId) : null;
|
|
2712
|
+
if (!marker || !isMarkerOverlayRowVisible(graph, item, marker.id, hierarchy, visibility))
|
|
2713
|
+
return null;
|
|
2714
|
+
const overlayMarker = resolveMarkerForOverlay(state, applyMarkerOverlayTransformPreview(state, item.id, marker));
|
|
2715
|
+
return {
|
|
2716
|
+
markerRowId: item.id,
|
|
2717
|
+
marker: overlayMarker,
|
|
2718
|
+
markerTypeLabel: markerTypeLabels.get(marker.markerType),
|
|
2719
|
+
selected: selectedIds.has(item.id),
|
|
2720
|
+
active: selection.activeId === item.id,
|
|
2721
|
+
};
|
|
2722
|
+
})
|
|
2723
|
+
.filter((entry) => !!entry),
|
|
2724
|
+
relations: createSelectedMarkerRelationOverlayEntries(state, resolveMarkerGraphForOverlay(state, graph), activeMarkerId, hierarchy, visibility),
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
function resolveMarkerGraphForOverlay(state, graph) {
|
|
2728
|
+
return {
|
|
2729
|
+
...graph,
|
|
2730
|
+
markers: graph.markers.map(marker => resolveMarkerForOverlay(state, marker)),
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
function resolveMarkerForOverlay(state, marker) {
|
|
2734
|
+
if (!isObjectBoundMarkerForOverlay(marker))
|
|
2735
|
+
return marker;
|
|
2736
|
+
const target = readSceneObjectMarkerTargetForOverlay(marker);
|
|
2737
|
+
if (!target)
|
|
2738
|
+
return marker;
|
|
2739
|
+
const bounds = state.projection?.getSelectionBounds([target.id]) ?? null;
|
|
2740
|
+
if (!bounds)
|
|
2741
|
+
return marker;
|
|
2742
|
+
return {
|
|
2743
|
+
...marker,
|
|
2744
|
+
spatial: {
|
|
2745
|
+
status: 'resolved',
|
|
2746
|
+
coordinateSpace: 'world',
|
|
2747
|
+
origin: { ...bounds.center },
|
|
2748
|
+
bounds: {
|
|
2749
|
+
min: { ...bounds.min },
|
|
2750
|
+
max: { ...bounds.max },
|
|
2751
|
+
center: { ...bounds.center },
|
|
2752
|
+
size: { ...bounds.size },
|
|
2753
|
+
},
|
|
2754
|
+
dimensions: { ...bounds.size },
|
|
2755
|
+
localFrame: {
|
|
2756
|
+
origin: { ...bounds.center },
|
|
2757
|
+
forward: marker.semanticFrame?.forward ? { ...marker.semanticFrame.forward } : { x: 0, y: 0, z: 1 },
|
|
2758
|
+
right: marker.semanticFrame?.right ? { ...marker.semanticFrame.right } : { x: 1, y: 0, z: 0 },
|
|
2759
|
+
up: marker.semanticFrame?.up ? { ...marker.semanticFrame.up } : { x: 0, y: 1, z: 0 },
|
|
2760
|
+
},
|
|
2761
|
+
target,
|
|
2762
|
+
},
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
function isObjectBoundMarkerForOverlay(marker) {
|
|
2766
|
+
const markerKind = marker.kind?.trim().toLowerCase();
|
|
2767
|
+
return markerKind === 'object'
|
|
2768
|
+
|| markerKind === 'object-bound'
|
|
2769
|
+
|| markerKind === 'object-bounds'
|
|
2770
|
+
|| marker.geometry.kind === 'object-bounds';
|
|
2771
|
+
}
|
|
2772
|
+
function readSceneObjectMarkerTargetForOverlay(marker) {
|
|
2773
|
+
if (marker.target?.kind === 'scene-object')
|
|
2774
|
+
return marker.target;
|
|
2775
|
+
if (marker.geometry.kind === 'object-bounds' && marker.geometry.target.kind === 'scene-object') {
|
|
2776
|
+
return marker.geometry.target;
|
|
2777
|
+
}
|
|
2778
|
+
if (marker.geometry.kind === 'point' && marker.geometry.target?.kind === 'scene-object') {
|
|
2779
|
+
return marker.geometry.target;
|
|
2780
|
+
}
|
|
2781
|
+
return null;
|
|
2782
|
+
}
|
|
2783
|
+
function createSelectedMarkerRelationOverlayEntries(state, graph, activeMarkerId, hierarchy, visibility) {
|
|
2784
|
+
if (!activeMarkerId)
|
|
2785
|
+
return [];
|
|
2786
|
+
if (!findSpatialMarkerById(graph, activeMarkerId))
|
|
2787
|
+
return [];
|
|
2788
|
+
const entries = [];
|
|
2789
|
+
for (const relation of getSpatialMarkerDirectRelations(graph, activeMarkerId)) {
|
|
2790
|
+
const from = resolveRelationOverlayEndpoint(state, graph, activeMarkerId, relation.from, hierarchy, visibility);
|
|
2791
|
+
const to = resolveRelationOverlayEndpoint(state, graph, activeMarkerId, relation.to, hierarchy, visibility);
|
|
2792
|
+
if (!from || !to)
|
|
2793
|
+
continue;
|
|
2794
|
+
entries.push({
|
|
2795
|
+
id: relation.id,
|
|
2796
|
+
type: relation.type,
|
|
2797
|
+
...(relation.label ? { label: relation.label } : {}),
|
|
2798
|
+
from,
|
|
2799
|
+
to,
|
|
2800
|
+
directed: relation.directed ?? true,
|
|
2801
|
+
active: state.activeMarkerRelationId === relation.id,
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
return entries;
|
|
2805
|
+
}
|
|
2806
|
+
function applyMarkerOverlayTransformPreview(state, markerRowId, marker) {
|
|
2807
|
+
const transform = readActiveTransformPreviewTransform(state, markerRowId)
|
|
2808
|
+
?? (markerRowId === marker.id ? null : readActiveTransformPreviewTransform(state, marker.id));
|
|
2809
|
+
if (!transform)
|
|
2810
|
+
return marker;
|
|
2811
|
+
const semanticFrame = createMarkerSemanticFrameFromTransform(marker, transform);
|
|
2812
|
+
if (marker.geometry.kind === 'point') {
|
|
2813
|
+
return {
|
|
2814
|
+
...marker,
|
|
2815
|
+
geometry: {
|
|
2816
|
+
...marker.geometry,
|
|
2817
|
+
coordinateSpace: 'world',
|
|
2818
|
+
position: { ...transform.position },
|
|
2819
|
+
},
|
|
2820
|
+
semanticFrame,
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
if (marker.geometry.kind !== 'box') {
|
|
2824
|
+
return {
|
|
2825
|
+
...marker,
|
|
2826
|
+
semanticFrame,
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
return {
|
|
2830
|
+
...marker,
|
|
2831
|
+
semanticFrame,
|
|
2832
|
+
geometry: {
|
|
2833
|
+
...marker.geometry,
|
|
2834
|
+
center: { ...transform.position },
|
|
2835
|
+
rotation: { ...transform.rotation },
|
|
2836
|
+
size: { ...transform.scale },
|
|
2837
|
+
},
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2840
|
+
function resolveRelationOverlayEndpoint(state, graph, activeMarkerId, endpoint, hierarchy, visibility) {
|
|
2841
|
+
if (endpoint.kind === 'marker') {
|
|
2842
|
+
if (!isMarkerVisibleForOverlayRelation(graph, endpoint.id, hierarchy, visibility))
|
|
2843
|
+
return null;
|
|
2844
|
+
const preview = endpoint.id === activeMarkerId ? readActiveTransformPreviewPosition(state) : null;
|
|
2845
|
+
if (preview)
|
|
2846
|
+
return preview;
|
|
2847
|
+
const marker = findSpatialMarkerById(graph, endpoint.id);
|
|
2848
|
+
return marker ? resolveMarkerOverlayEndpoint(marker) : null;
|
|
2849
|
+
}
|
|
2850
|
+
if (endpoint.kind === 'scene-object') {
|
|
2851
|
+
const preview = endpoint.id === state.activeTransformPreview?.activeId ? readActiveTransformPreviewPosition(state) : null;
|
|
2852
|
+
if (preview)
|
|
2853
|
+
return preview;
|
|
2854
|
+
const bounds = state.projection?.getSelectionBounds([endpoint.id]) ?? null;
|
|
2855
|
+
return bounds ? { ...bounds.center } : null;
|
|
2856
|
+
}
|
|
2857
|
+
return null;
|
|
2858
|
+
}
|
|
2859
|
+
function isMarkerVisibleForOverlayRelation(graph, markerId, hierarchy, visibility) {
|
|
2860
|
+
if (isSpatialMarkerBackedByHierarchyRow(graph, markerId, hierarchy)) {
|
|
2861
|
+
const markerRow = hierarchy.find(item => item.id === markerId);
|
|
2862
|
+
return markerRow?.enabled !== false && !isMarkerHiddenInHierarchyVisibility(markerId, visibility);
|
|
2863
|
+
}
|
|
2864
|
+
const markerRow = hierarchy.find(item => readMarkerGraphHierarchyMarkerIdForGraph(graph, item.id, hierarchy) === markerId);
|
|
2865
|
+
if (markerRow?.enabled === false)
|
|
2866
|
+
return false;
|
|
2867
|
+
return isSpatialMarkerHierarchyVisible(markerId, visibility);
|
|
2868
|
+
}
|
|
2869
|
+
function isMarkerHiddenInHierarchyVisibility(markerId, visibility) {
|
|
2870
|
+
const hiddenMarkerIds = visibility.hiddenMarkerIds;
|
|
2871
|
+
if (!hiddenMarkerIds)
|
|
2872
|
+
return false;
|
|
2873
|
+
return Array.isArray(hiddenMarkerIds)
|
|
2874
|
+
? hiddenMarkerIds.includes(markerId)
|
|
2875
|
+
: hiddenMarkerIds.has(markerId);
|
|
2876
|
+
}
|
|
2877
|
+
function readActiveTransformPreviewPosition(state) {
|
|
2878
|
+
const transform = readActiveTransformPreviewTransform(state);
|
|
2879
|
+
return transform ? { ...transform.position } : null;
|
|
2880
|
+
}
|
|
2881
|
+
function readActiveTransformPreviewTransform(state, targetId) {
|
|
2882
|
+
const preview = state.activeTransformPreview;
|
|
2883
|
+
const activeId = targetId ?? preview?.activeId ?? null;
|
|
2884
|
+
if (!preview || !activeId)
|
|
2885
|
+
return null;
|
|
2886
|
+
const transform = preview.transforms[activeId] ?? null;
|
|
2887
|
+
return transform && isEditorTransformTrsSnapshot(transform) ? transform : null;
|
|
2888
|
+
}
|
|
2889
|
+
function resolveMarkerOverlayEndpoint(marker) {
|
|
2890
|
+
if (isObjectBoundMarkerForOverlay(marker) && marker.spatial?.bounds?.center) {
|
|
2891
|
+
return { ...marker.spatial.bounds.center };
|
|
2892
|
+
}
|
|
2893
|
+
if (marker.geometry.kind === 'box')
|
|
2894
|
+
return { ...marker.geometry.center };
|
|
2895
|
+
if (marker.geometry.kind === 'point')
|
|
2896
|
+
return { ...marker.geometry.position };
|
|
2897
|
+
return null;
|
|
2898
|
+
}
|
|
2899
|
+
function isMarkerOverlayRowVisible(graph, item, markerId, hierarchy, visibility) {
|
|
2900
|
+
if (item.enabled === false)
|
|
2901
|
+
return false;
|
|
2902
|
+
if (readMarkerGraphHierarchyMarkerIdForGraph(graph, item.id, hierarchy)) {
|
|
2903
|
+
return isSpatialMarkerHierarchyVisible(markerId, visibility);
|
|
2904
|
+
}
|
|
2905
|
+
return true;
|
|
2906
|
+
}
|
|
2907
|
+
function createMarkerGraphHierarchyVisibility(state) {
|
|
2908
|
+
return {
|
|
2909
|
+
rootVisible: state.markerGraphVisibility.rootVisible,
|
|
2910
|
+
hiddenMarkerIds: state.markerGraphVisibility.hiddenMarkerIds,
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
function createMarkerRelationVisibilityOptions(state) {
|
|
2914
|
+
return {
|
|
2915
|
+
markersVisible: state.viewportTools.markersVisible !== false,
|
|
2916
|
+
rootVisible: state.markerGraphVisibility.rootVisible,
|
|
2917
|
+
hiddenMarkerIds: state.markerGraphVisibility.hiddenMarkerIds,
|
|
2918
|
+
};
|
|
1912
2919
|
}
|
|
1913
2920
|
function syncTransformGizmoToSceneArtifacts(state, reason, revision = state.editorStateRevision, beginSync = true) {
|
|
1914
2921
|
if (beginSync && !beginSceneArtifactSync(state, reason, revision))
|
|
@@ -1925,9 +2932,20 @@ function syncTransformGizmoToSceneArtifacts(state, reason, revision = state.edit
|
|
|
1925
2932
|
function syncTransformOperationSettingsToSceneArtifacts(state, reason, revision = state.editorStateRevision) {
|
|
1926
2933
|
if (!beginSceneArtifactSync(state, reason, revision))
|
|
1927
2934
|
return;
|
|
1928
|
-
state.gizmo?.setOperationSettings(state
|
|
2935
|
+
state.gizmo?.setOperationSettings(getScopedTransformOperationSettings(state));
|
|
1929
2936
|
requestEditorSceneFrame(state, reason);
|
|
1930
2937
|
}
|
|
2938
|
+
function getScopedTransformOperationSettings(state) {
|
|
2939
|
+
if (!state.prefabStage)
|
|
2940
|
+
return state.transformOperationSettings;
|
|
2941
|
+
return updateTransformOperationSettings(state.transformOperationSettings, {
|
|
2942
|
+
snap: {
|
|
2943
|
+
...state.transformOperationSettings.snap,
|
|
2944
|
+
enabled: false,
|
|
2945
|
+
},
|
|
2946
|
+
placementMode: 'off',
|
|
2947
|
+
});
|
|
2948
|
+
}
|
|
1931
2949
|
function beginSceneArtifactSync(state, reason, revision) {
|
|
1932
2950
|
if (revision < state.sceneArtifactRevision) {
|
|
1933
2951
|
return false;
|
|
@@ -1949,7 +2967,7 @@ function requestEditorArtifactRevealFrame(state, reason) {
|
|
|
1949
2967
|
coordinator.requestRevealFrame(`${reason}-artifact-reveal`);
|
|
1950
2968
|
}
|
|
1951
2969
|
function syncEditorWorldAppearanceFromDocument(state, options, document, reason) {
|
|
1952
|
-
const appearance =
|
|
2970
|
+
const appearance = resolveEffectiveLocalEditorWorldAppearance(state, options, document);
|
|
1953
2971
|
const key = serializeLocalEditorWorldAppearance(appearance);
|
|
1954
2972
|
if (key === state.worldAppearanceKey)
|
|
1955
2973
|
return;
|
|
@@ -1962,16 +2980,18 @@ function syncEditorWorldAppearanceFromDocument(state, options, document, reason)
|
|
|
1962
2980
|
requestEditorSceneFrame(state, reason);
|
|
1963
2981
|
}
|
|
1964
2982
|
function syncEditorWorldRenderingFromDocument(state, options, document, reason, refreshProjection = false) {
|
|
1965
|
-
const rendering =
|
|
2983
|
+
const rendering = resolveEffectiveLocalEditorWorldRendering(state, options, document);
|
|
1966
2984
|
const key = serializeLocalEditorWorldRendering(rendering);
|
|
1967
2985
|
if (key === state.worldRenderingKey) {
|
|
1968
2986
|
if (refreshProjection)
|
|
1969
2987
|
state.shadowPreview?.refresh();
|
|
2988
|
+
state.world?.refreshSkyBackdrop();
|
|
1970
2989
|
return;
|
|
1971
2990
|
}
|
|
1972
2991
|
state.worldRenderingKey = key;
|
|
1973
2992
|
state.shadowPreview?.setOptions(rendering.shadowPreview);
|
|
1974
2993
|
state.environmentTexture?.setProfile(rendering.environment);
|
|
2994
|
+
state.world?.refreshSkyBackdrop();
|
|
1975
2995
|
state.postProcess?.setProfile(rendering.postProcess);
|
|
1976
2996
|
requestEditorSceneFrame(state, reason);
|
|
1977
2997
|
}
|
|
@@ -1985,6 +3005,14 @@ function resolveLocalEditorWorldAppearance(options, document) {
|
|
|
1985
3005
|
grid: documentAppearance?.grid ?? options.world?.grid,
|
|
1986
3006
|
};
|
|
1987
3007
|
}
|
|
3008
|
+
function resolveEffectiveLocalEditorWorldAppearance(state, options, document) {
|
|
3009
|
+
if (!state.prefabStage)
|
|
3010
|
+
return resolveLocalEditorWorldAppearance(options, document);
|
|
3011
|
+
return {
|
|
3012
|
+
...resolveLocalEditorWorldAppearance(options, document),
|
|
3013
|
+
...PREFAB_STAGE_STUDIO_WORLD_APPEARANCE,
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
1988
3016
|
function resolveLocalEditorWorldRendering(options, document) {
|
|
1989
3017
|
const documentRendering = document
|
|
1990
3018
|
? options.documentAdapter.getWorldRendering?.(document) ?? null
|
|
@@ -1995,6 +3023,15 @@ function resolveLocalEditorWorldRendering(options, document) {
|
|
|
1995
3023
|
postProcess: documentRendering?.postProcess ?? null,
|
|
1996
3024
|
};
|
|
1997
3025
|
}
|
|
3026
|
+
function resolveEffectiveLocalEditorWorldRendering(state, options, document) {
|
|
3027
|
+
const rendering = resolveLocalEditorWorldRendering(options, document);
|
|
3028
|
+
if (!state.prefabStage)
|
|
3029
|
+
return rendering;
|
|
3030
|
+
return {
|
|
3031
|
+
...rendering,
|
|
3032
|
+
environment: PREFAB_STAGE_STUDIO_ENVIRONMENT,
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
1998
3035
|
function hasEditorWorldAppearanceSky(appearance) {
|
|
1999
3036
|
return !!appearance && Object.prototype.hasOwnProperty.call(appearance, 'sky');
|
|
2000
3037
|
}
|
|
@@ -2119,6 +3156,9 @@ function selectBrowserAsset(state, assetId) {
|
|
|
2119
3156
|
function handleBrowserAssetAction(state, options, input) {
|
|
2120
3157
|
if (input.browserAssetId)
|
|
2121
3158
|
state.selectedAssetId = input.browserAssetId;
|
|
3159
|
+
if (input.actionId === 'asset.edit-prefab') {
|
|
3160
|
+
return enterPrefabStage(state, options, input);
|
|
3161
|
+
}
|
|
2122
3162
|
if (input.actionId === 'asset.add-to-scene') {
|
|
2123
3163
|
return input.assetId ? addAssetToDocument(state, options, input.assetId).ok : false;
|
|
2124
3164
|
}
|
|
@@ -2141,18 +3181,355 @@ function handleBrowserAssetAction(state, options, input) {
|
|
|
2141
3181
|
state.statusToneStatus = state.status;
|
|
2142
3182
|
return true;
|
|
2143
3183
|
}
|
|
2144
|
-
function
|
|
3184
|
+
function handleInspectorAction(state, options, input) {
|
|
3185
|
+
if (!input.actionId.startsWith('prefab.')) {
|
|
3186
|
+
const activeId = input.targetId ?? state.session?.getState().selection.activeId ?? null;
|
|
3187
|
+
const selectedIds = input.targetIds ?? (activeId ? [activeId] : []);
|
|
3188
|
+
return patchBrowserAssetAction(state, options, {
|
|
3189
|
+
actionId: input.actionId,
|
|
3190
|
+
fieldPath: input.path,
|
|
3191
|
+
value: input.params,
|
|
3192
|
+
}, { activeId, selectedIds });
|
|
3193
|
+
}
|
|
3194
|
+
const assetId = readInspectorActionParamString(input, 'assetId');
|
|
3195
|
+
const browserAssetId = readInspectorActionParamString(input, 'browserAssetId')
|
|
3196
|
+
?? (assetId ? resolveBrowserAssetItemId(state, options, assetId) : null)
|
|
3197
|
+
?? undefined;
|
|
3198
|
+
if (input.actionId === 'prefab.edit-definition') {
|
|
3199
|
+
if (!assetId) {
|
|
3200
|
+
state.status = 'Prefab action unavailable: missing prefab asset id';
|
|
3201
|
+
state.statusTone = 'warning';
|
|
3202
|
+
state.statusToneStatus = state.status;
|
|
3203
|
+
return true;
|
|
3204
|
+
}
|
|
3205
|
+
return enterPrefabStage(state, options, {
|
|
3206
|
+
actionId: 'asset.edit-prefab',
|
|
3207
|
+
assetId,
|
|
3208
|
+
browserAssetId,
|
|
3209
|
+
assetKind: 'prefab',
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
if (input.actionId === 'prefab.select-definition' || input.actionId === 'prefab.ping-source') {
|
|
3213
|
+
if (!assetId) {
|
|
3214
|
+
state.status = `Prefab action unavailable: ${input.actionId}`;
|
|
3215
|
+
state.statusTone = 'warning';
|
|
3216
|
+
state.statusToneStatus = state.status;
|
|
3217
|
+
return true;
|
|
3218
|
+
}
|
|
3219
|
+
const selected = browserAssetId ? selectBrowserAsset(state, browserAssetId) : false;
|
|
3220
|
+
if (!selected && browserAssetId) {
|
|
3221
|
+
state.status = `Selected asset ${browserAssetId}`;
|
|
3222
|
+
state.statusTone = 'success';
|
|
3223
|
+
state.statusToneStatus = state.status;
|
|
3224
|
+
return true;
|
|
3225
|
+
}
|
|
3226
|
+
if (!browserAssetId) {
|
|
3227
|
+
state.status = `Asset not visible in browser: ${assetId}`;
|
|
3228
|
+
state.statusTone = 'warning';
|
|
3229
|
+
state.statusToneStatus = state.status;
|
|
3230
|
+
return true;
|
|
3231
|
+
}
|
|
3232
|
+
return selected;
|
|
3233
|
+
}
|
|
3234
|
+
state.status = `Prefab inspector action unavailable: ${input.actionId}`;
|
|
3235
|
+
state.statusTone = 'warning';
|
|
3236
|
+
state.statusToneStatus = state.status;
|
|
3237
|
+
return true;
|
|
3238
|
+
}
|
|
3239
|
+
function readInspectorActionParamString(input, key) {
|
|
3240
|
+
const value = input.params?.[key];
|
|
3241
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
3242
|
+
}
|
|
3243
|
+
function enterPrefabStage(state, options, input) {
|
|
3244
|
+
if (state.mode !== 'editor')
|
|
3245
|
+
return false;
|
|
3246
|
+
const sessionState = state.session?.getState({ cloneDocuments: false });
|
|
3247
|
+
const document = sessionState?.workingDocument ?? null;
|
|
3248
|
+
const assetId = input.assetId?.trim();
|
|
3249
|
+
if (!document || !assetId)
|
|
3250
|
+
return false;
|
|
3251
|
+
cancelActiveOperation(state);
|
|
3252
|
+
const previousPrefabStage = state.prefabStage;
|
|
3253
|
+
const asset = findAssetByResolvedId(state, options, assetId);
|
|
3254
|
+
const browserItem = findBrowserAssetItemByResolvedId(state, options, document, input.browserAssetId ?? assetId)
|
|
3255
|
+
?? (input.browserAssetId ? findBrowserAssetItemByResolvedId(state, options, document, assetId) : null);
|
|
3256
|
+
const descriptor = options.documentAdapter.getPrefabStageDescriptor?.(document, {
|
|
3257
|
+
assetId,
|
|
3258
|
+
browserAssetId: input.browserAssetId,
|
|
3259
|
+
asset,
|
|
3260
|
+
}) ?? createFallbackPrefabStageDescriptor(assetId, input.browserAssetId, browserItem);
|
|
3261
|
+
if (!descriptor) {
|
|
3262
|
+
state.status = `Prefab stage unavailable: ${assetId}`;
|
|
3263
|
+
state.statusTone = 'warning';
|
|
3264
|
+
state.statusToneStatus = state.status;
|
|
3265
|
+
return true;
|
|
3266
|
+
}
|
|
3267
|
+
if (previousPrefabStage)
|
|
3268
|
+
state.prefabComparisonPreview?.clear();
|
|
3269
|
+
state.prefabStage = {
|
|
3270
|
+
descriptor,
|
|
3271
|
+
asset,
|
|
3272
|
+
selectedItemId: 'prefab-root',
|
|
3273
|
+
restoreGridVisible: previousPrefabStage?.restoreGridVisible ?? state.gridVisible,
|
|
3274
|
+
restoreSceneCameraPreviewEnabled: previousPrefabStage?.restoreSceneCameraPreviewEnabled ?? state.sceneCameraPreviewEnabled,
|
|
3275
|
+
};
|
|
3276
|
+
setGridVisibleForEditorContext(state, false, 'prefab-stage-enter-grid');
|
|
3277
|
+
state.sceneCameraPreviewEnabled = false;
|
|
3278
|
+
state.sceneCameraPreview?.setActive(false);
|
|
3279
|
+
state.status = `Editing Prefab ${descriptor.label}`;
|
|
3280
|
+
state.statusTone = 'success';
|
|
3281
|
+
state.statusToneStatus = state.status;
|
|
3282
|
+
state.statusDetails = '';
|
|
3283
|
+
rebuildProjectionFromDocument(state, options, document, EMPTY_EDITOR_SELECTION);
|
|
3284
|
+
syncTransformOperationSettingsToSceneArtifacts(state, 'prefab-stage-enter-operation-settings');
|
|
3285
|
+
return true;
|
|
3286
|
+
}
|
|
3287
|
+
function exitPrefabStage(state, options) {
|
|
3288
|
+
if (!state.prefabStage)
|
|
3289
|
+
return false;
|
|
3290
|
+
const sessionState = state.session?.getState({ cloneDocuments: false });
|
|
3291
|
+
const label = sessionState?.workingDocument
|
|
3292
|
+
? resolvePrefabStageDescriptorForDocument(state, options, sessionState.workingDocument)?.label ?? state.prefabStage.descriptor.label
|
|
3293
|
+
: state.prefabStage.descriptor.label;
|
|
3294
|
+
const restoreGridVisible = state.prefabStage.restoreGridVisible;
|
|
3295
|
+
const restoreSceneCameraPreviewEnabled = state.prefabStage.restoreSceneCameraPreviewEnabled;
|
|
3296
|
+
state.prefabStage = null;
|
|
3297
|
+
setGridVisibleForEditorContext(state, restoreGridVisible, 'prefab-stage-exit-grid');
|
|
3298
|
+
if (sessionState?.workingDocument) {
|
|
3299
|
+
rebuildProjectionFromDocument(state, options, sessionState.workingDocument, sessionState.selection);
|
|
3300
|
+
}
|
|
3301
|
+
syncTransformOperationSettingsToSceneArtifacts(state, 'prefab-stage-exit-operation-settings');
|
|
3302
|
+
state.sceneCameraPreviewEnabled = restoreSceneCameraPreviewEnabled;
|
|
3303
|
+
if (restoreSceneCameraPreviewEnabled)
|
|
3304
|
+
syncSceneCameraPreview(state, options);
|
|
3305
|
+
else
|
|
3306
|
+
state.sceneCameraPreview?.setActive(false);
|
|
3307
|
+
state.status = `Exited Prefab ${label}`;
|
|
3308
|
+
state.statusTone = 'default';
|
|
3309
|
+
state.statusToneStatus = state.status;
|
|
3310
|
+
state.statusDetails = '';
|
|
3311
|
+
return true;
|
|
3312
|
+
}
|
|
3313
|
+
function selectPrefabStageItem(state, itemId) {
|
|
3314
|
+
if (!state.prefabStage || state.prefabStage.selectedItemId === itemId)
|
|
3315
|
+
return false;
|
|
3316
|
+
state.prefabStage = {
|
|
3317
|
+
...state.prefabStage,
|
|
3318
|
+
selectedItemId: itemId,
|
|
3319
|
+
};
|
|
3320
|
+
return true;
|
|
3321
|
+
}
|
|
3322
|
+
function selectPrefabStageItemWithPreviewSync(state, options, itemId) {
|
|
3323
|
+
const changed = selectPrefabStageItem(state, itemId);
|
|
3324
|
+
if (changed)
|
|
3325
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection');
|
|
3326
|
+
return changed;
|
|
3327
|
+
}
|
|
3328
|
+
function getCurrentPrefabStageProjectionSelection(state, options) {
|
|
3329
|
+
const stage = state.prefabStage;
|
|
3330
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3331
|
+
if (!stage || !document || !stage.selectedItemId)
|
|
3332
|
+
return EMPTY_EDITOR_SELECTION;
|
|
3333
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? stage.descriptor;
|
|
3334
|
+
const context = createPrefabStageContext(state, descriptor);
|
|
3335
|
+
const item = findPrefabStageStructureItemById(options.documentAdapter.getPrefabStageStructure?.(document, descriptor, context) ?? createFallbackPrefabStageStructure(descriptor), stage.selectedItemId);
|
|
3336
|
+
if (!item?.nodeId)
|
|
3337
|
+
return EMPTY_EDITOR_SELECTION;
|
|
3338
|
+
const projectionNodeId = resolvePrefabStageProjectionNodeIdForNode(state, options, document, item.nodeId);
|
|
3339
|
+
if (!projectionNodeId)
|
|
3340
|
+
return EMPTY_EDITOR_SELECTION;
|
|
3341
|
+
const target = resolvePrefabStagePreviewTarget(state, options, document, projectionNodeId);
|
|
3342
|
+
if (!target?.selectable)
|
|
3343
|
+
return EMPTY_EDITOR_SELECTION;
|
|
3344
|
+
return {
|
|
3345
|
+
selectedIds: [projectionNodeId],
|
|
3346
|
+
activeId: projectionNodeId,
|
|
3347
|
+
};
|
|
3348
|
+
}
|
|
3349
|
+
function syncPrefabStageSelectionToProjection(state, options, reason = 'prefab-stage-projection-selection', revision = state.editorStateRevision) {
|
|
3350
|
+
if (!state.prefabStage)
|
|
3351
|
+
return;
|
|
3352
|
+
if (!beginSceneArtifactSync(state, reason, revision))
|
|
3353
|
+
return;
|
|
3354
|
+
const projectionSelection = getCurrentPrefabStageProjectionSelection(state, options);
|
|
3355
|
+
state.projection?.syncSelection(projectionSelection);
|
|
3356
|
+
state.gizmo?.setSelection(getCurrentPrefabStageTransformGizmoSelection(state, options, projectionSelection));
|
|
3357
|
+
syncTransformGizmoToSceneArtifacts(state, reason, revision, false);
|
|
3358
|
+
}
|
|
3359
|
+
function getCurrentPrefabStageTransformGizmoSelection(state, options, selection = getCurrentPrefabStageProjectionSelection(state, options)) {
|
|
3360
|
+
const activeId = selection.activeId;
|
|
3361
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3362
|
+
if (!activeId || !state.prefabStage || !document)
|
|
3363
|
+
return EMPTY_EDITOR_SELECTION;
|
|
3364
|
+
const target = resolvePrefabStagePreviewTarget(state, options, document, activeId);
|
|
3365
|
+
return target?.transformable ? selection : EMPTY_EDITOR_SELECTION;
|
|
3366
|
+
}
|
|
3367
|
+
function isPrefabStageProjectionSelectable(state, options, projectionNodeId) {
|
|
3368
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3369
|
+
if (!state.prefabStage || !document)
|
|
3370
|
+
return false;
|
|
3371
|
+
return resolvePrefabStagePreviewTarget(state, options, document, projectionNodeId)?.selectable === true;
|
|
3372
|
+
}
|
|
3373
|
+
function dispatchPrefabStageProjectionSelectionCommand(state, options, command) {
|
|
3374
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3375
|
+
if (!state.prefabStage || !document)
|
|
3376
|
+
return false;
|
|
3377
|
+
const currentProjectionSelection = getCurrentPrefabStageProjectionSelection(state, options);
|
|
3378
|
+
if (command.type === 'selection.clear') {
|
|
3379
|
+
if (state.prefabStage.selectedItemId === null)
|
|
3380
|
+
return false;
|
|
3381
|
+
state.prefabStage = { ...state.prefabStage, selectedItemId: null };
|
|
3382
|
+
state.editorStateRevision += 1;
|
|
3383
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-clear', state.editorStateRevision);
|
|
3384
|
+
return true;
|
|
3385
|
+
}
|
|
3386
|
+
const candidateId = ('activeId' in command ? command.activeId : null)
|
|
3387
|
+
?? command.selectedIds[command.selectedIds.length - 1]
|
|
3388
|
+
?? null;
|
|
3389
|
+
if (!candidateId)
|
|
3390
|
+
return false;
|
|
3391
|
+
const target = resolvePrefabStagePreviewTarget(state, options, document, candidateId);
|
|
3392
|
+
if (!target?.selectable)
|
|
3393
|
+
return false;
|
|
3394
|
+
const currentlySelected = currentProjectionSelection.selectedIds.includes(candidateId);
|
|
3395
|
+
if ((command.type === 'selection.toggle' && currentlySelected)
|
|
3396
|
+
|| (command.type === 'selection.remove' && currentlySelected)) {
|
|
3397
|
+
state.prefabStage = { ...state.prefabStage, selectedItemId: null };
|
|
3398
|
+
state.editorStateRevision += 1;
|
|
3399
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-remove', state.editorStateRevision);
|
|
3400
|
+
return true;
|
|
3401
|
+
}
|
|
3402
|
+
if (command.type === 'selection.remove')
|
|
3403
|
+
return false;
|
|
3404
|
+
const nextItemId = target.itemId ?? `prefab-node:${target.targetId}`;
|
|
3405
|
+
if (state.prefabStage.selectedItemId === nextItemId)
|
|
3406
|
+
return false;
|
|
3407
|
+
state.prefabStage = { ...state.prefabStage, selectedItemId: nextItemId };
|
|
3408
|
+
state.editorStateRevision += 1;
|
|
3409
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-command', state.editorStateRevision);
|
|
3410
|
+
return true;
|
|
3411
|
+
}
|
|
3412
|
+
function resolvePrefabStagePreviewTarget(state, options, document, projectionNodeId) {
|
|
3413
|
+
const stage = state.prefabStage;
|
|
3414
|
+
if (!stage)
|
|
3415
|
+
return null;
|
|
3416
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? stage.descriptor;
|
|
3417
|
+
const context = createPrefabStageContext(state, descriptor);
|
|
3418
|
+
const adapterTarget = options.documentAdapter.resolvePrefabStagePreviewTarget?.(document, descriptor, projectionNodeId, context);
|
|
3419
|
+
if (adapterTarget)
|
|
3420
|
+
return adapterTarget;
|
|
3421
|
+
return resolvePrefabStagePreviewTargetFromStructure(descriptor, projectionNodeId, options.documentAdapter.getPrefabStageStructure?.(document, descriptor, context) ?? createFallbackPrefabStageStructure(descriptor));
|
|
3422
|
+
}
|
|
3423
|
+
function resolvePrefabStageProjectionNodeIdForNode(state, options, document, nodeId) {
|
|
3424
|
+
const stage = state.prefabStage;
|
|
3425
|
+
if (!stage)
|
|
3426
|
+
return null;
|
|
3427
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? stage.descriptor;
|
|
3428
|
+
const context = createPrefabStageContext(state, descriptor);
|
|
3429
|
+
const adapterProjectionNodeId = options.documentAdapter.getPrefabStageProjectionNodeId?.(document, descriptor, nodeId, context);
|
|
3430
|
+
if (adapterProjectionNodeId)
|
|
3431
|
+
return adapterProjectionNodeId;
|
|
3432
|
+
const target = findPrefabStageStructureNodeByNodeId(options.documentAdapter.getPrefabStageStructure?.(document, descriptor, context) ?? createFallbackPrefabStageStructure(descriptor), nodeId);
|
|
3433
|
+
return target?.nodeId ? createFallbackPrefabStageProjectionNodeId(descriptor, target.nodeId) : null;
|
|
3434
|
+
}
|
|
3435
|
+
function resolvePrefabStagePreviewTargetFromStructure(descriptor, projectionNodeId, items) {
|
|
3436
|
+
const prefix = descriptor.previewNodeId;
|
|
3437
|
+
if (!prefix || projectionNodeId.includes(':compare-'))
|
|
3438
|
+
return null;
|
|
3439
|
+
for (const item of flattenPrefabStageStructureNodes(items)) {
|
|
3440
|
+
if (!item.nodeId)
|
|
3441
|
+
continue;
|
|
3442
|
+
const expectedProjectionNodeId = createFallbackPrefabStageProjectionNodeId(descriptor, item.nodeId);
|
|
3443
|
+
if (expectedProjectionNodeId !== projectionNodeId)
|
|
3444
|
+
continue;
|
|
3445
|
+
const readonly = descriptor.readonly === true || item.readonly === true;
|
|
3446
|
+
const isRoot = item.kind === 'root';
|
|
3447
|
+
return {
|
|
3448
|
+
scopeId: `prefab-stage:${descriptor.assetId}`,
|
|
3449
|
+
scopeKind: 'prefab-stage',
|
|
3450
|
+
projectionNodeId,
|
|
3451
|
+
targetId: item.nodeId,
|
|
3452
|
+
itemId: item.id,
|
|
3453
|
+
label: item.label,
|
|
3454
|
+
kind: item.kind,
|
|
3455
|
+
selectable: true,
|
|
3456
|
+
transformable: !readonly && !isRoot,
|
|
3457
|
+
readonly,
|
|
3458
|
+
...(!readonly && !isRoot ? {} : { disabledReason: readonly ? 'Prefab stage is readonly.' : 'Prefab root cannot be transformed from Preview.' }),
|
|
3459
|
+
};
|
|
3460
|
+
}
|
|
3461
|
+
return null;
|
|
3462
|
+
}
|
|
3463
|
+
function createFallbackPrefabStageProjectionNodeId(descriptor, nodeId) {
|
|
3464
|
+
const prefix = descriptor.previewNodeId;
|
|
3465
|
+
if (!prefix)
|
|
3466
|
+
return null;
|
|
3467
|
+
return nodeId === 'prefab-root' ? prefix : `${prefix}:${nodeId}`;
|
|
3468
|
+
}
|
|
3469
|
+
function findPrefabStageStructureNodeByNodeId(items, nodeId) {
|
|
3470
|
+
return flattenPrefabStageStructureNodes(items).find(item => item.nodeId === nodeId) ?? null;
|
|
3471
|
+
}
|
|
3472
|
+
function findPrefabStageStructureItemById(items, itemId) {
|
|
3473
|
+
return flattenPrefabStageStructureNodes(items).find(item => item.id === itemId) ?? null;
|
|
3474
|
+
}
|
|
3475
|
+
function flattenPrefabStageStructureNodes(items) {
|
|
3476
|
+
const flattened = [];
|
|
3477
|
+
for (const item of items) {
|
|
3478
|
+
if (item.itemType === 'prefab-node' && item.nodeId)
|
|
3479
|
+
flattened.push(item);
|
|
3480
|
+
flattened.push(...flattenPrefabStageStructureNodes(item.children ?? []));
|
|
3481
|
+
}
|
|
3482
|
+
return flattened;
|
|
3483
|
+
}
|
|
3484
|
+
function createFallbackPrefabStageDescriptor(assetId, browserAssetId, item) {
|
|
3485
|
+
if (!item?.prefab)
|
|
3486
|
+
return null;
|
|
3487
|
+
return {
|
|
3488
|
+
assetId: item.prefab.id || item.assetId || assetId,
|
|
3489
|
+
browserAssetId: browserAssetId ?? item.id,
|
|
3490
|
+
label: item.prefab.name || item.label || item.prefab.id || assetId,
|
|
3491
|
+
sourceAssetId: item.prefab.sourceAssetId,
|
|
3492
|
+
sourceAssetGuid: item.prefab.sourceAssetGuid,
|
|
3493
|
+
readonly: item.prefab.readonly === true,
|
|
3494
|
+
previewNodeId: `prefab-stage:${item.prefab.id || item.assetId || assetId}`,
|
|
3495
|
+
};
|
|
3496
|
+
}
|
|
3497
|
+
function resolvePrefabStageDescriptorForDocument(state, options, document) {
|
|
3498
|
+
const stage = state.prefabStage;
|
|
3499
|
+
if (!stage)
|
|
3500
|
+
return null;
|
|
3501
|
+
const assetId = stage.descriptor.assetId;
|
|
3502
|
+
const browserAssetId = stage.descriptor.browserAssetId;
|
|
3503
|
+
const descriptor = options.documentAdapter.getPrefabStageDescriptor?.(document, {
|
|
3504
|
+
assetId,
|
|
3505
|
+
browserAssetId,
|
|
3506
|
+
asset: stage.asset,
|
|
3507
|
+
});
|
|
3508
|
+
if (descriptor) {
|
|
3509
|
+
return {
|
|
3510
|
+
...stage.descriptor,
|
|
3511
|
+
...descriptor,
|
|
3512
|
+
browserAssetId: descriptor.browserAssetId ?? browserAssetId,
|
|
3513
|
+
previewNodeId: descriptor.previewNodeId ?? stage.descriptor.previewNodeId,
|
|
3514
|
+
};
|
|
3515
|
+
}
|
|
3516
|
+
const browserItem = findBrowserAssetItemByResolvedId(state, options, document, browserAssetId ?? assetId)
|
|
3517
|
+
?? (browserAssetId ? findBrowserAssetItemByResolvedId(state, options, document, assetId) : null);
|
|
3518
|
+
return createFallbackPrefabStageDescriptor(assetId, browserAssetId, browserItem) ?? stage.descriptor;
|
|
3519
|
+
}
|
|
3520
|
+
function patchBrowserAssetAction(state, options, input, selectionOverride) {
|
|
2145
3521
|
const session = state.session;
|
|
2146
3522
|
const document = session?.getState().workingDocument ?? null;
|
|
2147
3523
|
if (!session || !document || !options.documentAdapter.createAssetActionPatch)
|
|
2148
3524
|
return false;
|
|
2149
3525
|
const asset = input.assetId ? findAssetByResolvedId(state, options, input.assetId) : null;
|
|
3526
|
+
const sessionSelection = session.getState().selection;
|
|
2150
3527
|
const patch = options.documentAdapter.createAssetActionPatch({
|
|
2151
3528
|
...input,
|
|
2152
3529
|
document,
|
|
2153
3530
|
asset,
|
|
2154
|
-
activeId:
|
|
2155
|
-
selectedIds: [...
|
|
3531
|
+
activeId: selectionOverride?.activeId ?? sessionSelection.activeId,
|
|
3532
|
+
selectedIds: selectionOverride?.selectedIds ?? [...sessionSelection.selectedIds],
|
|
2156
3533
|
});
|
|
2157
3534
|
if (!patch)
|
|
2158
3535
|
return false;
|
|
@@ -2175,12 +3552,52 @@ function patchBrowserAssetAction(state, options, input) {
|
|
|
2175
3552
|
reprojectProjectionForChangedIds(state, options, result.workingDocument, patch.reprojectIds);
|
|
2176
3553
|
else if (patch.changedIds)
|
|
2177
3554
|
syncProjectionForChangedIds(state, options, result.workingDocument, patch.changedIds);
|
|
3555
|
+
else if (state.prefabStage && result.documentChanged) {
|
|
3556
|
+
rebuildProjectionFromDocument(state, options, result.workingDocument, EMPTY_EDITOR_SELECTION);
|
|
3557
|
+
}
|
|
3558
|
+
if (result.documentChanged && isPrefabStageShadowAssetAction(input)) {
|
|
3559
|
+
state.shadowPreview?.invalidateStaticProjectedArtifact?.();
|
|
3560
|
+
scheduleProjectionShadowPreviewRefresh(state, 'prefab-stage-shadow-policy-action');
|
|
3561
|
+
}
|
|
3562
|
+
syncPrefabStageSelectionFromAssetAction(state, options, input, patch.createdId ?? patch.changedId ?? null);
|
|
2178
3563
|
if (input.actionId === 'asset.delete-material' && input.browserAssetId && state.selectedAssetId === input.browserAssetId) {
|
|
2179
3564
|
state.selectedAssetId = null;
|
|
2180
3565
|
}
|
|
2181
3566
|
selectCreatedBrowserAssetFromPatch(state, options, patch.createdId ?? null, input);
|
|
2182
3567
|
return true;
|
|
2183
3568
|
}
|
|
3569
|
+
function isPrefabStageShadowAssetAction(input) {
|
|
3570
|
+
if (input.actionId === 'prefab.node.setShadow')
|
|
3571
|
+
return true;
|
|
3572
|
+
if (input.actionId !== 'asset.edit-prefab-field')
|
|
3573
|
+
return false;
|
|
3574
|
+
const fieldPath = typeof input.fieldPath === 'string' ? input.fieldPath.trim() : '';
|
|
3575
|
+
return fieldPath === 'prefab.defaults.shadowMode' || fieldPath.startsWith('prefab.defaults.shadow.');
|
|
3576
|
+
}
|
|
3577
|
+
function syncPrefabStageSelectionFromAssetAction(state, options, input, nodeId) {
|
|
3578
|
+
if (!state.prefabStage)
|
|
3579
|
+
return;
|
|
3580
|
+
const isPrefabNodeAction = input.actionId.startsWith('prefab.node.')
|
|
3581
|
+
|| input.actionId === 'asset.add-to-current-prefab';
|
|
3582
|
+
if (!isPrefabNodeAction)
|
|
3583
|
+
return;
|
|
3584
|
+
if (input.actionId === 'prefab.node.delete') {
|
|
3585
|
+
const rootId = typeof nodeId === 'string' && nodeId ? nodeId : 'prefab-root';
|
|
3586
|
+
state.prefabStage = {
|
|
3587
|
+
...state.prefabStage,
|
|
3588
|
+
selectedItemId: `prefab-node:${rootId}`,
|
|
3589
|
+
};
|
|
3590
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-delete');
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
if (!nodeId)
|
|
3594
|
+
return;
|
|
3595
|
+
state.prefabStage = {
|
|
3596
|
+
...state.prefabStage,
|
|
3597
|
+
selectedItemId: `prefab-node:${nodeId}`,
|
|
3598
|
+
};
|
|
3599
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-asset-action');
|
|
3600
|
+
}
|
|
2184
3601
|
function selectCreatedBrowserAssetFromPatch(state, options, createdId, input) {
|
|
2185
3602
|
if (!createdId)
|
|
2186
3603
|
return;
|
|
@@ -2191,12 +3608,18 @@ function selectCreatedBrowserAssetFromPatch(state, options, createdId, input) {
|
|
|
2191
3608
|
else if (input.actionId === 'asset.create-material' || input.actionId === 'asset.duplicate-material') {
|
|
2192
3609
|
state.selectedAssetId = `material:${createdId}`;
|
|
2193
3610
|
}
|
|
3611
|
+
else if (input.actionId === 'asset.create-prefab'
|
|
3612
|
+
|| input.actionId === 'asset.create-prefab-from-game-object'
|
|
3613
|
+
|| input.actionId === 'asset.duplicate-prefab') {
|
|
3614
|
+
state.selectedAssetId = resolveBrowserAssetItemId(state, options, `prefab:${createdId}`) ?? `prefab:${createdId}`;
|
|
3615
|
+
}
|
|
2194
3616
|
}
|
|
2195
3617
|
function armAssetPlacement(state, options, assetId) {
|
|
2196
3618
|
if (state.mode !== 'editor')
|
|
2197
3619
|
return false;
|
|
2198
3620
|
cancelActiveOperation(state);
|
|
2199
|
-
const
|
|
3621
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3622
|
+
const asset = findAssetOrDocumentBrowserItemByResolvedId(state, options, document, assetId);
|
|
2200
3623
|
if (!asset)
|
|
2201
3624
|
return false;
|
|
2202
3625
|
state.armedPlacement = { assetId, asset };
|
|
@@ -2298,7 +3721,7 @@ function addAssetToDocument(state, options, assetId, createOptions = {}) {
|
|
|
2298
3721
|
state.status = 'Asset creation rejected: document is not loaded';
|
|
2299
3722
|
return { ok: false, assetId, changed: false, status: state.status, error: 'document_not_loaded' };
|
|
2300
3723
|
}
|
|
2301
|
-
const asset =
|
|
3724
|
+
const asset = findAssetOrDocumentBrowserItemByResolvedId(state, options, beforeDocument, assetId);
|
|
2302
3725
|
if (!asset) {
|
|
2303
3726
|
state.status = `Asset creation rejected: ${assetId} not found`;
|
|
2304
3727
|
return { ok: false, assetId, changed: false, status: state.status, error: 'asset_not_found' };
|
|
@@ -2307,6 +3730,7 @@ function addAssetToDocument(state, options, assetId, createOptions = {}) {
|
|
|
2307
3730
|
document: beforeDocument,
|
|
2308
3731
|
asset,
|
|
2309
3732
|
assetId,
|
|
3733
|
+
name: createOptions.name,
|
|
2310
3734
|
placement: createOptions.placement,
|
|
2311
3735
|
});
|
|
2312
3736
|
const result = session.dispatch({
|
|
@@ -2322,7 +3746,7 @@ function addAssetToDocument(state, options, assetId, createOptions = {}) {
|
|
|
2322
3746
|
?? options.documentAdapter.findCreatedId?.(beforeDocument, result.workingDocument)
|
|
2323
3747
|
?? null;
|
|
2324
3748
|
let selectionResult = null;
|
|
2325
|
-
if (createdId) {
|
|
3749
|
+
if (createdId && createOptions.select !== false) {
|
|
2326
3750
|
selectionResult = session.dispatch({
|
|
2327
3751
|
type: 'selection.replace',
|
|
2328
3752
|
selectedIds: [createdId],
|
|
@@ -2340,7 +3764,7 @@ function addAssetToDocument(state, options, assetId, createOptions = {}) {
|
|
|
2340
3764
|
if (projectedNode) {
|
|
2341
3765
|
state.projection?.projectNode(projectedNode);
|
|
2342
3766
|
if (selectionResult)
|
|
2343
|
-
syncSelectionToProjection(state, selectionResult.selection);
|
|
3767
|
+
syncSelectionToProjection(state, options, selectionResult.selection);
|
|
2344
3768
|
invalidateEditorScene(state, 'projection-project-node');
|
|
2345
3769
|
}
|
|
2346
3770
|
}
|
|
@@ -2367,6 +3791,12 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2367
3791
|
return false;
|
|
2368
3792
|
}
|
|
2369
3793
|
const payload = transaction.payload;
|
|
3794
|
+
if (state.prefabStage) {
|
|
3795
|
+
return patchPrefabStageInspectorProperty(state, options, payload);
|
|
3796
|
+
}
|
|
3797
|
+
const markerGraphPatched = patchMarkerGraphInspectorProperty(state, options, document, payload);
|
|
3798
|
+
if (markerGraphPatched !== null)
|
|
3799
|
+
return markerGraphPatched;
|
|
2370
3800
|
const shouldReprojectInspectorEdit = shouldReprojectEditorInspectorEditPath(payload.path);
|
|
2371
3801
|
if (targetIds.length > 1) {
|
|
2372
3802
|
const patch = options.documentAdapter.createSerializedMultiPropertyPatch?.({
|
|
@@ -2385,9 +3815,11 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2385
3815
|
return false;
|
|
2386
3816
|
const changedIds = patch.changedIds ?? targetIds;
|
|
2387
3817
|
const projectionMetadataPatch = isSerializedProjectionMetadataPath(payload.path);
|
|
3818
|
+
const shadowTopologyMetadataPatch = isSerializedShadowTopologyMetadataPath(payload.path);
|
|
2388
3819
|
const largeProjectionMetadataPatch = projectionMetadataPatch
|
|
3820
|
+
&& !shadowTopologyMetadataPatch
|
|
2389
3821
|
&& changedIds.length >= LARGE_SHADOW_MODE_BATCH_THRESHOLD;
|
|
2390
|
-
const invalidateStaticShadowArtifact = projectionMetadataPatch && payload.path
|
|
3822
|
+
const invalidateStaticShadowArtifact = projectionMetadataPatch && isSerializedShadowMetadataPath(payload.path);
|
|
2391
3823
|
const result = state.session.dispatch({
|
|
2392
3824
|
type: 'document.patch',
|
|
2393
3825
|
label: patch.label ?? `Patch ${payload.path} on ${targetIds.length} objects`,
|
|
@@ -2416,6 +3848,9 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2416
3848
|
reprojectProjectionForChangedIds(state, options, workingDocument, patch.reprojectIds);
|
|
2417
3849
|
else if (shouldReprojectInspectorEdit)
|
|
2418
3850
|
reprojectProjectionForChangedIds(state, options, workingDocument, changedIds);
|
|
3851
|
+
else if (shadowTopologyMetadataPatch) {
|
|
3852
|
+
rebuildProjectionAfterShadowTopologyMetadataPatch(state, options, workingDocument, sessionState.selection);
|
|
3853
|
+
}
|
|
2419
3854
|
else if (isSerializedProjectionMetadataPath(payload.path)) {
|
|
2420
3855
|
syncProjectionMetadataForChangedIds(state, options, workingDocument, projectionSyncIds, {
|
|
2421
3856
|
deferShadowPreviewRefresh: largeProjectionMetadataPatch,
|
|
@@ -2424,6 +3859,10 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2424
3859
|
}
|
|
2425
3860
|
else
|
|
2426
3861
|
syncProjectionForChangedIds(state, options, workingDocument, projectionSyncIds);
|
|
3862
|
+
if (isMarkerInspectorEditPath(payload.path)) {
|
|
3863
|
+
syncMarkerOverlayToSceneArtifacts(state, options, result.selection);
|
|
3864
|
+
state.gizmo?.refreshSelection();
|
|
3865
|
+
}
|
|
2427
3866
|
state.summary = summarizeDocument(options, workingDocument, state.session.getSource());
|
|
2428
3867
|
state.status = patch.label ?? `Patch ${payload.path} on ${targetIds.length} objects`;
|
|
2429
3868
|
return true;
|
|
@@ -2459,9 +3898,13 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2459
3898
|
else if (shouldReprojectInspectorEdit) {
|
|
2460
3899
|
reprojectProjectionForChangedIds(state, options, result.workingDocument, patch.changedIds ?? [patch.changedId ?? payload.targetId]);
|
|
2461
3900
|
}
|
|
3901
|
+
else if (isSerializedShadowTopologyMetadataPath(payload.path)) {
|
|
3902
|
+
const selection = state.session?.getState({ cloneDocuments: false }).selection ?? EMPTY_EDITOR_SELECTION;
|
|
3903
|
+
rebuildProjectionAfterShadowTopologyMetadataPatch(state, options, result.workingDocument, selection);
|
|
3904
|
+
}
|
|
2462
3905
|
else if (isSerializedProjectionMetadataPath(payload.path)) {
|
|
2463
|
-
syncProjectionMetadataForChangedIds(state, options, result.workingDocument, [patch.changedId ?? payload.targetId], {
|
|
2464
|
-
invalidateStaticShadowArtifact: payload.path
|
|
3906
|
+
syncProjectionMetadataForChangedIds(state, options, result.workingDocument, patch.changedIds ?? [patch.changedId ?? payload.targetId], {
|
|
3907
|
+
invalidateStaticShadowArtifact: isSerializedShadowMetadataPath(payload.path),
|
|
2465
3908
|
});
|
|
2466
3909
|
}
|
|
2467
3910
|
else if (isSerializedTransformPath(payload.path))
|
|
@@ -2470,11 +3913,313 @@ function patchSerializedProperty(state, options, input) {
|
|
|
2470
3913
|
syncProjectionForChangedIds(state, options, result.workingDocument, patch.changedIds);
|
|
2471
3914
|
else
|
|
2472
3915
|
syncProjectionForDispatchResult(state, options, result, patch.changedId ?? payload.targetId);
|
|
3916
|
+
if (isMarkerInspectorEditPath(payload.path)) {
|
|
3917
|
+
syncMarkerOverlayToSceneArtifacts(state, options, result.selection);
|
|
3918
|
+
state.gizmo?.refreshSelection();
|
|
3919
|
+
}
|
|
2473
3920
|
state.summary = summarizeDocument(options, result.workingDocument, state.session.getSource());
|
|
2474
3921
|
state.status = patch.label ?? `Patched ${payload.path}`;
|
|
2475
3922
|
return true;
|
|
2476
3923
|
}
|
|
3924
|
+
function patchPrefabStageInspectorProperty(state, options, payload) {
|
|
3925
|
+
if (payload.persistence !== 'document') {
|
|
3926
|
+
state.status = `Prefab field is not document-editable: ${payload.path}.`;
|
|
3927
|
+
return false;
|
|
3928
|
+
}
|
|
3929
|
+
const session = state.session;
|
|
3930
|
+
const document = session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
3931
|
+
if (!document)
|
|
3932
|
+
return false;
|
|
3933
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? state.prefabStage?.descriptor ?? null;
|
|
3934
|
+
if (!descriptor) {
|
|
3935
|
+
state.status = 'Prefab stage is not ready.';
|
|
3936
|
+
return false;
|
|
3937
|
+
}
|
|
3938
|
+
return patchBrowserAssetAction(state, options, {
|
|
3939
|
+
actionId: 'asset.edit-prefab-field',
|
|
3940
|
+
assetId: descriptor.assetId,
|
|
3941
|
+
browserAssetId: descriptor.browserAssetId,
|
|
3942
|
+
assetKind: 'prefab',
|
|
3943
|
+
fieldPath: payload.path,
|
|
3944
|
+
value: payload.value,
|
|
3945
|
+
});
|
|
3946
|
+
}
|
|
3947
|
+
function isMarkerInspectorEditPath(path) {
|
|
3948
|
+
return path === 'name' || path.startsWith('marker.');
|
|
3949
|
+
}
|
|
3950
|
+
function patchMarkerGraphInspectorProperty(state, options, document, payload) {
|
|
3951
|
+
if (!isMarkerInspectorEditPath(payload.path))
|
|
3952
|
+
return null;
|
|
3953
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
3954
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
3955
|
+
if (!readMarkerGraphHierarchyMarkerIdForGraph(graph, payload.targetId, hierarchy))
|
|
3956
|
+
return null;
|
|
3957
|
+
const markerTypes = options.documentAdapter.getMarkerTypeCatalog?.(document) ?? [];
|
|
3958
|
+
const command = createMarkerGraphPatchFromInspectorEdit(graph, payload, hierarchy, markerTypes);
|
|
3959
|
+
if (!command) {
|
|
3960
|
+
state.status = `Marker edit rejected: ${payload.path}`;
|
|
3961
|
+
return false;
|
|
3962
|
+
}
|
|
3963
|
+
const patch = options.documentAdapter.createMarkerGraphPatch?.(document, command);
|
|
3964
|
+
if (!patch) {
|
|
3965
|
+
state.status = `Marker edit rejected: ${payload.targetId}`;
|
|
3966
|
+
return false;
|
|
3967
|
+
}
|
|
3968
|
+
const result = state.session?.dispatch({
|
|
3969
|
+
type: 'document.patch',
|
|
3970
|
+
label: patch.label ?? `Patch marker ${payload.path}`,
|
|
3971
|
+
patch: patch.patch,
|
|
3972
|
+
targetId: payload.targetId,
|
|
3973
|
+
});
|
|
3974
|
+
if (!result?.documentChanged)
|
|
3975
|
+
return false;
|
|
3976
|
+
syncProjectionForDispatchResult(state, options, result, patch.changedId ?? payload.targetId);
|
|
3977
|
+
syncMarkerOverlayToSceneArtifacts(state, options, result.selection);
|
|
3978
|
+
state.gizmo?.refreshSelection();
|
|
3979
|
+
state.summary = summarizeDocument(options, result.workingDocument, state.session?.getSource());
|
|
3980
|
+
state.status = patch.label ?? `Patched marker ${payload.path}`;
|
|
3981
|
+
return true;
|
|
3982
|
+
}
|
|
3983
|
+
function patchMarkerTypeCatalog(state, options, input) {
|
|
3984
|
+
if (state.mode !== 'editor')
|
|
3985
|
+
return false;
|
|
3986
|
+
cancelActiveOperation(state);
|
|
3987
|
+
const document = state.session?.getState().workingDocument ?? null;
|
|
3988
|
+
if (!document)
|
|
3989
|
+
return false;
|
|
3990
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
3991
|
+
if (!graph || !options.documentAdapter.createMarkerGraphPatch)
|
|
3992
|
+
return false;
|
|
3993
|
+
const command = createMarkerTypeCatalogCommand(input);
|
|
3994
|
+
if (!command) {
|
|
3995
|
+
state.status = 'Marker type edit rejected';
|
|
3996
|
+
state.statusTone = 'warning';
|
|
3997
|
+
state.statusToneStatus = state.status;
|
|
3998
|
+
return false;
|
|
3999
|
+
}
|
|
4000
|
+
const patch = options.documentAdapter.createMarkerGraphPatch(document, command);
|
|
4001
|
+
if (!patch) {
|
|
4002
|
+
state.status = `Marker type edit rejected: ${input.type}`;
|
|
4003
|
+
state.statusTone = 'warning';
|
|
4004
|
+
state.statusToneStatus = state.status;
|
|
4005
|
+
return false;
|
|
4006
|
+
}
|
|
4007
|
+
const session = state.session;
|
|
4008
|
+
if (!session)
|
|
4009
|
+
return false;
|
|
4010
|
+
const result = session.dispatch({
|
|
4011
|
+
type: 'document.patch',
|
|
4012
|
+
label: patch.label ?? 'Patch marker type catalog',
|
|
4013
|
+
patch: patch.patch,
|
|
4014
|
+
targetId: session.getState().selection.activeId ?? undefined,
|
|
4015
|
+
});
|
|
4016
|
+
if (!result.documentChanged)
|
|
4017
|
+
return false;
|
|
4018
|
+
syncMarkerOverlayToSceneArtifacts(state, options, result.selection);
|
|
4019
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
4020
|
+
state.status = patch.label ?? 'Patched marker type catalog';
|
|
4021
|
+
state.statusTone = 'success';
|
|
4022
|
+
state.statusToneStatus = state.status;
|
|
4023
|
+
state.statusDetails = '';
|
|
4024
|
+
return true;
|
|
4025
|
+
}
|
|
4026
|
+
function patchMarkerRelation(state, options, input) {
|
|
4027
|
+
if (state.mode !== 'editor')
|
|
4028
|
+
return false;
|
|
4029
|
+
cancelActiveOperation(state);
|
|
4030
|
+
const document = state.session?.getState().workingDocument ?? null;
|
|
4031
|
+
if (!document)
|
|
4032
|
+
return false;
|
|
4033
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
4034
|
+
if (!graph)
|
|
4035
|
+
return false;
|
|
4036
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
4037
|
+
const activeId = state.session?.getState().selection.activeId ?? null;
|
|
4038
|
+
const activeMarkerId = activeId ? readSpatialMarkerIdFromHierarchySelection(graph, activeId, hierarchy) : null;
|
|
4039
|
+
if (input.action === 'pick-cancel') {
|
|
4040
|
+
state.markerRelationPick = null;
|
|
4041
|
+
state.status = '已取消关系端点拾取。';
|
|
4042
|
+
state.statusTone = 'success';
|
|
4043
|
+
state.statusToneStatus = state.status;
|
|
4044
|
+
state.statusDetails = '';
|
|
4045
|
+
return true;
|
|
4046
|
+
}
|
|
4047
|
+
if (input.action === 'pick-start') {
|
|
4048
|
+
const relationTypes = options.documentAdapter.getRelationTypeCatalog?.(document) ?? [];
|
|
4049
|
+
const type = input.type.trim();
|
|
4050
|
+
if (!type) {
|
|
4051
|
+
state.status = '请选择关系类型。';
|
|
4052
|
+
state.statusTone = 'warning';
|
|
4053
|
+
state.statusToneStatus = state.status;
|
|
4054
|
+
state.statusDetails = state.status;
|
|
4055
|
+
return true;
|
|
4056
|
+
}
|
|
4057
|
+
const typeDefinition = relationTypes.find(definition => definition.type === type);
|
|
4058
|
+
const from = createMarkerRelationPickEndpoint(input.fromKind, input.fromId);
|
|
4059
|
+
const directed = input.directed ?? typeDefinition?.directed ?? true;
|
|
4060
|
+
const typeLabel = typeDefinition?.label ?? type;
|
|
4061
|
+
const status = from
|
|
4062
|
+
? `关系拾取中:${formatMarkerRelationPickEndpointLabel(from, graph, hierarchy)} ${typeLabel} ... 请在视口点击终点。`
|
|
4063
|
+
: `关系拾取中:请选择 ${typeLabel} 的起点。`;
|
|
4064
|
+
state.markerRelationPick = {
|
|
4065
|
+
active: true,
|
|
4066
|
+
type,
|
|
4067
|
+
typeLabel,
|
|
4068
|
+
directed,
|
|
4069
|
+
from,
|
|
4070
|
+
status,
|
|
4071
|
+
statusTone: 'success',
|
|
4072
|
+
};
|
|
4073
|
+
state.status = status;
|
|
4074
|
+
state.statusTone = 'success';
|
|
4075
|
+
state.statusToneStatus = state.status;
|
|
4076
|
+
state.statusDetails = '关系拾取会消费下一次有效视口点击,不改变当前选择。';
|
|
4077
|
+
return true;
|
|
4078
|
+
}
|
|
4079
|
+
if (input.action === 'select') {
|
|
4080
|
+
const relationId = input.relationId.trim();
|
|
4081
|
+
if (!relationId)
|
|
4082
|
+
return false;
|
|
4083
|
+
const relation = graph.relations.find(candidate => candidate.id === relationId) ?? null;
|
|
4084
|
+
state.activeMarkerRelationId = relationId;
|
|
4085
|
+
state.status = relation ? `高亮关系:${relation.label ?? relation.type}` : `关系不存在:${relationId}`;
|
|
4086
|
+
state.statusTone = relation ? 'success' : 'warning';
|
|
4087
|
+
state.statusToneStatus = state.status;
|
|
4088
|
+
state.statusDetails = relation ? relationId : state.status;
|
|
4089
|
+
syncMarkerOverlayToSceneArtifacts(state, options, state.session?.getState().selection ?? { selectedIds: [], activeId: null });
|
|
4090
|
+
requestEditorSceneFrame(state, 'marker-relation-select');
|
|
4091
|
+
return true;
|
|
4092
|
+
}
|
|
4093
|
+
if (!options.documentAdapter.createMarkerGraphPatch)
|
|
4094
|
+
return false;
|
|
4095
|
+
const relationTypes = options.documentAdapter.getRelationTypeCatalog?.(document) ?? [];
|
|
4096
|
+
const result = input.action === 'reverse'
|
|
4097
|
+
? createMarkerRelationReverseCommand(input.relationId, graph)
|
|
4098
|
+
: input.action === 'delete-connected'
|
|
4099
|
+
? createMarkerRelationDeleteConnectedCommand(input.markerId ?? activeMarkerId ?? '', graph)
|
|
4100
|
+
: input.action === 'create' && input.toEndpoints && input.toEndpoints.length > 0
|
|
4101
|
+
? createMarkerRelationCreateManyCommand({
|
|
4102
|
+
type: input.type,
|
|
4103
|
+
fromKind: input.fromKind,
|
|
4104
|
+
fromId: input.fromId,
|
|
4105
|
+
toEndpoints: input.toEndpoints,
|
|
4106
|
+
directed: input.directed,
|
|
4107
|
+
}, graph, relationTypes, hierarchy, activeMarkerId)
|
|
4108
|
+
: createMarkerRelationCommand(input, graph, relationTypes, hierarchy, activeMarkerId);
|
|
4109
|
+
if (!result.command) {
|
|
4110
|
+
state.status = result.status;
|
|
4111
|
+
state.statusTone = result.statusTone;
|
|
4112
|
+
state.statusToneStatus = state.status;
|
|
4113
|
+
state.statusDetails = result.status;
|
|
4114
|
+
return true;
|
|
4115
|
+
}
|
|
4116
|
+
const patch = options.documentAdapter.createMarkerGraphPatch(document, result.command);
|
|
4117
|
+
if (!patch) {
|
|
4118
|
+
state.status = result.status || 'Marker relation edit rejected';
|
|
4119
|
+
state.statusTone = 'warning';
|
|
4120
|
+
state.statusToneStatus = state.status;
|
|
4121
|
+
state.statusDetails = state.status;
|
|
4122
|
+
return true;
|
|
4123
|
+
}
|
|
4124
|
+
const session = state.session;
|
|
4125
|
+
if (!session)
|
|
4126
|
+
return false;
|
|
4127
|
+
const patchResult = session.dispatch({
|
|
4128
|
+
type: 'document.patch',
|
|
4129
|
+
label: patch.label ?? result.status,
|
|
4130
|
+
patch: patch.patch,
|
|
4131
|
+
targetId: session.getState().selection.activeId ?? undefined,
|
|
4132
|
+
});
|
|
4133
|
+
if (!patchResult.documentChanged)
|
|
4134
|
+
return false;
|
|
4135
|
+
if (doesMarkerGraphCommandDeleteRelation(result.command, state.activeMarkerRelationId)) {
|
|
4136
|
+
state.activeMarkerRelationId = null;
|
|
4137
|
+
}
|
|
4138
|
+
if (!isMarkerRelationStillPresent(options, patchResult.workingDocument, state.activeMarkerRelationId)) {
|
|
4139
|
+
state.activeMarkerRelationId = null;
|
|
4140
|
+
}
|
|
4141
|
+
state.markerRelationPick = null;
|
|
4142
|
+
syncMarkerOverlayToSceneArtifacts(state, options, patchResult.selection);
|
|
4143
|
+
state.gizmo?.refreshSelection();
|
|
4144
|
+
state.summary = summarizeDocument(options, patchResult.workingDocument, session.getSource());
|
|
4145
|
+
state.status = patch.label ?? result.status;
|
|
4146
|
+
state.statusTone = result.statusTone;
|
|
4147
|
+
state.statusToneStatus = state.status;
|
|
4148
|
+
state.statusDetails = '';
|
|
4149
|
+
return true;
|
|
4150
|
+
}
|
|
4151
|
+
function createMarkerRelationPickEndpoint(kind, id) {
|
|
4152
|
+
const endpointKind = kind?.trim();
|
|
4153
|
+
const endpointId = id?.trim();
|
|
4154
|
+
if (!endpointKind || !endpointId)
|
|
4155
|
+
return null;
|
|
4156
|
+
if (endpointKind !== 'marker' && endpointKind !== 'scene-object')
|
|
4157
|
+
return null;
|
|
4158
|
+
return { kind: endpointKind, id: endpointId };
|
|
4159
|
+
}
|
|
4160
|
+
function formatMarkerRelationPickEndpointLabel(endpoint, graph, hierarchy) {
|
|
4161
|
+
const label = endpoint.kind === 'marker'
|
|
4162
|
+
? findSpatialMarkerById(graph, endpoint.id)?.label ?? endpoint.id
|
|
4163
|
+
: hierarchy.find(item => item.id === endpoint.id)?.label ?? endpoint.id;
|
|
4164
|
+
const kindLabel = endpoint.kind === 'marker' ? '标记' : '对象';
|
|
4165
|
+
return `${kindLabel} ${label}`;
|
|
4166
|
+
}
|
|
4167
|
+
function doesMarkerGraphCommandDeleteRelation(command, relationId) {
|
|
4168
|
+
if (!relationId)
|
|
4169
|
+
return false;
|
|
4170
|
+
switch (command.type) {
|
|
4171
|
+
case 'relation.delete':
|
|
4172
|
+
return command.relationId === relationId;
|
|
4173
|
+
case 'relation.delete-many':
|
|
4174
|
+
return command.relationIds.includes(relationId);
|
|
4175
|
+
default:
|
|
4176
|
+
return false;
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
function isMarkerRelationStillPresent(options, document, relationId) {
|
|
4180
|
+
if (!relationId)
|
|
4181
|
+
return true;
|
|
4182
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
4183
|
+
return !!graph?.relations.some(relation => relation.id === relationId);
|
|
4184
|
+
}
|
|
4185
|
+
function createMarkerTypeCatalogCommand(input) {
|
|
4186
|
+
const type = input.type.trim();
|
|
4187
|
+
if (!type)
|
|
4188
|
+
return null;
|
|
4189
|
+
if (input.action === 'delete') {
|
|
4190
|
+
return {
|
|
4191
|
+
type: 'marker-type.delete',
|
|
4192
|
+
typeId: type,
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
const label = input.label?.trim() || type;
|
|
4196
|
+
const kind = input.kind?.trim() || undefined;
|
|
4197
|
+
const description = 'description' in input ? input.description?.trim() ?? '' : undefined;
|
|
4198
|
+
if (input.action === 'create') {
|
|
4199
|
+
return {
|
|
4200
|
+
type: 'marker-type.create',
|
|
4201
|
+
definition: {
|
|
4202
|
+
type,
|
|
4203
|
+
label,
|
|
4204
|
+
...(kind ? { kind } : {}),
|
|
4205
|
+
...(description ? { description } : {}),
|
|
4206
|
+
},
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
return {
|
|
4210
|
+
type: 'marker-type.update',
|
|
4211
|
+
typeId: type,
|
|
4212
|
+
patch: {
|
|
4213
|
+
label,
|
|
4214
|
+
...(kind !== undefined ? { kind } : {}),
|
|
4215
|
+
...(description !== undefined ? { description } : {}),
|
|
4216
|
+
},
|
|
4217
|
+
};
|
|
4218
|
+
}
|
|
2477
4219
|
function patchHierarchyItemEnabled(state, options, input) {
|
|
4220
|
+
const markerVisibilityResult = patchMarkerGraphHierarchyVisibility(state, options, input);
|
|
4221
|
+
if (markerVisibilityResult !== 'unhandled')
|
|
4222
|
+
return markerVisibilityResult === 'changed';
|
|
2478
4223
|
return patchSerializedProperty(state, options, {
|
|
2479
4224
|
targetId: input.id,
|
|
2480
4225
|
path: 'enabled',
|
|
@@ -2486,6 +4231,47 @@ function patchHierarchyItemEnabled(state, options, input) {
|
|
|
2486
4231
|
source: 'toggle',
|
|
2487
4232
|
});
|
|
2488
4233
|
}
|
|
4234
|
+
function patchMarkerGraphHierarchyVisibility(state, options, input) {
|
|
4235
|
+
const document = state.session?.getState().workingDocument ?? null;
|
|
4236
|
+
if (!document)
|
|
4237
|
+
return 'unhandled';
|
|
4238
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
4239
|
+
if (!graph)
|
|
4240
|
+
return 'unhandled';
|
|
4241
|
+
const hierarchy = options.documentAdapter.getHierarchyItems(document);
|
|
4242
|
+
const visibility = state.markerGraphVisibility;
|
|
4243
|
+
if (isMarkerGraphHierarchyRootRowId(graph, input.id, hierarchy)) {
|
|
4244
|
+
if (visibility.rootVisible === input.enabled)
|
|
4245
|
+
return 'handled';
|
|
4246
|
+
visibility.rootVisible = input.enabled;
|
|
4247
|
+
state.editorStateRevision += 1;
|
|
4248
|
+
syncCurrentSelectionToSceneArtifacts(state, options, 'marker-graph-visibility-toggle', state.editorStateRevision);
|
|
4249
|
+
state.status = input.enabled ? 'Markers shown' : 'Markers hidden';
|
|
4250
|
+
state.statusTone = 'success';
|
|
4251
|
+
state.statusToneStatus = state.status;
|
|
4252
|
+
state.statusDetails = '';
|
|
4253
|
+
return 'changed';
|
|
4254
|
+
}
|
|
4255
|
+
const markerId = readMarkerGraphHierarchyMarkerIdForGraph(graph, input.id, hierarchy)
|
|
4256
|
+
?? (isSpatialMarkerBackedByHierarchyRow(graph, input.id, hierarchy) ? input.id : null);
|
|
4257
|
+
if (!markerId)
|
|
4258
|
+
return 'unhandled';
|
|
4259
|
+
const changed = input.enabled
|
|
4260
|
+
? visibility.hiddenMarkerIds.delete(markerId)
|
|
4261
|
+
: !visibility.hiddenMarkerIds.has(markerId);
|
|
4262
|
+
if (!input.enabled)
|
|
4263
|
+
visibility.hiddenMarkerIds.add(markerId);
|
|
4264
|
+
if (!changed)
|
|
4265
|
+
return 'handled';
|
|
4266
|
+
state.editorStateRevision += 1;
|
|
4267
|
+
syncCurrentSelectionToSceneArtifacts(state, options, 'marker-visibility-toggle', state.editorStateRevision);
|
|
4268
|
+
const marker = findSpatialMarkerById(graph, markerId);
|
|
4269
|
+
state.status = `${marker?.label ?? markerId} ${input.enabled ? 'shown' : 'hidden'}`;
|
|
4270
|
+
state.statusTone = 'success';
|
|
4271
|
+
state.statusToneStatus = state.status;
|
|
4272
|
+
state.statusDetails = '';
|
|
4273
|
+
return 'changed';
|
|
4274
|
+
}
|
|
2489
4275
|
async function applyRenderingPropertyChange(state, options, input) {
|
|
2490
4276
|
if (state.mode !== 'editor')
|
|
2491
4277
|
return false;
|
|
@@ -2547,17 +4333,26 @@ async function applyRenderingPropertyChange(state, options, input) {
|
|
|
2547
4333
|
}
|
|
2548
4334
|
}
|
|
2549
4335
|
async function applyRenderingAction(state, options, input, render) {
|
|
2550
|
-
if (state.mode !== 'editor')
|
|
2551
|
-
return false;
|
|
2552
|
-
|
|
2553
|
-
|
|
4336
|
+
if (state.mode !== 'editor') {
|
|
4337
|
+
return { ok: false, changed: false, rendered: false, status: 'Editor is not in edit mode.', statusTone: 'warning' };
|
|
4338
|
+
}
|
|
4339
|
+
if (!state.session || !options.documentAdapter.onRenderingAction) {
|
|
4340
|
+
return { ok: false, changed: false, rendered: false, status: 'Rendering action pipeline is unavailable.', statusTone: 'warning' };
|
|
4341
|
+
}
|
|
2554
4342
|
if (state.renderingAction) {
|
|
2555
4343
|
state.status = state.renderingAction.status ?? `Rendering action already running: ${state.renderingAction.actionId}`;
|
|
2556
4344
|
state.statusTone = state.renderingAction.statusTone ?? 'default';
|
|
2557
4345
|
state.statusToneStatus = state.status;
|
|
2558
4346
|
state.statusDetails = state.renderingAction.statusDetails ?? '';
|
|
2559
4347
|
render();
|
|
2560
|
-
return
|
|
4348
|
+
return {
|
|
4349
|
+
ok: false,
|
|
4350
|
+
changed: false,
|
|
4351
|
+
rendered: true,
|
|
4352
|
+
status: state.status,
|
|
4353
|
+
statusTone: state.statusTone,
|
|
4354
|
+
...(state.statusDetails ? { statusDetails: state.statusDetails } : {}),
|
|
4355
|
+
};
|
|
2561
4356
|
}
|
|
2562
4357
|
const document = state.session.getState().workingDocument;
|
|
2563
4358
|
const progressStartedAt = Date.now();
|
|
@@ -2606,6 +4401,7 @@ async function applyRenderingAction(state, options, input, render) {
|
|
|
2606
4401
|
|| resultObject?.changed === true
|
|
2607
4402
|
|| resultObject?.refreshWorldRendering === true
|
|
2608
4403
|
|| documentPatchResult?.changed === true;
|
|
4404
|
+
const rendered = changed || !!resultObject?.status;
|
|
2609
4405
|
if (resultObject?.status) {
|
|
2610
4406
|
state.status = resultObject.status;
|
|
2611
4407
|
state.statusTone = resultObject.statusTone ?? 'default';
|
|
@@ -2629,7 +4425,15 @@ async function applyRenderingAction(state, options, input, render) {
|
|
|
2629
4425
|
invalidateEditorScene(state, 'rendering-panel-action', options);
|
|
2630
4426
|
}
|
|
2631
4427
|
clearRenderingActionAfterMinimumDuration(state, progressStartedAt, input.actionId, render);
|
|
2632
|
-
return
|
|
4428
|
+
return {
|
|
4429
|
+
ok: resultObject?.statusTone !== 'error',
|
|
4430
|
+
changed,
|
|
4431
|
+
rendered,
|
|
4432
|
+
...(state.status ? { status: state.status } : {}),
|
|
4433
|
+
statusTone: state.statusTone,
|
|
4434
|
+
...(state.statusDetails ? { statusDetails: state.statusDetails } : {}),
|
|
4435
|
+
...(resultObject?.details ? { details: resultObject.details } : {}),
|
|
4436
|
+
};
|
|
2633
4437
|
}
|
|
2634
4438
|
catch (error) {
|
|
2635
4439
|
state.renderingAction = null;
|
|
@@ -2638,7 +4442,15 @@ async function applyRenderingAction(state, options, input, render) {
|
|
|
2638
4442
|
state.statusToneStatus = state.status;
|
|
2639
4443
|
state.statusDetails = state.status;
|
|
2640
4444
|
console.error('[LocalEditorHarness] rendering action failed', error);
|
|
2641
|
-
return
|
|
4445
|
+
return {
|
|
4446
|
+
ok: false,
|
|
4447
|
+
changed: false,
|
|
4448
|
+
rendered: true,
|
|
4449
|
+
status: state.status,
|
|
4450
|
+
statusTone: 'error',
|
|
4451
|
+
statusDetails: state.statusDetails,
|
|
4452
|
+
error: state.status,
|
|
4453
|
+
};
|
|
2642
4454
|
}
|
|
2643
4455
|
}
|
|
2644
4456
|
function clearRenderingActionAfterMinimumDuration(state, startedAt, actionId, render) {
|
|
@@ -2735,6 +4547,11 @@ function findInspectorPropertyForEdit(state, options, document, input, targetIds
|
|
|
2735
4547
|
return findInspectorPropertyByPath(inspector, input.path);
|
|
2736
4548
|
}
|
|
2737
4549
|
function createInspectorObjectForEdit(state, options, document, input, targetIds) {
|
|
4550
|
+
if (targetIds.length === 1 && state.prefabStage) {
|
|
4551
|
+
const inspector = createPrefabStageInspectorObjectForEdit(state, options, document);
|
|
4552
|
+
if (inspector && inspector.targetIds.includes(input.targetId))
|
|
4553
|
+
return inspector;
|
|
4554
|
+
}
|
|
2738
4555
|
if (targetIds.length > 1) {
|
|
2739
4556
|
const activeId = state.session?.getState().selection.activeId ?? input.targetId ?? null;
|
|
2740
4557
|
const inspector = createInspectorMultiObjectBase(state, options, document, targetIds, activeId);
|
|
@@ -2742,6 +4559,9 @@ function createInspectorObjectForEdit(state, options, document, input, targetIds
|
|
|
2742
4559
|
return withDefaultEditorInspectorSections(state, options, document, inspector);
|
|
2743
4560
|
return null;
|
|
2744
4561
|
}
|
|
4562
|
+
const markerInspector = createMarkerInspectorObjectBase(options, document, input.targetId);
|
|
4563
|
+
if (markerInspector)
|
|
4564
|
+
return markerInspector;
|
|
2745
4565
|
const inspector = options.documentAdapter.getInspectorObject?.(document, input.targetId) ?? null;
|
|
2746
4566
|
if (inspector)
|
|
2747
4567
|
return withDefaultEditorInspectorSections(state, options, document, inspector);
|
|
@@ -2750,6 +4570,13 @@ function createInspectorObjectForEdit(state, options, document, input, targetIds
|
|
|
2750
4570
|
? withDefaultEditorInspectorSections(state, options, document, serializedObjectToInspectorObject(serializedObject, document))
|
|
2751
4571
|
: null;
|
|
2752
4572
|
}
|
|
4573
|
+
function createPrefabStageInspectorObjectForEdit(state, options, document) {
|
|
4574
|
+
const stage = state.prefabStage;
|
|
4575
|
+
if (!stage || !options.documentAdapter.getPrefabStageInspectorObject)
|
|
4576
|
+
return null;
|
|
4577
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? stage.descriptor;
|
|
4578
|
+
return options.documentAdapter.getPrefabStageInspectorObject(document, descriptor, stage.selectedItemId, createPrefabStageContext(state, descriptor)) ?? null;
|
|
4579
|
+
}
|
|
2753
4580
|
function findInspectorPropertyByPath(inspector, path) {
|
|
2754
4581
|
for (const section of inspector.sections) {
|
|
2755
4582
|
const property = section.properties.find(candidate => candidate.path === path);
|
|
@@ -2793,14 +4620,28 @@ function isSerializedTransformPath(path) {
|
|
|
2793
4620
|
|| path.startsWith('transform.scale.');
|
|
2794
4621
|
}
|
|
2795
4622
|
function isSerializedProjectionMetadataPath(path) {
|
|
2796
|
-
return path
|
|
4623
|
+
return isSerializedShadowMetadataPath(path);
|
|
4624
|
+
}
|
|
4625
|
+
function isSerializedShadowMetadataPath(path) {
|
|
4626
|
+
return path === 'shadowMode' || path.startsWith('shadow.');
|
|
4627
|
+
}
|
|
4628
|
+
function isSerializedShadowTopologyMetadataPath(path) {
|
|
4629
|
+
return path === 'shadowMode'
|
|
4630
|
+
|| path === 'shadow.cast'
|
|
4631
|
+
|| path === 'shadow.receive'
|
|
4632
|
+
|| path === 'shadow.mode'
|
|
4633
|
+
|| path === 'shadow.quality'
|
|
4634
|
+
|| path === 'shadow.light.mode'
|
|
4635
|
+
|| path === 'shadow.light.lightId'
|
|
4636
|
+
|| path.startsWith('shadow.light.');
|
|
2797
4637
|
}
|
|
2798
4638
|
function beginDuplicateDrag(state, options, input) {
|
|
2799
4639
|
if (state.mode !== 'editor' || !state.session)
|
|
2800
4640
|
return null;
|
|
2801
4641
|
if (state.duplicateDrag)
|
|
2802
4642
|
return null;
|
|
2803
|
-
const
|
|
4643
|
+
const session = state.session;
|
|
4644
|
+
const document = session.getState().workingDocument;
|
|
2804
4645
|
const patch = options.documentAdapter.createDuplicateSelectionPatch?.({
|
|
2805
4646
|
document,
|
|
2806
4647
|
targetIds: input.targetIds,
|
|
@@ -2811,9 +4652,9 @@ function beginDuplicateDrag(state, options, input) {
|
|
|
2811
4652
|
state.status = 'Duplicate drag rejected';
|
|
2812
4653
|
return null;
|
|
2813
4654
|
}
|
|
2814
|
-
const originalSelection =
|
|
4655
|
+
const originalSelection = session.getSelection();
|
|
2815
4656
|
const projectionImpact = resolveProjectionImpact(patch, createDuplicateProjectionImpact(patch));
|
|
2816
|
-
const result =
|
|
4657
|
+
const result = session.dispatch({
|
|
2817
4658
|
type: 'document.patch',
|
|
2818
4659
|
label: patch.label ?? `Duplicate ${input.targetIds.length} object(s)`,
|
|
2819
4660
|
patch: patch.patch,
|
|
@@ -2854,7 +4695,7 @@ function beginDuplicateDrag(state, options, input) {
|
|
|
2854
4695
|
})) {
|
|
2855
4696
|
rebuildProjectionFromDocument(state, options, result.workingDocument, selectionResult.selection);
|
|
2856
4697
|
}
|
|
2857
|
-
state.summary = summarizeDocument(options, result.workingDocument,
|
|
4698
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
2858
4699
|
state.status = patch.label ?? `Duplicated ${createdIds.length} object(s)`;
|
|
2859
4700
|
return {
|
|
2860
4701
|
targetIds: createdIds,
|
|
@@ -2883,7 +4724,12 @@ function cancelDuplicateDrag(state, options) {
|
|
|
2883
4724
|
function commitGizmoTransform(state, options, event) {
|
|
2884
4725
|
if (state.mode !== 'editor' || !state.session)
|
|
2885
4726
|
return false;
|
|
4727
|
+
if (state.prefabStage)
|
|
4728
|
+
return commitPrefabStageGizmoTransform(state, options, event);
|
|
2886
4729
|
const document = state.session.getState().workingDocument;
|
|
4730
|
+
const markerChanged = commitMarkerGizmoTransform(state, options, document, event);
|
|
4731
|
+
if (markerChanged !== null)
|
|
4732
|
+
return markerChanged;
|
|
2887
4733
|
if (isTransformBatchCommit(event)) {
|
|
2888
4734
|
const patch = options.documentAdapter.createTransformBatchPatch?.({
|
|
2889
4735
|
...event,
|
|
@@ -2933,30 +4779,233 @@ function commitGizmoTransform(state, options, event) {
|
|
|
2933
4779
|
state.status = `Ignored ${event.tool} ${targetId}`;
|
|
2934
4780
|
}
|
|
2935
4781
|
return false;
|
|
2936
|
-
}
|
|
2937
|
-
const
|
|
4782
|
+
}
|
|
4783
|
+
const session = state.session;
|
|
4784
|
+
if (!session)
|
|
4785
|
+
return false;
|
|
4786
|
+
const result = session.dispatch({
|
|
4787
|
+
type: 'document.patch',
|
|
4788
|
+
label: patch.label ?? `${event.tool} ${targetId}`,
|
|
4789
|
+
patch: patch.patch,
|
|
4790
|
+
targetId,
|
|
4791
|
+
...withProjectionImpact(resolveProjectionImpact(patch, patch.reprojectIds?.length
|
|
4792
|
+
? createReprojectProjectionImpact(patch.reprojectIds)
|
|
4793
|
+
: createTransformProjectionImpact([patch.changedId ?? targetId]))),
|
|
4794
|
+
}, {
|
|
4795
|
+
mergeWithPrevious: state.duplicateDrag?.createdIds.includes(targetId) === true,
|
|
4796
|
+
});
|
|
4797
|
+
if (patch.reprojectIds?.length)
|
|
4798
|
+
reprojectProjectionForChangedIds(state, options, result.workingDocument, patch.reprojectIds);
|
|
4799
|
+
else
|
|
4800
|
+
syncProjectionForChangedIds(state, options, result.workingDocument, [patch.changedId ?? targetId]);
|
|
4801
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
4802
|
+
state.status = patch.label ?? `${event.tool} ${targetId}`;
|
|
4803
|
+
state.duplicateDrag = null;
|
|
4804
|
+
return result.documentChanged;
|
|
4805
|
+
}
|
|
4806
|
+
function commitPrefabStageGizmoTransform(state, options, event) {
|
|
4807
|
+
const session = state.session;
|
|
4808
|
+
const document = session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
4809
|
+
if (!state.prefabStage || !session || !document || !options.documentAdapter.createAssetActionPatch)
|
|
4810
|
+
return false;
|
|
4811
|
+
if (isTransformBatchCommit(event)) {
|
|
4812
|
+
restoreBatchTransformPreview(state, event.targets);
|
|
4813
|
+
state.status = 'Ignored Prefab Stage multi-selection transform';
|
|
4814
|
+
state.statusTone = 'warning';
|
|
4815
|
+
state.statusToneStatus = state.status;
|
|
4816
|
+
return false;
|
|
4817
|
+
}
|
|
4818
|
+
const target = resolvePrefabStagePreviewTarget(state, options, document, event.nodeId);
|
|
4819
|
+
if (!target?.selectable || !target.transformable) {
|
|
4820
|
+
state.projection?.setNodeTransformPreview(event.nodeId, event.before);
|
|
4821
|
+
state.status = target?.disabledReason ?? `Ignored ${event.tool} ${event.nodeId}`;
|
|
4822
|
+
state.statusTone = 'warning';
|
|
4823
|
+
state.statusToneStatus = state.status;
|
|
4824
|
+
return false;
|
|
4825
|
+
}
|
|
4826
|
+
const transformActionValue = createPrefabStageTransformActionValue(event.after);
|
|
4827
|
+
if (!transformActionValue) {
|
|
4828
|
+
state.projection?.setNodeTransformPreview(event.nodeId, event.before);
|
|
4829
|
+
state.status = `Ignored ${event.tool} ${target.label ?? target.targetId}: Prefab Stage transform requires TRS data`;
|
|
4830
|
+
state.statusTone = 'warning';
|
|
4831
|
+
state.statusToneStatus = state.status;
|
|
4832
|
+
return false;
|
|
4833
|
+
}
|
|
4834
|
+
const patch = options.documentAdapter.createAssetActionPatch({
|
|
4835
|
+
actionId: 'prefab.node.setTransform',
|
|
4836
|
+
targetPrefabAssetId: state.prefabStage.descriptor.assetId,
|
|
4837
|
+
nodeId: target.targetId,
|
|
4838
|
+
document,
|
|
4839
|
+
asset: null,
|
|
4840
|
+
activeId: target.targetId,
|
|
4841
|
+
selectedIds: [target.targetId],
|
|
4842
|
+
value: transformActionValue,
|
|
4843
|
+
});
|
|
4844
|
+
if (!patch) {
|
|
4845
|
+
state.projection?.setNodeTransformPreview(event.nodeId, event.before);
|
|
4846
|
+
state.status = `Ignored ${event.tool} ${target.label ?? target.targetId}`;
|
|
4847
|
+
state.statusTone = 'warning';
|
|
4848
|
+
state.statusToneStatus = state.status;
|
|
4849
|
+
return false;
|
|
4850
|
+
}
|
|
4851
|
+
const result = session.dispatch({
|
|
4852
|
+
type: 'document.patch',
|
|
4853
|
+
label: patch.label ?? `Set prefab node ${target.targetId} transform`,
|
|
4854
|
+
patch: patch.patch,
|
|
4855
|
+
targetId: target.targetId,
|
|
4856
|
+
...withProjectionImpact(resolveProjectionImpact(patch, patch.reprojectIds?.length
|
|
4857
|
+
? createReprojectProjectionImpact(patch.reprojectIds)
|
|
4858
|
+
: createTransformProjectionImpact([patch.changedId ?? target.targetId]))),
|
|
4859
|
+
});
|
|
4860
|
+
syncProjectionForDispatchResult(state, options, result);
|
|
4861
|
+
rebuildProjectionFromDocument(state, options, result.workingDocument, EMPTY_EDITOR_SELECTION);
|
|
4862
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
4863
|
+
state.status = patch.label ?? `Set prefab node ${target.label ?? target.targetId} transform`;
|
|
4864
|
+
state.statusTone = 'success';
|
|
4865
|
+
state.statusToneStatus = state.status;
|
|
4866
|
+
state.statusDetails = '';
|
|
4867
|
+
syncPrefabStageSelectionFromAssetAction(state, options, {
|
|
4868
|
+
actionId: 'prefab.node.setTransform',
|
|
4869
|
+
}, patch.changedId ?? target.targetId);
|
|
4870
|
+
return result.documentChanged;
|
|
4871
|
+
}
|
|
4872
|
+
function createPrefabStageTransformActionValue(transform) {
|
|
4873
|
+
if (!isEditorTransformTrsSnapshot(transform))
|
|
4874
|
+
return null;
|
|
4875
|
+
return {
|
|
4876
|
+
type: 'Transform',
|
|
4877
|
+
position: cloneEditorTransformVec3(transform.position),
|
|
4878
|
+
rotation: cloneEditorTransformVec3(transform.rotation),
|
|
4879
|
+
scale: cloneEditorTransformVec3(transform.scale),
|
|
4880
|
+
};
|
|
4881
|
+
}
|
|
4882
|
+
function cloneEditorTransformVec3(value) {
|
|
4883
|
+
return { x: value.x, y: value.y, z: value.z };
|
|
4884
|
+
}
|
|
4885
|
+
function commitMarkerGizmoTransform(state, options, document, event) {
|
|
4886
|
+
if (isTransformBatchCommit(event))
|
|
4887
|
+
return null;
|
|
4888
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
4889
|
+
const hierarchy = graph ? options.documentAdapter.getHierarchyItems(document) : [];
|
|
4890
|
+
const markerId = readSpatialMarkerIdFromHierarchySelection(graph, event.nodeId, hierarchy);
|
|
4891
|
+
if (!markerId)
|
|
4892
|
+
return null;
|
|
4893
|
+
if (markerId === event.nodeId)
|
|
4894
|
+
return null;
|
|
4895
|
+
const marker = findSpatialMarkerById(graph, markerId);
|
|
4896
|
+
if (!marker)
|
|
4897
|
+
return false;
|
|
4898
|
+
if (!isEditorTransformTrsSnapshot(event.after)) {
|
|
4899
|
+
state.status = `Ignored ${event.tool} marker ${marker.label}: transform is not editable as TRS`;
|
|
4900
|
+
return false;
|
|
4901
|
+
}
|
|
4902
|
+
if (editorTransformSnapshotsEqual(event.before, event.after)) {
|
|
4903
|
+
state.status = `Unchanged ${event.tool} ${marker.label}`;
|
|
4904
|
+
return false;
|
|
4905
|
+
}
|
|
4906
|
+
const nextPatch = createMarkerTransformPatchFromGizmo(marker, event.after);
|
|
4907
|
+
const patch = options.documentAdapter.createMarkerGraphPatch?.(document, {
|
|
4908
|
+
type: 'marker.update',
|
|
4909
|
+
markerId,
|
|
4910
|
+
patch: nextPatch,
|
|
4911
|
+
});
|
|
4912
|
+
if (!patch) {
|
|
4913
|
+
state.markerOverlay?.setMarkerTransformPreview(event.nodeId, event.before);
|
|
4914
|
+
state.status = `Ignored ${event.tool} marker ${marker.label}`;
|
|
4915
|
+
return false;
|
|
4916
|
+
}
|
|
4917
|
+
const session = state.session;
|
|
4918
|
+
if (!session)
|
|
4919
|
+
return false;
|
|
4920
|
+
const result = session.dispatch({
|
|
2938
4921
|
type: 'document.patch',
|
|
2939
|
-
label: patch.label ?? `${event.tool} ${
|
|
4922
|
+
label: patch.label ?? `${event.tool} marker ${marker.label}`,
|
|
2940
4923
|
patch: patch.patch,
|
|
2941
|
-
targetId,
|
|
2942
|
-
...withProjectionImpact(resolveProjectionImpact(patch, patch.reprojectIds?.length
|
|
2943
|
-
? createReprojectProjectionImpact(patch.reprojectIds)
|
|
2944
|
-
: createTransformProjectionImpact([patch.changedId ?? targetId]))),
|
|
2945
|
-
}, {
|
|
2946
|
-
mergeWithPrevious: state.duplicateDrag?.createdIds.includes(targetId) === true,
|
|
4924
|
+
targetId: event.nodeId,
|
|
2947
4925
|
});
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
state.
|
|
2953
|
-
state.status = patch.label ?? `${event.tool} ${targetId}`;
|
|
2954
|
-
state.duplicateDrag = null;
|
|
4926
|
+
syncProjectionForDispatchResult(state, options, result, patch.changedId ?? markerId);
|
|
4927
|
+
state.gizmo?.refreshSelection();
|
|
4928
|
+
requestEditorSceneFrame(state, 'marker-gizmo-transform');
|
|
4929
|
+
state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
|
|
4930
|
+
state.status = patch.label ?? `${event.tool} marker ${marker.label}`;
|
|
2955
4931
|
return result.documentChanged;
|
|
2956
4932
|
}
|
|
4933
|
+
function createMarkerTransformPatchFromGizmo(marker, transform) {
|
|
4934
|
+
const semanticFrame = createMarkerSemanticFrameFromTransform(marker, transform);
|
|
4935
|
+
if (marker.geometry.kind === 'box') {
|
|
4936
|
+
const nextGeometry = {
|
|
4937
|
+
...marker.geometry,
|
|
4938
|
+
center: { ...transform.position },
|
|
4939
|
+
size: normalizeMarkerBoxSize(transform.scale),
|
|
4940
|
+
};
|
|
4941
|
+
if (marker.geometry.rotation || !editorVec3Equal(transform.rotation, { x: 0, y: 0, z: 0 })) {
|
|
4942
|
+
nextGeometry.rotation = { ...transform.rotation };
|
|
4943
|
+
}
|
|
4944
|
+
else {
|
|
4945
|
+
delete nextGeometry.rotation;
|
|
4946
|
+
}
|
|
4947
|
+
return {
|
|
4948
|
+
geometry: nextGeometry,
|
|
4949
|
+
semanticFrame,
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4952
|
+
if (marker.geometry.kind === 'point') {
|
|
4953
|
+
return {
|
|
4954
|
+
geometry: {
|
|
4955
|
+
...marker.geometry,
|
|
4956
|
+
coordinateSpace: 'world',
|
|
4957
|
+
position: { ...transform.position },
|
|
4958
|
+
},
|
|
4959
|
+
semanticFrame,
|
|
4960
|
+
};
|
|
4961
|
+
}
|
|
4962
|
+
return {
|
|
4963
|
+
semanticFrame,
|
|
4964
|
+
};
|
|
4965
|
+
}
|
|
4966
|
+
function createMarkerSemanticFrameFromTransform(marker, transform) {
|
|
4967
|
+
return {
|
|
4968
|
+
...(marker.semanticFrame ?? {}),
|
|
4969
|
+
origin: { ...transform.position },
|
|
4970
|
+
right: rotateEditorVec3ByEuler({ x: 1, y: 0, z: 0 }, transform.rotation),
|
|
4971
|
+
up: rotateEditorVec3ByEuler({ x: 0, y: 1, z: 0 }, transform.rotation),
|
|
4972
|
+
forward: rotateEditorVec3ByEuler({ x: 0, y: 0, z: 1 }, transform.rotation),
|
|
4973
|
+
label: marker.semanticFrame?.label ?? marker.label,
|
|
4974
|
+
};
|
|
4975
|
+
}
|
|
4976
|
+
function rotateEditorVec3ByEuler(value, rotation) {
|
|
4977
|
+
const cx = Math.cos(rotation.x);
|
|
4978
|
+
const sx = Math.sin(rotation.x);
|
|
4979
|
+
const cy = Math.cos(rotation.y);
|
|
4980
|
+
const sy = Math.sin(rotation.y);
|
|
4981
|
+
const cz = Math.cos(rotation.z);
|
|
4982
|
+
const sz = Math.sin(rotation.z);
|
|
4983
|
+
const afterX = {
|
|
4984
|
+
x: value.x,
|
|
4985
|
+
y: value.y * cx - value.z * sx,
|
|
4986
|
+
z: value.y * sx + value.z * cx,
|
|
4987
|
+
};
|
|
4988
|
+
const afterY = {
|
|
4989
|
+
x: afterX.x * cy + afterX.z * sy,
|
|
4990
|
+
y: afterX.y,
|
|
4991
|
+
z: -afterX.x * sy + afterX.z * cy,
|
|
4992
|
+
};
|
|
4993
|
+
return {
|
|
4994
|
+
x: afterY.x * cz - afterY.y * sz,
|
|
4995
|
+
y: afterY.x * sz + afterY.y * cz,
|
|
4996
|
+
z: afterY.z,
|
|
4997
|
+
};
|
|
4998
|
+
}
|
|
2957
4999
|
function isTransformBatchCommit(event) {
|
|
2958
5000
|
return 'targets' in event;
|
|
2959
5001
|
}
|
|
5002
|
+
function normalizeMarkerBoxSize(size) {
|
|
5003
|
+
return {
|
|
5004
|
+
x: Math.max(0.000001, Math.abs(size.x)),
|
|
5005
|
+
y: Math.max(0.000001, Math.abs(size.y)),
|
|
5006
|
+
z: Math.max(0.000001, Math.abs(size.z)),
|
|
5007
|
+
};
|
|
5008
|
+
}
|
|
2960
5009
|
function restoreBatchTransformPreview(state, targets) {
|
|
2961
5010
|
const transforms = {};
|
|
2962
5011
|
for (const target of targets)
|
|
@@ -2991,11 +5040,38 @@ function cancelActiveOperation(state) {
|
|
|
2991
5040
|
function cancelEditorIntent(state, options) {
|
|
2992
5041
|
if (state.mode !== 'editor')
|
|
2993
5042
|
return false;
|
|
5043
|
+
if (state.markerRelationPick) {
|
|
5044
|
+
state.markerRelationPick = null;
|
|
5045
|
+
state.status = '已取消关系端点拾取。';
|
|
5046
|
+
state.statusTone = 'success';
|
|
5047
|
+
state.statusToneStatus = state.status;
|
|
5048
|
+
state.statusDetails = '';
|
|
5049
|
+
return true;
|
|
5050
|
+
}
|
|
2994
5051
|
if (state.viewportTools.activeUtilityTool === 'measure-distance'
|
|
2995
5052
|
|| state.viewportMeasurement.start
|
|
2996
5053
|
|| state.viewportMeasurement.end) {
|
|
2997
5054
|
return clearViewportMeasurement(state);
|
|
2998
5055
|
}
|
|
5056
|
+
if (state.prefabStage?.selectedItemId) {
|
|
5057
|
+
cancelActiveOperation(state);
|
|
5058
|
+
state.prefabStage = { ...state.prefabStage, selectedItemId: null };
|
|
5059
|
+
state.editorStateRevision += 1;
|
|
5060
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-selection-cancel', state.editorStateRevision);
|
|
5061
|
+
state.status = 'Cleared Prefab Stage selection';
|
|
5062
|
+
state.statusTone = 'default';
|
|
5063
|
+
state.statusToneStatus = state.status;
|
|
5064
|
+
state.statusDetails = '';
|
|
5065
|
+
return true;
|
|
5066
|
+
}
|
|
5067
|
+
if (state.prefabStage) {
|
|
5068
|
+
cancelActiveOperation(state);
|
|
5069
|
+
state.status = 'Canceled Prefab Stage operation';
|
|
5070
|
+
state.statusTone = 'default';
|
|
5071
|
+
state.statusToneStatus = state.status;
|
|
5072
|
+
state.statusDetails = '';
|
|
5073
|
+
return true;
|
|
5074
|
+
}
|
|
2999
5075
|
const selection = state.session?.getSelection();
|
|
3000
5076
|
if (selection && selection.selectedIds.length > 0) {
|
|
3001
5077
|
return dispatchSelectionCommand(state, options, { type: 'selection.clear', label: 'Clear Selection' });
|
|
@@ -3003,9 +5079,17 @@ function cancelEditorIntent(state, options) {
|
|
|
3003
5079
|
cancelActiveOperation(state);
|
|
3004
5080
|
return true;
|
|
3005
5081
|
}
|
|
3006
|
-
function focusSelectedProjection(state) {
|
|
5082
|
+
function focusSelectedProjection(state, options) {
|
|
3007
5083
|
if (state.mode !== 'editor')
|
|
3008
5084
|
return false;
|
|
5085
|
+
if (state.prefabStage) {
|
|
5086
|
+
const activeId = getCurrentPrefabStageProjectionSelection(state, options).activeId;
|
|
5087
|
+
if (!activeId) {
|
|
5088
|
+
state.status = 'Focus failed: no Prefab Stage selection';
|
|
5089
|
+
return true;
|
|
5090
|
+
}
|
|
5091
|
+
return focusPrefabStageProjectionNode(state, options, activeId, 'prefab-stage-focus-selection');
|
|
5092
|
+
}
|
|
3009
5093
|
const activeId = state.session?.getState().selection.activeId ?? null;
|
|
3010
5094
|
if (!activeId) {
|
|
3011
5095
|
state.status = 'Focus failed: no selection';
|
|
@@ -3031,6 +5115,79 @@ function focusProjectionNode(state, nodeId) {
|
|
|
3031
5115
|
requestEditorSceneFrame(state, 'viewport-focus-selection');
|
|
3032
5116
|
return true;
|
|
3033
5117
|
}
|
|
5118
|
+
function frameViewportProjectionNode(state, nodeId) {
|
|
5119
|
+
if (state.mode !== 'editor')
|
|
5120
|
+
return false;
|
|
5121
|
+
const root = state.projection?.getAttachableRoot(nodeId) ?? null;
|
|
5122
|
+
if (!root) {
|
|
5123
|
+
state.status = `Focus failed: missing projection for ${nodeId}`;
|
|
5124
|
+
return false;
|
|
5125
|
+
}
|
|
5126
|
+
const focused = focusEditorViewportSelection(state.world?.camera ?? null, root, {
|
|
5127
|
+
babylon: state.babylon ?? undefined,
|
|
5128
|
+
});
|
|
5129
|
+
state.status = focused
|
|
5130
|
+
? `Focused ${nodeId} · ${formatEditorStatusTime(Date.now())}`
|
|
5131
|
+
: `Focus failed: camera could not frame ${nodeId}`;
|
|
5132
|
+
if (focused)
|
|
5133
|
+
requestEditorSceneFrame(state, 'viewport-focus-object');
|
|
5134
|
+
return focused;
|
|
5135
|
+
}
|
|
5136
|
+
function frameSelectedViewportProjection(state, options) {
|
|
5137
|
+
if (state.mode !== 'editor')
|
|
5138
|
+
return false;
|
|
5139
|
+
if (state.prefabStage) {
|
|
5140
|
+
const activeId = getCurrentPrefabStageProjectionSelection(state, options).activeId;
|
|
5141
|
+
if (!activeId) {
|
|
5142
|
+
state.status = 'Focus failed: no Prefab Stage selection';
|
|
5143
|
+
return false;
|
|
5144
|
+
}
|
|
5145
|
+
return focusPrefabStageProjectionNode(state, options, activeId, 'prefab-stage-frame-selection');
|
|
5146
|
+
}
|
|
5147
|
+
const activeId = state.session?.getState({ cloneDocuments: false }).selection.activeId ?? null;
|
|
5148
|
+
if (!activeId) {
|
|
5149
|
+
state.status = 'Focus failed: no selection';
|
|
5150
|
+
return false;
|
|
5151
|
+
}
|
|
5152
|
+
return frameViewportProjectionNode(state, activeId);
|
|
5153
|
+
}
|
|
5154
|
+
function focusPrefabStageProjectionNode(state, options, projectionNodeId, reason) {
|
|
5155
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
5156
|
+
if (!state.prefabStage || !document)
|
|
5157
|
+
return false;
|
|
5158
|
+
const target = resolvePrefabStagePreviewTarget(state, options, document, projectionNodeId);
|
|
5159
|
+
if (!target?.selectable) {
|
|
5160
|
+
state.status = `Focus failed: ${projectionNodeId} is not an editable Prefab Stage preview target`;
|
|
5161
|
+
return true;
|
|
5162
|
+
}
|
|
5163
|
+
const root = state.projection?.getAttachableRoot(projectionNodeId) ?? null;
|
|
5164
|
+
if (!root) {
|
|
5165
|
+
state.status = `Focus failed: missing projection for ${projectionNodeId}`;
|
|
5166
|
+
return true;
|
|
5167
|
+
}
|
|
5168
|
+
const focused = focusEditorViewportSelection(state.world?.camera ?? null, root, {
|
|
5169
|
+
babylon: state.babylon ?? undefined,
|
|
5170
|
+
});
|
|
5171
|
+
state.status = focused
|
|
5172
|
+
? `Focused ${target.label ?? projectionNodeId} · ${formatEditorStatusTime(Date.now())}`
|
|
5173
|
+
: `Focus failed: camera could not frame ${target.label ?? projectionNodeId}`;
|
|
5174
|
+
if (focused)
|
|
5175
|
+
requestEditorSceneFrame(state, reason);
|
|
5176
|
+
return true;
|
|
5177
|
+
}
|
|
5178
|
+
function focusPrefabStagePreviewProjection(state, reason) {
|
|
5179
|
+
const previewNodeId = state.prefabStage?.descriptor.previewNodeId;
|
|
5180
|
+
if (!previewNodeId)
|
|
5181
|
+
return;
|
|
5182
|
+
const root = state.projection?.getAttachableRoot(previewNodeId) ?? null;
|
|
5183
|
+
if (!root)
|
|
5184
|
+
return;
|
|
5185
|
+
const focused = focusEditorViewportSelection(state.world?.camera ?? null, root, {
|
|
5186
|
+
babylon: state.babylon ?? undefined,
|
|
5187
|
+
});
|
|
5188
|
+
if (focused)
|
|
5189
|
+
requestEditorSceneFrame(state, reason);
|
|
5190
|
+
}
|
|
3034
5191
|
function formatEditorStatusTime(timestamp) {
|
|
3035
5192
|
const date = new Date(timestamp);
|
|
3036
5193
|
const pad = (value) => String(value).padStart(2, '0');
|
|
@@ -3232,6 +5389,10 @@ function applyIncrementalHistoryProjectionImpact(state, options, result, operati
|
|
|
3232
5389
|
function applyIncrementalProjectionImpactToDocument(state, options, input) {
|
|
3233
5390
|
if (!state.projection)
|
|
3234
5391
|
return false;
|
|
5392
|
+
if (state.prefabStage) {
|
|
5393
|
+
rebuildProjectionFromDocument(state, options, input.document, EMPTY_EDITOR_SELECTION);
|
|
5394
|
+
return true;
|
|
5395
|
+
}
|
|
3235
5396
|
const syncTransformIds = uniqueProjectionIds(input.syncTransformIds);
|
|
3236
5397
|
const reprojectIds = uniqueProjectionIds(input.reprojectIds);
|
|
3237
5398
|
const projectNodeIds = uniqueProjectionIds(input.projectNodeIds);
|
|
@@ -3254,13 +5415,14 @@ function applyIncrementalProjectionImpactToDocument(state, options, input) {
|
|
|
3254
5415
|
state.projection.projectNode(projectedNode);
|
|
3255
5416
|
}
|
|
3256
5417
|
for (const projectedNode of reprojectNodes) {
|
|
3257
|
-
state
|
|
5418
|
+
syncProjectionNodeTransformOrReprojectRuntime(state, projectedNode, { forceReproject: true });
|
|
3258
5419
|
}
|
|
3259
5420
|
for (const projectedNode of syncTransformNodes) {
|
|
3260
|
-
state
|
|
5421
|
+
syncProjectionNodeTransformOrReprojectRuntime(state, projectedNode);
|
|
3261
5422
|
}
|
|
5423
|
+
applyPreviewVisibilityStateToProjection(state);
|
|
3262
5424
|
const sanitized = sanitizeSelection(state, options, input.document, input.selection);
|
|
3263
|
-
syncSelectionToProjection(state, sanitized ?? input.selection);
|
|
5425
|
+
syncSelectionToProjection(state, options, sanitized ?? input.selection);
|
|
3264
5426
|
syncEditorWorldAppearanceFromDocument(state, options, input.document, `world-appearance-${input.reason}`);
|
|
3265
5427
|
syncEditorWorldRenderingFromDocument(state, options, input.document, `world-rendering-${input.reason}`, true);
|
|
3266
5428
|
invalidateEditorScene(state, `projection-${input.reason}`, options);
|
|
@@ -3276,27 +5438,53 @@ function resolveProjectionNodes(options, document, ids) {
|
|
|
3276
5438
|
}
|
|
3277
5439
|
return projectedNodes;
|
|
3278
5440
|
}
|
|
5441
|
+
function resolveCurrentEditorProjectionNodes(state, options, document) {
|
|
5442
|
+
if (!state.prefabStage)
|
|
5443
|
+
return options.documentAdapter.getProjectionNodes(document);
|
|
5444
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document);
|
|
5445
|
+
if (!descriptor)
|
|
5446
|
+
return [];
|
|
5447
|
+
return options.documentAdapter.getPrefabStageProjectionNodes?.(document, descriptor) ?? [];
|
|
5448
|
+
}
|
|
3279
5449
|
function rebuildProjectionFromDocument(state, options, document, selection) {
|
|
3280
|
-
state
|
|
3281
|
-
|
|
3282
|
-
|
|
5450
|
+
const nodes = resolveCurrentEditorProjectionNodes(state, options, document);
|
|
5451
|
+
state.projection?.rebuild(nodes);
|
|
5452
|
+
applyPreviewVisibilityStateToProjection(state);
|
|
5453
|
+
if (state.prefabStage) {
|
|
5454
|
+
syncPrefabStageSelectionToProjection(state, options, 'prefab-stage-projection-rebuild');
|
|
5455
|
+
}
|
|
5456
|
+
else {
|
|
5457
|
+
const sanitized = sanitizeSelection(state, options, document, selection);
|
|
5458
|
+
syncSelectionToProjection(state, options, sanitized ?? selection);
|
|
5459
|
+
}
|
|
3283
5460
|
syncEditorWorldAppearanceFromDocument(state, options, document, 'world-appearance-rebuild');
|
|
3284
5461
|
syncEditorWorldRenderingFromDocument(state, options, document, 'world-rendering-rebuild', true);
|
|
5462
|
+
if (state.prefabStage && nodes.length === 0) {
|
|
5463
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document);
|
|
5464
|
+
state.status = `Prefab preview unavailable: ${descriptor?.label ?? state.prefabStage.descriptor.label}`;
|
|
5465
|
+
state.statusTone = 'warning';
|
|
5466
|
+
state.statusToneStatus = state.status;
|
|
5467
|
+
state.statusDetails = 'The prefab source model asset could not be resolved for preview.';
|
|
5468
|
+
}
|
|
3285
5469
|
invalidateEditorScene(state, 'projection-rebuild');
|
|
3286
5470
|
}
|
|
3287
5471
|
function syncProjectionForDispatchResult(state, options, result, changedId) {
|
|
5472
|
+
if (state.prefabStage && result.documentChanged && result.workingDocument) {
|
|
5473
|
+
rebuildProjectionFromDocument(state, options, result.workingDocument, EMPTY_EDITOR_SELECTION);
|
|
5474
|
+
return;
|
|
5475
|
+
}
|
|
3288
5476
|
if (result.documentChanged && changedId && result.workingDocument) {
|
|
3289
5477
|
const projectedNode = options.documentAdapter.getProjectionNode(result.workingDocument, changedId);
|
|
3290
5478
|
if (projectedNode)
|
|
3291
|
-
state
|
|
5479
|
+
syncProjectionNodeTransformOrReprojectRuntime(state, projectedNode);
|
|
3292
5480
|
}
|
|
3293
5481
|
if (result.selectionChanged) {
|
|
3294
|
-
syncSelectionToProjection(state, result.selection ?? { selectedIds: [], activeId: null });
|
|
5482
|
+
syncSelectionToProjection(state, options, result.selection ?? { selectedIds: [], activeId: null });
|
|
3295
5483
|
}
|
|
3296
5484
|
else if (result.documentChanged) {
|
|
3297
5485
|
const selection = state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null };
|
|
3298
5486
|
const sanitized = result.workingDocument ? sanitizeSelection(state, options, result.workingDocument, selection) : null;
|
|
3299
|
-
syncSelectionToProjection(state, sanitized ?? selection);
|
|
5487
|
+
syncSelectionToProjection(state, options, sanitized ?? selection);
|
|
3300
5488
|
}
|
|
3301
5489
|
if (result.documentChanged && result.workingDocument) {
|
|
3302
5490
|
syncEditorWorldAppearanceFromDocument(state, options, result.workingDocument, 'world-appearance-dispatch-result');
|
|
@@ -3307,18 +5495,44 @@ function syncProjectionForDispatchResult(state, options, result, changedId) {
|
|
|
3307
5495
|
}
|
|
3308
5496
|
}
|
|
3309
5497
|
function syncProjectionForChangedIds(state, options, document, changedIds) {
|
|
5498
|
+
if (state.prefabStage) {
|
|
5499
|
+
rebuildProjectionFromDocument(state, options, document, EMPTY_EDITOR_SELECTION);
|
|
5500
|
+
return;
|
|
5501
|
+
}
|
|
3310
5502
|
for (const changedId of changedIds) {
|
|
3311
5503
|
const projectedNode = options.documentAdapter.getProjectionNode(document, changedId);
|
|
3312
5504
|
if (projectedNode)
|
|
3313
|
-
state
|
|
5505
|
+
syncProjectionNodeTransformOrReprojectRuntime(state, projectedNode);
|
|
3314
5506
|
}
|
|
3315
5507
|
const selection = state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null };
|
|
3316
|
-
syncSelectionToProjection(state, selection);
|
|
5508
|
+
syncSelectionToProjection(state, options, selection);
|
|
3317
5509
|
syncEditorWorldAppearanceFromDocument(state, options, document, 'world-appearance-sync-changed-ids');
|
|
3318
5510
|
syncEditorWorldRenderingFromDocument(state, options, document, 'world-rendering-sync-changed-ids', true);
|
|
3319
5511
|
invalidateEditorScene(state, 'projection-sync-changed-ids');
|
|
3320
5512
|
}
|
|
5513
|
+
function syncProjectionNodeTransformOrReprojectRuntime(state, projectedNode, options = {}) {
|
|
5514
|
+
if (!state.projection)
|
|
5515
|
+
return;
|
|
5516
|
+
if (projectedNode.runtimeKind === 'light' && state.projection.syncRuntimeNode(projectedNode)) {
|
|
5517
|
+
state.shadowPreview?.refresh();
|
|
5518
|
+
return;
|
|
5519
|
+
}
|
|
5520
|
+
if (options.forceReproject || projectedNode.runtimeKind === 'light' || shouldReprojectRuntimeProjectionNode(projectedNode)) {
|
|
5521
|
+
state.projection.projectNode(projectedNode);
|
|
5522
|
+
if (projectedNode.runtimeKind === 'light')
|
|
5523
|
+
state.shadowPreview?.refresh();
|
|
5524
|
+
return;
|
|
5525
|
+
}
|
|
5526
|
+
state.projection.syncNodeTransform(projectedNode);
|
|
5527
|
+
}
|
|
5528
|
+
function shouldReprojectRuntimeProjectionNode(projectedNode) {
|
|
5529
|
+
return projectedNode.runtimeKind === 'camera';
|
|
5530
|
+
}
|
|
3321
5531
|
function syncProjectionMetadataForChangedIds(state, options, document, changedIds, syncOptions = {}) {
|
|
5532
|
+
if (state.prefabStage) {
|
|
5533
|
+
rebuildProjectionFromDocument(state, options, document, EMPTY_EDITOR_SELECTION);
|
|
5534
|
+
return;
|
|
5535
|
+
}
|
|
3322
5536
|
for (const changedId of changedIds) {
|
|
3323
5537
|
const projectedNode = options.documentAdapter.getProjectionNode(document, changedId);
|
|
3324
5538
|
if (projectedNode) {
|
|
@@ -3326,7 +5540,7 @@ function syncProjectionMetadataForChangedIds(state, options, document, changedId
|
|
|
3326
5540
|
}
|
|
3327
5541
|
}
|
|
3328
5542
|
const selection = state.session?.getState({ cloneDocuments: false }).selection ?? { selectedIds: [], activeId: null };
|
|
3329
|
-
syncSelectionToProjection(state, selection);
|
|
5543
|
+
syncSelectionToProjection(state, options, selection);
|
|
3330
5544
|
syncEditorWorldAppearanceFromDocument(state, options, document, 'world-appearance-sync-metadata-ids');
|
|
3331
5545
|
if (syncOptions.invalidateStaticShadowArtifact) {
|
|
3332
5546
|
state.shadowPreview?.invalidateStaticProjectedArtifact?.();
|
|
@@ -3342,17 +5556,37 @@ function syncProjectionMetadataForChangedIds(state, options, document, changedId
|
|
|
3342
5556
|
}
|
|
3343
5557
|
invalidateEditorScene(state, 'projection-sync-metadata-ids');
|
|
3344
5558
|
}
|
|
5559
|
+
function rebuildProjectionAfterShadowTopologyMetadataPatch(state, options, document, selection) {
|
|
5560
|
+
rebuildProjectionFromDocument(state, options, document, selection);
|
|
5561
|
+
state.shadowPreview?.invalidateStaticProjectedArtifact?.();
|
|
5562
|
+
scheduleProjectionShadowPreviewRebuild(state, 'projection-shadow-topology-metadata-rebuild');
|
|
5563
|
+
}
|
|
3345
5564
|
function reprojectProjectionForChangedIds(state, options, document, changedIds) {
|
|
5565
|
+
if (state.prefabStage) {
|
|
5566
|
+
rebuildProjectionFromDocument(state, options, document, EMPTY_EDITOR_SELECTION);
|
|
5567
|
+
return;
|
|
5568
|
+
}
|
|
3346
5569
|
for (const changedId of changedIds) {
|
|
3347
5570
|
const projectedNode = options.documentAdapter.getProjectionNode(document, changedId);
|
|
3348
5571
|
if (projectedNode)
|
|
3349
5572
|
state.projection?.projectNode(projectedNode);
|
|
3350
5573
|
}
|
|
3351
|
-
|
|
5574
|
+
applyPreviewVisibilityStateToProjection(state);
|
|
5575
|
+
syncCurrentSelectionToSceneArtifacts(state, options);
|
|
3352
5576
|
syncEditorWorldAppearanceFromDocument(state, options, document, 'world-appearance-reproject-changed-ids');
|
|
3353
5577
|
syncEditorWorldRenderingFromDocument(state, options, document, 'world-rendering-reproject-changed-ids', true);
|
|
3354
5578
|
invalidateEditorScene(state, 'projection-reproject-changed-ids', options);
|
|
3355
5579
|
}
|
|
5580
|
+
function applyPreviewVisibilityStateToProjection(state) {
|
|
5581
|
+
const projection = state.projection;
|
|
5582
|
+
if (!projection?.clearPreviewVisibilityOverrides || !projection.setPreviewVisibilityOverrides)
|
|
5583
|
+
return;
|
|
5584
|
+
projection.clearPreviewVisibilityOverrides();
|
|
5585
|
+
const overrides = state.previewVisibility.overrides;
|
|
5586
|
+
if (Object.keys(overrides).length > 0) {
|
|
5587
|
+
projection.setPreviewVisibilityOverrides(overrides);
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
3356
5590
|
function setSceneCameraPreviewEnabled(state, options, enabled) {
|
|
3357
5591
|
if (!enabled) {
|
|
3358
5592
|
state.sceneCameraPreviewEnabled = false;
|
|
@@ -3376,15 +5610,21 @@ function setSceneCameraPreviewEnabled(state, options, enabled) {
|
|
|
3376
5610
|
}
|
|
3377
5611
|
function setGridVisible(state, visible) {
|
|
3378
5612
|
const nextVisible = visible === true;
|
|
3379
|
-
if (state
|
|
5613
|
+
if (!setGridVisibleForEditorContext(state, nextVisible, 'grid-visible-change'))
|
|
3380
5614
|
return false;
|
|
3381
|
-
state.gridVisible = nextVisible;
|
|
3382
|
-
state.grid?.setVisible(nextVisible);
|
|
3383
5615
|
state.status = nextVisible ? 'Grid visible' : 'Grid hidden';
|
|
3384
5616
|
state.statusTone = 'default';
|
|
3385
5617
|
state.statusToneStatus = state.status;
|
|
3386
5618
|
state.statusDetails = '';
|
|
3387
|
-
|
|
5619
|
+
return true;
|
|
5620
|
+
}
|
|
5621
|
+
function setGridVisibleForEditorContext(state, visible, reason) {
|
|
5622
|
+
const nextVisible = visible === true;
|
|
5623
|
+
if (state.gridVisible === nextVisible)
|
|
5624
|
+
return false;
|
|
5625
|
+
state.gridVisible = nextVisible;
|
|
5626
|
+
state.grid?.setVisible(nextVisible);
|
|
5627
|
+
requestEditorSceneFrame(state, reason);
|
|
3388
5628
|
return true;
|
|
3389
5629
|
}
|
|
3390
5630
|
function syncSceneCameraPreview(state, options) {
|
|
@@ -3414,16 +5654,16 @@ function syncViewportCameraState(state) {
|
|
|
3414
5654
|
projectionMode: cameraState.projectionMode,
|
|
3415
5655
|
};
|
|
3416
5656
|
}
|
|
3417
|
-
function syncViewportSpatialOverlay(state) {
|
|
5657
|
+
function syncViewportSpatialOverlay(state, options) {
|
|
3418
5658
|
const settings = state.viewportTools.overlay;
|
|
3419
5659
|
if (!settings.bounds && !settings.dimensions && !settings.edgeLengths && !settings.anchor) {
|
|
3420
5660
|
state.viewportSpatialOverlay = createEmptyEditorViewportSpatialOverlayState();
|
|
3421
5661
|
return;
|
|
3422
5662
|
}
|
|
3423
5663
|
const overlay = state.sceneViewSpatialOverlay;
|
|
3424
|
-
const selection = state
|
|
3425
|
-
const activeId = selection
|
|
3426
|
-
if (state.mode !== 'editor' || !overlay || !activeId || selection
|
|
5664
|
+
const selection = getCurrentPreviewSelection(state, options);
|
|
5665
|
+
const activeId = selection.activeId;
|
|
5666
|
+
if (state.mode !== 'editor' || !overlay || !activeId || selection.selectedIds.length !== 1) {
|
|
3427
5667
|
state.viewportSpatialOverlay = createEmptyEditorViewportSpatialOverlayState();
|
|
3428
5668
|
return;
|
|
3429
5669
|
}
|
|
@@ -3523,25 +5763,46 @@ function radiansToInspectorDegrees(value) {
|
|
|
3523
5763
|
function createUiState(state, options) {
|
|
3524
5764
|
const sessionState = state.session?.getState({ cloneDocuments: false });
|
|
3525
5765
|
const document = sessionState?.workingDocument ?? null;
|
|
3526
|
-
const
|
|
3527
|
-
const
|
|
3528
|
-
const
|
|
5766
|
+
const documentSelectedIds = sessionState?.selection.selectedIds ?? [];
|
|
5767
|
+
const documentActiveId = sessionState?.selection.activeId ?? null;
|
|
5768
|
+
const scopedPreviewSelection = getScopedPreviewSelectionForUiState(state, options, {
|
|
5769
|
+
selectedIds: documentSelectedIds,
|
|
5770
|
+
activeId: documentActiveId,
|
|
5771
|
+
});
|
|
5772
|
+
const selectedIds = scopedPreviewSelection.selectedIds;
|
|
5773
|
+
const activeId = scopedPreviewSelection.activeId;
|
|
5774
|
+
const largeSelection = isLargeSelection(documentSelectedIds);
|
|
5775
|
+
const transformSelectionIsLarge = isLargeSelection(selectedIds);
|
|
5776
|
+
const markerGraph = document ? options.documentAdapter.getMarkerGraph?.(document) ?? null : null;
|
|
5777
|
+
const markerTypes = document ? options.documentAdapter.getMarkerTypeCatalog?.(document) ?? [] : [];
|
|
5778
|
+
const relationTypes = document ? options.documentAdapter.getRelationTypeCatalog?.(document) ?? [] : [];
|
|
5779
|
+
const documentHierarchy = document ? options.documentAdapter.getHierarchyItems(document) : [];
|
|
5780
|
+
const activeMarkerId = activeId ? readSpatialMarkerIdFromHierarchySelection(markerGraph, activeId, documentHierarchy) : null;
|
|
5781
|
+
const markerRelationVisibility = createMarkerRelationVisibilityOptions(state);
|
|
5782
|
+
const markerInspectorObject = document && activeId
|
|
5783
|
+
? createMarkerInspectorObjectBase(options, document, activeId, markerGraph, documentHierarchy, markerTypes, state.activeMarkerRelationId, state.markerRelationPick, markerRelationVisibility)
|
|
5784
|
+
: null;
|
|
3529
5785
|
const serializedObject = document && activeId && selectedIds.length === 1
|
|
3530
|
-
? options.documentAdapter.getSerializedObject(document, activeId)
|
|
5786
|
+
? markerInspectorObject ? null : options.documentAdapter.getSerializedObject(document, activeId)
|
|
3531
5787
|
: null;
|
|
3532
|
-
const serializedMultiObject = document &&
|
|
3533
|
-
? options.documentAdapter.getSerializedMultiObject?.(document,
|
|
5788
|
+
const serializedMultiObject = document && documentSelectedIds.length > 1 && !largeSelection
|
|
5789
|
+
? options.documentAdapter.getSerializedMultiObject?.(document, documentSelectedIds, documentActiveId) ?? null
|
|
3534
5790
|
: null;
|
|
3535
|
-
const inspectorObjectBase = document && activeId && selectedIds.length === 1
|
|
3536
|
-
?
|
|
5791
|
+
const inspectorObjectBase = document && activeId && (selectedIds.length === 1 || markerInspectorObject)
|
|
5792
|
+
? markerInspectorObject
|
|
5793
|
+
?? options.documentAdapter.getInspectorObject?.(document, activeId)
|
|
5794
|
+
?? (serializedObject ? serializedObjectToInspectorObject(serializedObject, document) : null)
|
|
3537
5795
|
: null;
|
|
3538
|
-
const inspectorMultiObjectBase = document &&
|
|
3539
|
-
? createInspectorMultiObjectBase(state, options, document,
|
|
5796
|
+
const inspectorMultiObjectBase = document && documentSelectedIds.length > 1
|
|
5797
|
+
? createInspectorMultiObjectBase(state, options, document, documentSelectedIds, documentActiveId, serializedMultiObject, {
|
|
3540
5798
|
largeSelection,
|
|
3541
5799
|
})
|
|
3542
5800
|
: null;
|
|
3543
|
-
const
|
|
3544
|
-
?
|
|
5801
|
+
const markerRelationInspectorObjectBase = document && inspectorObjectBase
|
|
5802
|
+
? withMarkerGraphRelationInspectorSection(options, document, inspectorObjectBase, markerGraph, documentHierarchy, markerTypes, relationTypes, state.activeMarkerRelationId, state.markerRelationPick, markerRelationVisibility)
|
|
5803
|
+
: inspectorObjectBase;
|
|
5804
|
+
const inspectorObject = document && markerRelationInspectorObjectBase
|
|
5805
|
+
? withRuntimeInspectorSections(state, options, document, markerRelationInspectorObjectBase)
|
|
3545
5806
|
: inspectorObjectBase;
|
|
3546
5807
|
const inspectorMultiObject = document && inspectorMultiObjectBase
|
|
3547
5808
|
? withRuntimeInspectorSections(state, options, document, inspectorMultiObjectBase)
|
|
@@ -3551,8 +5812,10 @@ function createUiState(state, options) {
|
|
|
3551
5812
|
const documentAssetItems = document
|
|
3552
5813
|
? options.documentAdapter.getBrowserAssetItems?.(document) ?? []
|
|
3553
5814
|
: [];
|
|
3554
|
-
const hierarchy = document
|
|
3555
|
-
|
|
5815
|
+
const hierarchy = document
|
|
5816
|
+
? createMarkerGraphHierarchyItems(documentHierarchy, markerGraph, createMarkerGraphHierarchyVisibility(state))
|
|
5817
|
+
: [];
|
|
5818
|
+
state.performanceObjectCount = document ? countLocalEditorAuthoredObjects(documentHierarchy) : null;
|
|
3556
5819
|
state.performanceStats = createLocalEditorPerformanceStats({
|
|
3557
5820
|
frameStats: state.sceneFrameStats,
|
|
3558
5821
|
runtimeStats: state.performanceMonitor?.readSnapshot() ?? null,
|
|
@@ -3565,6 +5828,7 @@ function createUiState(state, options) {
|
|
|
3565
5828
|
return {
|
|
3566
5829
|
mode: state.mode,
|
|
3567
5830
|
busy: state.busy,
|
|
5831
|
+
agentBridge: state.agentBridgeStatus,
|
|
3568
5832
|
status: state.status,
|
|
3569
5833
|
statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
|
|
3570
5834
|
statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',
|
|
@@ -3591,6 +5855,9 @@ function createUiState(state, options) {
|
|
|
3591
5855
|
renderingAction: state.renderingAction,
|
|
3592
5856
|
}) ?? null
|
|
3593
5857
|
: null,
|
|
5858
|
+
markerPanel: document
|
|
5859
|
+
? createMarkerPanelState(markerGraph, markerTypes, relationTypes, documentHierarchy, activeMarkerId, state.activeMarkerRelationId, state.markerRelationPick, markerRelationVisibility)
|
|
5860
|
+
: null,
|
|
3594
5861
|
boxSelection: state.boxSelection,
|
|
3595
5862
|
coordinateAxes: options.world?.coordinateAxes === false
|
|
3596
5863
|
? null
|
|
@@ -3603,11 +5870,11 @@ function createUiState(state, options) {
|
|
|
3603
5870
|
draggingNodeId: state.gizmo?.getState().draggingNodeId ?? null,
|
|
3604
5871
|
},
|
|
3605
5872
|
transformOperations: {
|
|
3606
|
-
settings: cloneTransformOperationSettings(state
|
|
5873
|
+
settings: cloneTransformOperationSettings(getScopedTransformOperationSettings(state)),
|
|
3607
5874
|
selectedCount: selectedIds.length,
|
|
3608
5875
|
activeId,
|
|
3609
|
-
canAlign: !
|
|
3610
|
-
canDistribute: !
|
|
5876
|
+
canAlign: !transformSelectionIsLarge && selectedIds.length >= 2 && activeId != null && !state.prefabStage,
|
|
5877
|
+
canDistribute: !transformSelectionIsLarge && selectedIds.length >= 3 && !state.prefabStage,
|
|
3611
5878
|
},
|
|
3612
5879
|
viewportTools: cloneEditorViewportToolState(state.viewportTools),
|
|
3613
5880
|
viewportMeasurement: cloneViewportMeasurement(state.viewportMeasurement),
|
|
@@ -3620,6 +5887,7 @@ function createUiState(state, options) {
|
|
|
3620
5887
|
enabled: state.sceneCameraPreviewEnabled,
|
|
3621
5888
|
available: hasSceneCameraPreviewRig(state, options),
|
|
3622
5889
|
},
|
|
5890
|
+
prefabStage: createBrowserPrefabStageState(state, options, document),
|
|
3623
5891
|
grid: {
|
|
3624
5892
|
visible: state.gridVisible,
|
|
3625
5893
|
available: !!state.grid,
|
|
@@ -3635,18 +5903,196 @@ function createUiState(state, options) {
|
|
|
3635
5903
|
: null,
|
|
3636
5904
|
};
|
|
3637
5905
|
}
|
|
5906
|
+
function createBrowserPrefabStageState(state, options, document) {
|
|
5907
|
+
const stage = state.prefabStage;
|
|
5908
|
+
if (!stage || !document)
|
|
5909
|
+
return null;
|
|
5910
|
+
const descriptor = resolvePrefabStageDescriptorForDocument(state, options, document) ?? stage.descriptor;
|
|
5911
|
+
const context = createPrefabStageContext(state, descriptor);
|
|
5912
|
+
const structureItems = options.documentAdapter.getPrefabStageStructure?.(document, descriptor, context)
|
|
5913
|
+
?? createFallbackPrefabStageStructure(descriptor);
|
|
5914
|
+
const inspectorObject = options.documentAdapter.getPrefabStageInspectorObject?.(document, descriptor, stage.selectedItemId, context) ?? null;
|
|
5915
|
+
return {
|
|
5916
|
+
assetId: descriptor.assetId,
|
|
5917
|
+
browserAssetId: descriptor.browserAssetId,
|
|
5918
|
+
label: descriptor.label,
|
|
5919
|
+
sourceAssetId: descriptor.sourceAssetId,
|
|
5920
|
+
sourceAssetGuid: descriptor.sourceAssetGuid,
|
|
5921
|
+
readonly: descriptor.readonly,
|
|
5922
|
+
selectedItemId: stage.selectedItemId,
|
|
5923
|
+
structureItems,
|
|
5924
|
+
inspectorObject,
|
|
5925
|
+
importStructureReady: context.importStructureReady,
|
|
5926
|
+
importStats: createPrefabStageImportStats(context),
|
|
5927
|
+
previewNodeId: descriptor.previewNodeId,
|
|
5928
|
+
comparisonPreviews: createPrefabStageComparisonPreviews(state, descriptor),
|
|
5929
|
+
};
|
|
5930
|
+
}
|
|
5931
|
+
function summarizeAgentBridgePrefabStage(state, options) {
|
|
5932
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
5933
|
+
const stage = createBrowserPrefabStageState(state, options, document);
|
|
5934
|
+
if (!stage)
|
|
5935
|
+
return null;
|
|
5936
|
+
return createAgentBridgePrefabStageState(stage);
|
|
5937
|
+
}
|
|
5938
|
+
function summarizeAgentBridgePrefabStageDetails(state, options) {
|
|
5939
|
+
const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
|
|
5940
|
+
const stage = createBrowserPrefabStageState(state, options, document);
|
|
5941
|
+
if (!stage)
|
|
5942
|
+
return null;
|
|
5943
|
+
return {
|
|
5944
|
+
stage: createAgentBridgePrefabStageState(stage),
|
|
5945
|
+
structureItems: stage.structureItems,
|
|
5946
|
+
inspectorObject: stage.inspectorObject ?? null,
|
|
5947
|
+
};
|
|
5948
|
+
}
|
|
5949
|
+
function createAgentBridgePrefabStageState(stage) {
|
|
5950
|
+
return {
|
|
5951
|
+
assetId: stage.assetId,
|
|
5952
|
+
...(stage.browserAssetId ? { browserAssetId: stage.browserAssetId } : {}),
|
|
5953
|
+
label: stage.label,
|
|
5954
|
+
...(stage.sourceAssetId ? { sourceAssetId: stage.sourceAssetId } : {}),
|
|
5955
|
+
...(stage.sourceAssetGuid ? { sourceAssetGuid: stage.sourceAssetGuid } : {}),
|
|
5956
|
+
...(stage.previewNodeId ? { previewNodeId: stage.previewNodeId } : {}),
|
|
5957
|
+
selectedItemId: stage.selectedItemId ?? null,
|
|
5958
|
+
...(stage.readonly != null ? { readonly: stage.readonly } : {}),
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
function createAgentBridgePrefabSummaryFromStage(stage) {
|
|
5962
|
+
return {
|
|
5963
|
+
assetId: stage.assetId,
|
|
5964
|
+
...(stage.browserAssetId ? { browserAssetId: stage.browserAssetId } : {}),
|
|
5965
|
+
displayName: stage.label,
|
|
5966
|
+
...(stage.sourceAssetId ? { sourceAssetId: stage.sourceAssetId } : {}),
|
|
5967
|
+
...(stage.sourceAssetGuid ? { sourceAssetGuid: stage.sourceAssetGuid } : {}),
|
|
5968
|
+
...(stage.readonly != null ? { readonly: stage.readonly } : {}),
|
|
5969
|
+
status: 'ready',
|
|
5970
|
+
};
|
|
5971
|
+
}
|
|
5972
|
+
function isSameAgentBridgePrefabStage(left, right) {
|
|
5973
|
+
if (!left || !right)
|
|
5974
|
+
return false;
|
|
5975
|
+
return left.assetId === right.assetId
|
|
5976
|
+
|| (!!left.browserAssetId && left.browserAssetId === right.browserAssetId);
|
|
5977
|
+
}
|
|
5978
|
+
function createPrefabStageContext(state, descriptor) {
|
|
5979
|
+
const previewNodeId = descriptor.previewNodeId;
|
|
5980
|
+
if (!previewNodeId) {
|
|
5981
|
+
return {
|
|
5982
|
+
importStructure: null,
|
|
5983
|
+
importStructureReady: false,
|
|
5984
|
+
};
|
|
5985
|
+
}
|
|
5986
|
+
const projectedNode = state.projection?.getProjectedNode(previewNodeId) ?? null;
|
|
5987
|
+
return {
|
|
5988
|
+
previewNodeId,
|
|
5989
|
+
importStructure: state.projection?.readNodeImportStructure(previewNodeId) ?? null,
|
|
5990
|
+
importStructureReady: !!projectedNode && !projectedNode.loadPromise,
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5993
|
+
function createPrefabStageImportStats(context) {
|
|
5994
|
+
const snapshot = context.importStructure;
|
|
5995
|
+
if (!context.importStructureReady) {
|
|
5996
|
+
return createEmptyPrefabStageImportStats('loading', snapshot);
|
|
5997
|
+
}
|
|
5998
|
+
if (!snapshot) {
|
|
5999
|
+
return createEmptyPrefabStageImportStats('missing', null);
|
|
6000
|
+
}
|
|
6001
|
+
const nodes = snapshot.nodes ?? [];
|
|
6002
|
+
return {
|
|
6003
|
+
status: 'ready',
|
|
6004
|
+
projectionNodeId: snapshot.projectionNodeId,
|
|
6005
|
+
...(snapshot.assetId ? { assetId: snapshot.assetId } : {}),
|
|
6006
|
+
...(snapshot.sourceId ? { sourceId: snapshot.sourceId } : {}),
|
|
6007
|
+
nodeCount: nodes.length,
|
|
6008
|
+
transformCount: nodes.filter(node => node.kind === 'root' || node.kind === 'transform').length,
|
|
6009
|
+
meshCount: nodes.filter(node => node.kind === 'mesh').length,
|
|
6010
|
+
materialCount: snapshot.materials?.length ?? 0,
|
|
6011
|
+
textureCount: snapshot.textures?.length ?? 0,
|
|
6012
|
+
animationCount: snapshot.animations?.length ?? 0,
|
|
6013
|
+
};
|
|
6014
|
+
}
|
|
6015
|
+
function createEmptyPrefabStageImportStats(status, snapshot) {
|
|
6016
|
+
return {
|
|
6017
|
+
status,
|
|
6018
|
+
...(snapshot?.projectionNodeId ? { projectionNodeId: snapshot.projectionNodeId } : {}),
|
|
6019
|
+
...(snapshot?.assetId ? { assetId: snapshot.assetId } : {}),
|
|
6020
|
+
...(snapshot?.sourceId ? { sourceId: snapshot.sourceId } : {}),
|
|
6021
|
+
nodeCount: 0,
|
|
6022
|
+
transformCount: 0,
|
|
6023
|
+
meshCount: 0,
|
|
6024
|
+
materialCount: 0,
|
|
6025
|
+
textureCount: 0,
|
|
6026
|
+
animationCount: 0,
|
|
6027
|
+
};
|
|
6028
|
+
}
|
|
6029
|
+
function createPrefabStageComparisonPreviews(state, descriptor) {
|
|
6030
|
+
return PREFAB_STAGE_COMPARISON_PREVIEW_DEFINITIONS.map((definition) => {
|
|
6031
|
+
const projectionNodeId = createPrefabStageComparisonProjectionNodeId(descriptor, definition.nodeIdSuffix);
|
|
6032
|
+
const projectedNode = state.projection?.getProjectedNode(projectionNodeId) ?? null;
|
|
6033
|
+
const status = !descriptor.sourceAssetId || !projectedNode
|
|
6034
|
+
? 'unavailable'
|
|
6035
|
+
: projectedNode.loadPromise
|
|
6036
|
+
? 'loading'
|
|
6037
|
+
: 'ready';
|
|
6038
|
+
return {
|
|
6039
|
+
id: definition.id,
|
|
6040
|
+
label: definition.label,
|
|
6041
|
+
mode: definition.mode,
|
|
6042
|
+
projectionNodeId,
|
|
6043
|
+
status,
|
|
6044
|
+
};
|
|
6045
|
+
});
|
|
6046
|
+
}
|
|
6047
|
+
function createPrefabStageComparisonProjectionNodeId(descriptor, suffix) {
|
|
6048
|
+
const previewNodeId = descriptor.previewNodeId ?? `prefab-stage:${descriptor.assetId}`;
|
|
6049
|
+
return `${previewNodeId}:${suffix}`;
|
|
6050
|
+
}
|
|
6051
|
+
function createFallbackPrefabStageStructure(descriptor) {
|
|
6052
|
+
return [{
|
|
6053
|
+
id: 'prefab-root',
|
|
6054
|
+
label: descriptor.label,
|
|
6055
|
+
kind: 'root',
|
|
6056
|
+
icon: 'prefab',
|
|
6057
|
+
meta: descriptor.assetId,
|
|
6058
|
+
readonly: descriptor.readonly,
|
|
6059
|
+
children: [{
|
|
6060
|
+
id: 'prefab-source',
|
|
6061
|
+
label: 'Source Model',
|
|
6062
|
+
kind: 'source',
|
|
6063
|
+
icon: 'asset',
|
|
6064
|
+
sourceAssetId: descriptor.sourceAssetId,
|
|
6065
|
+
meta: descriptor.sourceAssetId ?? 'Missing source asset',
|
|
6066
|
+
readonly: true,
|
|
6067
|
+
}],
|
|
6068
|
+
}];
|
|
6069
|
+
}
|
|
6070
|
+
function getScopedPreviewSelectionForUiState(state, options, fallbackSelection) {
|
|
6071
|
+
return state.prefabStage
|
|
6072
|
+
? getCurrentPrefabStageProjectionSelection(state, options)
|
|
6073
|
+
: fallbackSelection;
|
|
6074
|
+
}
|
|
6075
|
+
function getCurrentPreviewSelection(state, options) {
|
|
6076
|
+
return getScopedPreviewSelectionForUiState(state, options, state.session?.getState({ cloneDocuments: false }).selection ?? EMPTY_EDITOR_SELECTION);
|
|
6077
|
+
}
|
|
3638
6078
|
function createUiPreviewState(state, options) {
|
|
3639
6079
|
const sessionState = state.session?.getState({ cloneDocuments: false });
|
|
3640
6080
|
const selection = sessionState?.selection;
|
|
3641
6081
|
const document = sessionState?.workingDocument ?? null;
|
|
3642
|
-
const
|
|
3643
|
-
const
|
|
3644
|
-
const
|
|
3645
|
-
|
|
6082
|
+
const documentSelectedIds = selection?.selectedIds ?? [];
|
|
6083
|
+
const documentActiveId = selection?.activeId ?? null;
|
|
6084
|
+
const scopedPreviewSelection = getScopedPreviewSelectionForUiState(state, options, {
|
|
6085
|
+
selectedIds: documentSelectedIds,
|
|
6086
|
+
activeId: documentActiveId,
|
|
6087
|
+
});
|
|
6088
|
+
const selectedIds = scopedPreviewSelection.selectedIds;
|
|
6089
|
+
const activeId = scopedPreviewSelection.activeId;
|
|
6090
|
+
const transformSelectionIsLarge = isLargeSelection(selectedIds);
|
|
6091
|
+
const shouldPreviewInspector = !!state.activeTransformPreview && document && documentActiveId && documentSelectedIds.length === 1;
|
|
3646
6092
|
const inspectorObjectBase = shouldPreviewInspector
|
|
3647
|
-
? options.documentAdapter.getInspectorObject?.(document,
|
|
6093
|
+
? options.documentAdapter.getInspectorObject?.(document, documentActiveId)
|
|
3648
6094
|
?? (() => {
|
|
3649
|
-
const serializedObject = options.documentAdapter.getSerializedObject(document,
|
|
6095
|
+
const serializedObject = options.documentAdapter.getSerializedObject(document, documentActiveId);
|
|
3650
6096
|
return serializedObject ? serializedObjectToInspectorObject(serializedObject, document) : null;
|
|
3651
6097
|
})()
|
|
3652
6098
|
: null;
|
|
@@ -3670,11 +6116,11 @@ function createUiPreviewState(state, options) {
|
|
|
3670
6116
|
draggingNodeId: state.gizmo?.getState().draggingNodeId ?? null,
|
|
3671
6117
|
},
|
|
3672
6118
|
transformOperations: {
|
|
3673
|
-
settings: cloneTransformOperationSettings(state
|
|
6119
|
+
settings: cloneTransformOperationSettings(getScopedTransformOperationSettings(state)),
|
|
3674
6120
|
selectedCount: selectedIds.length,
|
|
3675
6121
|
activeId,
|
|
3676
|
-
canAlign: !
|
|
3677
|
-
canDistribute: !
|
|
6122
|
+
canAlign: !transformSelectionIsLarge && selectedIds.length >= 2 && activeId != null && !state.prefabStage,
|
|
6123
|
+
canDistribute: !transformSelectionIsLarge && selectedIds.length >= 3 && !state.prefabStage,
|
|
3678
6124
|
},
|
|
3679
6125
|
viewportTools: cloneEditorViewportToolState(state.viewportTools),
|
|
3680
6126
|
viewportMeasurement: cloneViewportMeasurement(state.viewportMeasurement),
|
|
@@ -3891,12 +6337,108 @@ function createAggregatedInspectorMultiObjectBase(_state, options, document, sel
|
|
|
3891
6337
|
return aggregatedInspector;
|
|
3892
6338
|
}
|
|
3893
6339
|
function createSingleInspectorObjectBase(options, document, targetId) {
|
|
6340
|
+
const markerInspector = createMarkerInspectorObjectBase(options, document, targetId);
|
|
6341
|
+
if (markerInspector)
|
|
6342
|
+
return markerInspector;
|
|
3894
6343
|
const inspectorObject = options.documentAdapter.getInspectorObject?.(document, targetId) ?? null;
|
|
3895
6344
|
if (inspectorObject)
|
|
3896
|
-
return inspectorObject;
|
|
6345
|
+
return withMarkerGraphRelationInspectorSection(options, document, inspectorObject);
|
|
3897
6346
|
const serializedObject = options.documentAdapter.getSerializedObject(document, targetId);
|
|
3898
6347
|
return serializedObject ? serializedObjectToInspectorObject(serializedObject, document) : null;
|
|
3899
6348
|
}
|
|
6349
|
+
function withMarkerGraphRelationInspectorSection(options, document, inspectorObject, graph = options.documentAdapter.getMarkerGraph?.(document) ?? null, hierarchy = options.documentAdapter.getHierarchyItems(document), markerTypes = options.documentAdapter.getMarkerTypeCatalog?.(document) ?? [], relationTypes = options.documentAdapter.getRelationTypeCatalog?.(document) ?? [], activeRelationId = null, relationPick = null, relationVisibility = {}) {
|
|
6350
|
+
if (inspectorObject.targetIds.length !== 1)
|
|
6351
|
+
return inspectorObject;
|
|
6352
|
+
if (inspectorObject.sections.some(section => section.id === 'markerRelations'))
|
|
6353
|
+
return inspectorObject;
|
|
6354
|
+
if (inspectorObject.sections.some(section => section.properties.some(property => property.path === 'marker.relations.editor'))) {
|
|
6355
|
+
return inspectorObject;
|
|
6356
|
+
}
|
|
6357
|
+
const targetId = inspectorObject.activeId ?? inspectorObject.targetIds[0] ?? null;
|
|
6358
|
+
const markerId = readSpatialMarkerIdFromHierarchySelection(graph, targetId, hierarchy);
|
|
6359
|
+
if (!targetId || !markerId)
|
|
6360
|
+
return inspectorObject;
|
|
6361
|
+
const markerInspector = createMarkerGraphInspectorObject({
|
|
6362
|
+
document,
|
|
6363
|
+
graph,
|
|
6364
|
+
markerId: targetId,
|
|
6365
|
+
hierarchy,
|
|
6366
|
+
markerTypes,
|
|
6367
|
+
relationTypes,
|
|
6368
|
+
activeRelationId,
|
|
6369
|
+
relationPick,
|
|
6370
|
+
relationVisibility,
|
|
6371
|
+
});
|
|
6372
|
+
const relationSection = markerInspector?.sections.find(section => section.id === 'markerRelations') ?? null;
|
|
6373
|
+
if (!relationSection)
|
|
6374
|
+
return inspectorObject;
|
|
6375
|
+
const capabilities = new Set(inspectorObject.selection.capabilities ?? []);
|
|
6376
|
+
capabilities.add('markerGraph');
|
|
6377
|
+
const markerSection = inspectorObject.sections.find(section => section.id === 'marker') ?? null;
|
|
6378
|
+
const sections = markerSection
|
|
6379
|
+
? inspectorObject.sections.map(section => section.id === 'marker'
|
|
6380
|
+
? {
|
|
6381
|
+
...section,
|
|
6382
|
+
properties: [
|
|
6383
|
+
...section.properties,
|
|
6384
|
+
...createIntegratedMarkerRelationProperties(section.properties, relationSection.properties),
|
|
6385
|
+
],
|
|
6386
|
+
}
|
|
6387
|
+
: section)
|
|
6388
|
+
: mergeInspectorSections(inspectorObject.sections, [relationSection], { propertyConflict: 'ignore' });
|
|
6389
|
+
return {
|
|
6390
|
+
...inspectorObject,
|
|
6391
|
+
selection: {
|
|
6392
|
+
...inspectorObject.selection,
|
|
6393
|
+
targetKind: inspectorObject.selection.targetKind ?? 'marker',
|
|
6394
|
+
capabilities: [...capabilities],
|
|
6395
|
+
},
|
|
6396
|
+
sections,
|
|
6397
|
+
};
|
|
6398
|
+
}
|
|
6399
|
+
function createIntegratedMarkerRelationProperties(markerProperties, relationProperties) {
|
|
6400
|
+
const existingPaths = new Set(markerProperties.map(property => property.path));
|
|
6401
|
+
const baseOrder = markerProperties.reduce((maxOrder, property, index) => (Math.max(maxOrder, property.order ?? index)), -1);
|
|
6402
|
+
return relationProperties
|
|
6403
|
+
.filter(property => !existingPaths.has(property.path))
|
|
6404
|
+
.map((property, index) => ({
|
|
6405
|
+
...property,
|
|
6406
|
+
label: formatIntegratedMarkerRelationPropertyLabel(property),
|
|
6407
|
+
order: baseOrder + index + 1,
|
|
6408
|
+
}));
|
|
6409
|
+
}
|
|
6410
|
+
function formatIntegratedMarkerRelationPropertyLabel(property) {
|
|
6411
|
+
switch (property.path) {
|
|
6412
|
+
case 'marker.relations.count': return '关系数量';
|
|
6413
|
+
case 'marker.relations.status': return '关系状态';
|
|
6414
|
+
case 'marker.relations.editor': return '关系';
|
|
6415
|
+
default: return property.label;
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6418
|
+
function createMarkerInspectorObjectBase(options, document, targetId, graph = options.documentAdapter.getMarkerGraph?.(document) ?? null, hierarchy = options.documentAdapter.getHierarchyItems(document), markerTypes = options.documentAdapter.getMarkerTypeCatalog?.(document) ?? [], activeRelationId = null, relationPick = null, relationVisibility = {}) {
|
|
6419
|
+
const virtualMarkerId = readMarkerGraphHierarchyMarkerIdForGraph(graph, targetId, hierarchy);
|
|
6420
|
+
const isVirtualRoot = isMarkerGraphHierarchyRootRowId(graph, targetId, hierarchy);
|
|
6421
|
+
if (!virtualMarkerId && !isVirtualRoot)
|
|
6422
|
+
return null;
|
|
6423
|
+
return createMarkerGraphInspectorObject({
|
|
6424
|
+
document,
|
|
6425
|
+
graph,
|
|
6426
|
+
markerId: targetId,
|
|
6427
|
+
hierarchy,
|
|
6428
|
+
markerTypes,
|
|
6429
|
+
relationTypes: options.documentAdapter.getRelationTypeCatalog?.(document) ?? [],
|
|
6430
|
+
activeRelationId,
|
|
6431
|
+
relationPick,
|
|
6432
|
+
relationVisibility,
|
|
6433
|
+
}) ?? createMarkerGraphRootInspectorObject({
|
|
6434
|
+
document,
|
|
6435
|
+
graph,
|
|
6436
|
+
rootId: targetId,
|
|
6437
|
+
hierarchy,
|
|
6438
|
+
markerTypes,
|
|
6439
|
+
relationTypes: options.documentAdapter.getRelationTypeCatalog?.(document) ?? [],
|
|
6440
|
+
});
|
|
6441
|
+
}
|
|
3900
6442
|
function applyMultiInspectorBatchCapabilityGate(options, document, inspectorObject) {
|
|
3901
6443
|
return options.documentAdapter.createSerializedMultiPropertyPatch
|
|
3902
6444
|
? applyAggregatedBatchInspectorCapabilityGate(options, document, inspectorObject)
|
|
@@ -4225,6 +6767,12 @@ function isDocumentNodeLocked(state, options, id) {
|
|
|
4225
6767
|
return options.documentAdapter.isLocked?.(document, id) ?? false;
|
|
4226
6768
|
}
|
|
4227
6769
|
function isNodeSelectableInDocument(options, document, id) {
|
|
6770
|
+
const graph = options.documentAdapter.getMarkerGraph?.(document) ?? null;
|
|
6771
|
+
const hierarchy = graph ? options.documentAdapter.getHierarchyItems(document) : [];
|
|
6772
|
+
if (isMarkerGraphHierarchyRootRowId(graph, id, hierarchy))
|
|
6773
|
+
return true;
|
|
6774
|
+
if (isMarkerGraphHierarchyId(graph, id, hierarchy))
|
|
6775
|
+
return true;
|
|
4228
6776
|
if (options.documentAdapter.isLocked?.(document, id))
|
|
4229
6777
|
return false;
|
|
4230
6778
|
return options.documentAdapter.isSelectable?.(document, id) ?? true;
|
|
@@ -4246,6 +6794,36 @@ function findAssetByResolvedId(state, options, assetId) {
|
|
|
4246
6794
|
}
|
|
4247
6795
|
return selected?.asset ?? null;
|
|
4248
6796
|
}
|
|
6797
|
+
function findBrowserAssetItemByResolvedId(state, options, document, assetId) {
|
|
6798
|
+
let selected = null;
|
|
6799
|
+
for (const asset of state.assets) {
|
|
6800
|
+
const item = toBrowserAssetItem(options, asset);
|
|
6801
|
+
if (item.id !== assetId && item.assetId !== assetId && resolveAssetId(options, asset) !== assetId)
|
|
6802
|
+
continue;
|
|
6803
|
+
if (!selected || shouldReplaceBrowserAssetItem(selected, item))
|
|
6804
|
+
selected = item;
|
|
6805
|
+
}
|
|
6806
|
+
const documentItem = document ? findDocumentBrowserAssetItemByResolvedId(options, document, assetId) : null;
|
|
6807
|
+
if (documentItem && (!selected || shouldReplaceBrowserAssetItem(selected, documentItem)))
|
|
6808
|
+
selected = documentItem;
|
|
6809
|
+
return selected;
|
|
6810
|
+
}
|
|
6811
|
+
function findAssetOrDocumentBrowserItemByResolvedId(state, options, document, assetId) {
|
|
6812
|
+
return findAssetByResolvedId(state, options, assetId)
|
|
6813
|
+
?? (document ? findDocumentBrowserAssetItemByResolvedId(options, document, assetId) : null);
|
|
6814
|
+
}
|
|
6815
|
+
function findDocumentBrowserAssetItemByResolvedId(options, document, assetId) {
|
|
6816
|
+
let selected = null;
|
|
6817
|
+
for (const item of options.documentAdapter.getBrowserAssetItems?.(document) ?? []) {
|
|
6818
|
+
if (item.id !== assetId && item.assetId !== assetId)
|
|
6819
|
+
continue;
|
|
6820
|
+
if (item.placeable === false || item.disabled === true)
|
|
6821
|
+
continue;
|
|
6822
|
+
if (!selected || shouldReplaceBrowserAssetItem(selected, item))
|
|
6823
|
+
selected = item;
|
|
6824
|
+
}
|
|
6825
|
+
return selected;
|
|
6826
|
+
}
|
|
4249
6827
|
function resolveBrowserAssetItemId(state, options, assetId) {
|
|
4250
6828
|
let selected = null;
|
|
4251
6829
|
for (const asset of state.assets) {
|
|
@@ -4271,6 +6849,7 @@ function toBrowserAssetItem(options, asset) {
|
|
|
4271
6849
|
placeable: asset.placeable,
|
|
4272
6850
|
preview: asset.preview,
|
|
4273
6851
|
material: asset.material,
|
|
6852
|
+
prefab: asset.prefab,
|
|
4274
6853
|
meta: asset.meta,
|
|
4275
6854
|
disabled: asset.disabled ?? asset.placeable === false,
|
|
4276
6855
|
};
|