scene starting with site and not with building anymore
This commit is contained in:
@@ -49,8 +49,10 @@ function SitePhaseView() {
|
||||
const selectedBuildingId = useViewer((state) => state.selection.buildingId);
|
||||
const setSelection = useViewer((state) => state.setSelection);
|
||||
|
||||
const buildings = rootNodeIds
|
||||
.map((id) => nodes[id])
|
||||
// Get site node and its building children
|
||||
const siteNode = rootNodeIds[0] ? nodes[rootNodeIds[0]] : null;
|
||||
const buildings = (siteNode?.type === 'site' ? siteNode.children : [])
|
||||
.map((child) => typeof child === 'string' ? nodes[child] : child)
|
||||
.filter((node): node is BuildingNode => node?.type === "building");
|
||||
|
||||
if (buildings.length === 0) {
|
||||
@@ -92,8 +94,10 @@ function BuildingSelector() {
|
||||
const selectedBuildingId = useViewer((state) => state.selection.buildingId);
|
||||
const setSelection = useViewer((state) => state.setSelection);
|
||||
|
||||
const buildings = rootNodeIds
|
||||
.map((id) => nodes[id])
|
||||
// Get site node and its building children
|
||||
const siteNode = rootNodeIds[0] ? nodes[rootNodeIds[0]] : null;
|
||||
const buildings = (siteNode?.type === 'site' ? siteNode.children : [])
|
||||
.map((child) => typeof child === 'string' ? nodes[child] : child)
|
||||
.filter((node): node is BuildingNode => node?.type === "building");
|
||||
|
||||
const selectedBuilding = selectedBuildingId
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ThreeEvent } from '@react-three/fiber'
|
||||
import mitt from 'mitt'
|
||||
import type { BuildingNode, CeilingNode, ItemNode, LevelNode, RoofNode, SlabNode, WallNode, ZoneNode } from '../schema'
|
||||
import type { BuildingNode, CeilingNode, ItemNode, LevelNode, RoofNode, SiteNode, SlabNode, WallNode, ZoneNode } from '../schema'
|
||||
import type { AnyNode } from '../schema/types'
|
||||
|
||||
// Base event interfaces
|
||||
@@ -20,6 +20,7 @@ export interface NodeEvent<T extends AnyNode = AnyNode> {
|
||||
|
||||
export type WallEvent = NodeEvent<WallNode>
|
||||
export type ItemEvent = NodeEvent<ItemNode>
|
||||
export type SiteEvent = NodeEvent<SiteNode>
|
||||
export type BuildingEvent = NodeEvent<BuildingNode>
|
||||
export type LevelEvent = NodeEvent<LevelNode>
|
||||
export type ZoneEvent = NodeEvent<ZoneNode>
|
||||
@@ -64,6 +65,7 @@ type CameraControlEvents = {
|
||||
type EditorEvents = GridEvents &
|
||||
NodeEvents<'wall', WallEvent> &
|
||||
NodeEvents<'item', ItemEvent> &
|
||||
NodeEvents<'site', SiteEvent> &
|
||||
NodeEvents<'building', BuildingEvent> &
|
||||
NodeEvents<'level', LevelEvent> &
|
||||
NodeEvents<'zone', ZoneEvent> &
|
||||
|
||||
@@ -8,6 +8,7 @@ export const sceneRegistry = {
|
||||
// Categorized lookups: Type -> Set of IDs
|
||||
// Using a Set is faster for adding/deleting than an Array
|
||||
byType: {
|
||||
site: new Set<string>(),
|
||||
building: new Set<string>(),
|
||||
ceiling: new Set<string>(),
|
||||
level: new Set<string>(),
|
||||
|
||||
@@ -8,6 +8,7 @@ export type {
|
||||
ItemEvent,
|
||||
LevelEvent,
|
||||
NodeEvent,
|
||||
SiteEvent,
|
||||
SlabEvent,
|
||||
WallEvent,
|
||||
ZoneEvent,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { create, type StoreApi, type UseBoundStore } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import { BuildingNode } from '../schema'
|
||||
import { LevelNode } from '../schema/nodes/level'
|
||||
import { SiteNode } from '../schema/nodes/site'
|
||||
import type { AnyNode, AnyNodeId } from '../schema/types'
|
||||
import { isObject } from '../utils/types'
|
||||
import * as nodeActions from './actions/node-actions'
|
||||
@@ -87,25 +88,29 @@ const useScene: UseSceneStore = create<SceneState>()(
|
||||
return // Scene already loaded
|
||||
}
|
||||
|
||||
const building = BuildingNode.parse({
|
||||
children: [],
|
||||
})
|
||||
|
||||
// Create hierarchy: Site → Building → Level
|
||||
const level0 = LevelNode.parse({
|
||||
level: 0,
|
||||
children: [],
|
||||
})
|
||||
|
||||
building.children.push(level0.id)
|
||||
const building = BuildingNode.parse({
|
||||
children: [level0.id],
|
||||
})
|
||||
|
||||
const site = SiteNode.parse({
|
||||
children: [building],
|
||||
})
|
||||
|
||||
// Define all nodes flat
|
||||
const nodes: Record<AnyNodeId, AnyNode> = {
|
||||
[site.id]: site,
|
||||
[building.id]: building,
|
||||
[level0.id]: level0,
|
||||
}
|
||||
|
||||
// Root nodes are the levels
|
||||
const rootNodeIds = [building.id]
|
||||
// Site is the root
|
||||
const rootNodeIds = [site.id]
|
||||
|
||||
set({ nodes, rootNodeIds })
|
||||
},
|
||||
@@ -155,13 +160,44 @@ const useScene: UseSceneStore = create<SceneState>()(
|
||||
onRehydrateStorage: (state) => {
|
||||
console.log('hydrating...')
|
||||
|
||||
// optional
|
||||
return (state, error) => {
|
||||
if (error) {
|
||||
console.log('an error happened during hydration', error)
|
||||
} else {
|
||||
console.log('hydration finished')
|
||||
return
|
||||
}
|
||||
|
||||
if (!state) {
|
||||
console.log('hydration finished - no state')
|
||||
return
|
||||
}
|
||||
|
||||
// Migration: Wrap old scenes (where root is not a SiteNode) in a SiteNode
|
||||
const rootId = state.rootNodeIds?.[0]
|
||||
const rootNode = rootId ? state.nodes[rootId] : null
|
||||
|
||||
if (rootNode && rootNode.type !== 'site') {
|
||||
console.log('Migrating old scene: wrapping in SiteNode')
|
||||
|
||||
// Collect existing root nodes (should be BuildingNode or ItemNode)
|
||||
const existingRoots = (state.rootNodeIds || [])
|
||||
.map(id => state.nodes[id])
|
||||
.filter(node => node?.type === 'building' || node?.type === 'item')
|
||||
|
||||
// Create a new SiteNode with existing roots as children
|
||||
const site = SiteNode.parse({
|
||||
children: existingRoots,
|
||||
})
|
||||
|
||||
// Add site to nodes
|
||||
state.nodes[site.id] = site
|
||||
|
||||
// Update root to be the site
|
||||
state.rootNodeIds = [site.id]
|
||||
|
||||
console.log('Migration complete: scene now has SiteNode as root')
|
||||
}
|
||||
|
||||
console.log('hydration finished')
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ItemRenderer } from './item/item-renderer'
|
||||
import { LevelRenderer } from './level/level-renderer'
|
||||
import { RoofRenderer } from './roof/roof-renderer'
|
||||
import { ScanRenderer } from './scan/scan-renderer'
|
||||
import { SiteRenderer } from './site/site-renderer'
|
||||
import { SlabRenderer } from './slab/slab-renderer'
|
||||
import { WallRenderer } from './wall/wall-renderer'
|
||||
import { ZoneRenderer } from './zone/zone-renderer'
|
||||
@@ -19,6 +20,7 @@ export const NodeRenderer = ({ nodeId }: { nodeId: AnyNode['id'] }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{node.type === 'site' && <SiteRenderer node={node} />}
|
||||
{node.type === 'building' && <BuildingRenderer node={node} />}
|
||||
{node.type === 'ceiling' && <CeilingRenderer node={node} />}
|
||||
{node.type === 'level' && <LevelRenderer node={node} />}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { type SiteNode, useRegistry } from '@pascal-app/core'
|
||||
import { useRef } from 'react'
|
||||
import type { Group } from 'three'
|
||||
import { useNodeEvents } from '../../../hooks/use-node-events'
|
||||
import { NodeRenderer } from '../node-renderer'
|
||||
|
||||
export const SiteRenderer = ({ node }: { node: SiteNode }) => {
|
||||
const ref = useRef<Group>(null!)
|
||||
|
||||
useRegistry(node.id, node.type, ref)
|
||||
const handlers = useNodeEvents(node, 'site')
|
||||
|
||||
return (
|
||||
<group ref={ref} {...handlers}>
|
||||
{node.children.map((child) => (
|
||||
<NodeRenderer key={child.id} nodeId={child.id} />
|
||||
))}
|
||||
</group>
|
||||
)
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
type LevelNode,
|
||||
type RoofEvent,
|
||||
type RoofNode,
|
||||
type SiteEvent,
|
||||
type SiteNode,
|
||||
type SlabEvent,
|
||||
type SlabNode,
|
||||
type WallEvent,
|
||||
@@ -21,6 +23,7 @@ import {
|
||||
import type { ThreeEvent } from '@react-three/fiber'
|
||||
|
||||
type NodeConfig = {
|
||||
site: { node: SiteNode; event: SiteEvent }
|
||||
item: { node: ItemNode; event: ItemEvent }
|
||||
wall: { node: WallNode; event: WallEvent }
|
||||
building: { node: BuildingNode; event: BuildingEvent }
|
||||
|
||||
Reference in New Issue
Block a user