import { useFrame } from "@react-three/fiber"; import { keepPreviousData } from "@tanstack/react-query"; import OrbitContainer, { OrbitLine } from "@thorium/components/Starmap/OrbitContainer"; import { planetSpriteScale } from "@thorium/components/Starmap/Planet"; import { PlanetSprite } from "@thorium/components/Starmap/Planet"; import { SolarSystemMap } from "@thorium/components/Starmap/SolarSystemMap"; import { StarSprite } from "@thorium/components/Starmap/Star/StarMesh"; import { StarmapShip } from "@thorium/components/Starmap/StarmapShip"; import { useGetStarmapStore } from "@thorium/components/Starmap/starmapStore"; import SystemLabel from "@thorium/components/Starmap/SystemMarker/SystemLabel"; import { WaypointEntity } from "@thorium/components/Starmap/WaypointEntity"; import { q } from "@thorium/context/AppContext"; import { useStation } from "@thorium/routes/station/useStation"; import { setCursor } from "@thorium/utils/setCursor"; import { getOrbitPosition } from "@thorium/utils/starmap/getOrbitPosition"; import { Coordinates, degToRad, solarRadiusToKilometers } from "@thorium/utils/unitTypes"; import { useEffect, useMemo, useRef } from "react"; import { Suspense } from "react"; import { ErrorBoundary } from "react-error-boundary"; import { Color, type Group } from "three"; export function SolarSystemWrapper() { const { shipId } = useStation(); const useStarmapStore = useGetStarmapStore(); const currentSystem = useStarmapStore((store) => store.currentSystem); const [system] = q.starmapCore.system.useNetRequest( { systemId: currentSystem!, }, { placeholderData: keepPreviousData, enabled: currentSystem !== null }, ); const [starmapEntities] = q.starmapCore.entities.useNetRequest({ systemId: currentSystem, }); const [ship] = q.navigation.ship.useNetRequest({ shipId }); const [waypoints] = q.waypoints.all.useNetRequest({ shipId, active: false, systemId: currentSystem, }); const [autopilot] = q.pilot.autopilot.get.useNetRequest({ shipId }); useEffect(() => { useStarmapStore.getState().currentSystemSet?.(currentSystem); }, [useStarmapStore, currentSystem]); if (currentSystem === null) return null; return ( {starmapEntities.map((entity) => { if (entity.components.isStar) { if (!entity.components.satellite) return null; const size = solarRadiusToKilometers(entity.components.isStar.radius); const color = new Color( `hsl(${entity.components.isStar.hue}, 100%, ${ entity.components.isStar.isWhite ? 100 : 50 }%)`, ); return ( { setCursor("pointer"); }} onPointerOut={() => { setCursor("auto"); }} onClick={() => { if (entity.components.satellite) { const position = getOrbitPosition(entity.components.satellite); useStarmapStore.getState().setCameraFocus(position); } useStarmapStore.setState({ selectedObjectIds: [entity.id] }); }} > ); } if (entity.components.isPlanet) { if (!entity.components.satellite) return null; return ( ) => { useStarmapStore.setState({ selectedObjectIds: [entity.id] }); useStarmapStore.getState().setCameraFocus(position); }} /> ); } return null; })} {ship.position?.parentId === currentSystem && ( <>} onError={(err) => console.error(err)}> )} {waypoints.map((waypoint) => ( <>} onError={(err) => console.error(err)}> ))} ); } function PlanetRenderer({ name, satellite, onClick, }: { name?: string; satellite: { axialTilt: number; semiMajorAxis: number; eccentricity: number; inclination: number; orbitalArc: number; parentId: number | null; }; onClick: (position: Coordinates) => void; }) { const useStarmapStore = useGetStarmapStore(); const currentSystem = useStarmapStore((store) => store.currentSystem); const [starmapEntities] = q.starmapCore.entities.useNetRequest({ systemId: currentSystem, }); const labelRef = useRef(null); const origin = useMemo(() => { const parent = starmapEntities.find((s) => s.id === satellite.parentId)?.components.satellite; if (!parent) return undefined; return getOrbitPosition(parent); }, [starmapEntities, satellite.parentId]); const position = getOrbitPosition({ ...satellite, origin }); const { semiMajorAxis, eccentricity, inclination } = satellite; const radiusY = semiMajorAxis - semiMajorAxis * eccentricity; useFrame(({ camera }) => { if (labelRef.current) { const zoom = camera.position.distanceTo(position) + 500; const zoomedScale = (zoom / 2) * 0.01; labelRef.current.scale.set(zoomedScale, zoomedScale, zoomedScale); labelRef.current.quaternion.copy(camera.quaternion); } }); return ( { setCursor("pointer"); }} onPointerOut={() => { setCursor("auto"); }} onClick={onClick} > {name && ( )} ); }