fix(viewer): stack levels per building (#519)
* fix(viewer): stack levels per building * fix(viewer): recover legacy level ownership
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import { getLevelHeight, type LevelNode, sceneRegistry, useScene } from '@pascal-app/core'
|
||||
import {
|
||||
type BuildingNode,
|
||||
getLevelHeight,
|
||||
type LevelNode,
|
||||
sceneRegistry,
|
||||
useScene,
|
||||
} from '@pascal-app/core'
|
||||
import { useFrame } from '@react-three/fiber'
|
||||
import type { Object3D } from 'three'
|
||||
import { lerp } from 'three/src/math/MathUtils.js'
|
||||
import { applyShadowOnly, clearShadowOnly } from '../../lib/shadow-only'
|
||||
import useViewer from '../../store/use-viewer'
|
||||
import { getLevelBuildingId, getLevelStackPositions } from './level-stacking'
|
||||
|
||||
const EXPLODED_GAP = 5
|
||||
|
||||
@@ -19,31 +26,44 @@ export const LevelSystem = () => {
|
||||
const levelMode = useViewer.getState().levelMode
|
||||
const selectedLevel = useViewer.getState().selection.levelId
|
||||
|
||||
// Collect and sort levels by floor index so we can compute cumulative offsets.
|
||||
// Collect level heights so each building can compute its own cumulative offsets.
|
||||
// Level 0 → Y=0, Level 1 → Y=height(0), Level 2 → Y=height(0)+height(1), etc.
|
||||
type LevelEntry = {
|
||||
levelId: string
|
||||
buildingId: string | null
|
||||
index: number
|
||||
height: number
|
||||
obj: NonNullable<ReturnType<typeof sceneRegistry.nodes.get>>
|
||||
}
|
||||
const entries: LevelEntry[] = []
|
||||
const buildings = Object.values(nodes).filter(
|
||||
(node): node is BuildingNode => node?.type === 'building',
|
||||
)
|
||||
sceneRegistry.byType.level!.forEach((levelId) => {
|
||||
const obj = sceneRegistry.nodes.get(levelId)
|
||||
const level = nodes[levelId as LevelNode['id']]
|
||||
const level = nodes[levelId as LevelNode['id']] as LevelNode | undefined
|
||||
if (obj && level) {
|
||||
entries.push({ levelId, index: (level as any).level ?? 0, obj })
|
||||
entries.push({
|
||||
levelId,
|
||||
buildingId: getLevelBuildingId(levelId, level.parentId, buildings),
|
||||
index: level.level,
|
||||
height: getLevelHeight(
|
||||
levelId,
|
||||
nodes,
|
||||
(wallId) => sceneRegistry.nodes.get(wallId)?.position.y,
|
||||
),
|
||||
obj,
|
||||
})
|
||||
}
|
||||
})
|
||||
entries.sort((a, b) => a.index - b.index)
|
||||
const stackPositions = getLevelStackPositions(entries)
|
||||
|
||||
// Walk sorted levels, accumulating base Y offsets
|
||||
const selectedIndex = selectedLevel
|
||||
? entries.find((e) => e.levelId === selectedLevel)?.index
|
||||
: undefined
|
||||
let cumulativeY = 0
|
||||
for (const { levelId, index, obj } of entries) {
|
||||
const level = nodes[levelId as LevelNode['id']]
|
||||
const baseY = cumulativeY
|
||||
const level = nodes[levelId as LevelNode['id']] as LevelNode | undefined
|
||||
const baseY = stackPositions.get(levelId) ?? 0
|
||||
const explodedExtra = levelMode === 'exploded' ? index * EXPLODED_GAP : 0
|
||||
const targetY = baseY + explodedExtra
|
||||
|
||||
@@ -65,12 +85,6 @@ export const LevelSystem = () => {
|
||||
}
|
||||
obj.visible = !hidden
|
||||
}
|
||||
|
||||
cumulativeY += getLevelHeight(
|
||||
levelId,
|
||||
nodes,
|
||||
(wallId) => sceneRegistry.nodes.get(wallId)?.position.y,
|
||||
)
|
||||
}
|
||||
}, 5) // Using a lower priority so it runs after transforms from other systems have settled
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user