import { CuboidCollider, RigidBody } from "@react-three/rapier"; import { useMemo, useSyncExternalStore } from "react"; import type { Object3D } from "three"; import { activeDungeonEncounterRevision, subscribeDungeonEncounterSnapshots, } from "../game/dungeonEncounterRuntime"; import { activeDungeonWorldObjectStates } from "../game/dungeonWorldInteraction"; import { dungeonWorldObjectState, type DungeonWorldObjectDefinition, } from "../game/dungeonWorldObjects"; import { DUNGEON_PHYSICAL_COLLISION_GROUPS, DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS, } from "./dungeonLineOfSight"; import { useGameGLTF } from "./useGameGLTF"; function AssetObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) { const gltf = useGameGLTF(definition.visual!.assetUrl!); const visual = useMemo(() => gltf.scene.clone(true), [gltf.scene]); return ; } function ProceduralObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) { const [x, y, z] = definition.halfExtents; const round = definition.kind === "trap" || definition.kind === "ritual" || definition.kind === "trigger"; return ( {round ? : } ); } function WorldObject({ definition, stateId, }: { readonly definition: DungeonWorldObjectDefinition; readonly stateId?: string; }) { const state = dungeonWorldObjectState(definition, stateId); if (!state.visible) return null; const showVisual = definition.visual?.hidden !== true; if (!showVisual && !state.blocksMovement && !state.blocksSight) return null; return ( {state.blocksMovement && ( )} {state.blocksSight && ( )} {showVisual && (definition.visual?.assetUrl ? : )} ); } export function DungeonWorldObjects({ definitions, }: { readonly definitions: readonly DungeonWorldObjectDefinition[]; }) { useSyncExternalStore( subscribeDungeonEncounterSnapshots, activeDungeonEncounterRevision, activeDungeonEncounterRevision, ); const states = activeDungeonWorldObjectStates(); return ( {definitions.map((definition) => ( ))} ); }