Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
5.4 kB · 171 lines
TSX
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172import { Canvas, useFrame } from "@react-three/fiber";import { PlanetSphere } from "@thorium/components/Starmap/Planet";import { Clouds } from "@thorium/components/Starmap/Planet/Clouds";import Star from "@thorium/components/Starmap/Star/StarMesh";import { useGetStarmapStore } from "@thorium/components/Starmap/starmapStore";import { q } from "@thorium/context/AppContext";import { useCardContext } from "@thorium/context/CardContext";import useAnimationFrame from "@thorium/hooks/useAnimationFrame";import { useStation } from "@thorium/routes/station/useStation";import { cn } from "@thorium/utils/cn";import { useLiveQuery } from "@thorium/utils/live-query/client";import { getNavigationDistance } from "@thorium/utils/starmap/getNavigationDistance";import { Suspense, useRef } from "react";import { Color, type Group } from "three";
function getDistanceLabel(input: { distance: number; unit: string } | null) { if (!input) return "Unknown"; return `${input.distance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, })} ${input.unit}`;}
export const ObjectDetails = () => { const useStarmapStore = useGetStarmapStore(); const selectedObjectIds = useStarmapStore((store) => store.selectedObjectIds);
return ( <div className="panel panel-primary p-2"> {selectedObjectIds[0] ? ( <Suspense fallback={<h3 className="text-2xl">Accessing...</h3>}> <ObjectData objectId={selectedObjectIds[0]} /> </Suspense> ) : ( <h3 className="text-2xl">No Object Selected</h3> )} </div> );};
export const ObjectData = ({ objectId }: { objectId: number | string }) => { const [object, distanceRef] = useObjectData(objectId);
if (!object) return null; return ( <div className="flex items-center gap-2"> <ObjectImage objectImage={object.image} /> <div> <h3 className="text-lg">{object.name}</h3> <h4>{object.classification}</h4> <h4 className="tabular-nums"> <strong>Distance:</strong> <span ref={distanceRef} /> </h4> </div> </div> );};
export function useObjectData(objectId: number | string) { const { shipId } = useStation(); const { cardLoaded } = useCardContext(); const [ship] = q.navigation.ship.useNetRequest({ shipId }); const { interpolate } = useLiveQuery(); const distanceRef = useRef<HTMLSpanElement>(null); const [requestData] = q.navigation.object.useNetRequest({ objectId: Number(objectId) || undefined, shipId, }); const [result] = q.sensors.scanResult.useNetRequest({ objectId: Number(objectId), shipId, }); const object = requestData.object; const objectSystem = requestData.objectSystem; const shipSystem = requestData.shipSystem;
useAnimationFrame(() => { const objectPosition = interpolate(Number(objectId)) || object?.position; if (distanceRef.current && objectPosition) { const shipPosition = interpolate(ship.id); const distance = getNavigationDistance( objectPosition, shipPosition, objectSystem, shipSystem, ); distanceRef.current.innerText = getDistanceLabel(distance); } }, cardLoaded); return [result.identification, distanceRef] as const;}
export function ObjectImage({ objectImage, className,}: { objectImage: NonNullable< Awaited<ReturnType<typeof q.sensors.scanResult.netRequest>>["identification"] >["image"]; className?: string;}) { if (!objectImage) return null; return objectImage.type === "solarSystem" ? null : ( <div className={cn("w-24 h-24 border border-white/30 rounded-xl overflow-hidden", className)}> <Suspense> {objectImage.type === "planet" ? ( <PlanetCanvas cloudMapAsset={objectImage.cloudMapAsset} textureMapAsset={objectImage.textureMapAsset} ringMapAsset={objectImage.ringMapAsset} /> ) : objectImage.type === "star" ? ( <StarCanvas hue={objectImage.hue || 30} isWhite={objectImage.isWhite || false} /> ) : objectImage.type === "ship" ? ( <img draggable="false" alt="" src={objectImage?.vanity} /> ) : null} </Suspense> </div> );}
const PlanetGroup = ({ cloudMapAsset, textureMapAsset,}: { cloudMapAsset?: string | null; ringMapAsset?: string | null; textureMapAsset: string;}) => { const planetRef = useRef<Group>(null); useFrame(() => { if (planetRef.current) { planetRef.current.rotateY(0.002); } }); return ( <group ref={planetRef}> <PlanetSphere texture={textureMapAsset} /> {/* The ring really does not look goood. */} {/* {ringMapAsset && <Rings texture={ringMapAsset} />} */} {cloudMapAsset && <Clouds texture={cloudMapAsset} />} </group> );};const PlanetCanvas = ({ textureMapAsset, ...props}: { cloudMapAsset?: string | null; ringMapAsset?: string | null; textureMapAsset?: string | null;}) => { if (!textureMapAsset) return null; return ( <Canvas camera={{ position: [0, 0, 1.8] }}> <ambientLight intensity={0.2} /> <pointLight position={[0, 0.5, 1.5]} intensity={1} /> <PlanetGroup textureMapAsset={textureMapAsset} {...props} /> </Canvas> );};
const StarCanvas = ({ hue, isWhite }: { hue: number; isWhite: boolean }) => { const color1 = new Color(`hsl(${hue}, 100%, ${isWhite ? 100 : 50}%)`); const color2 = new Color(`hsl(${hue + 20}, 100%, ${isWhite ? 100 : 50}%)`); return ( <Canvas camera={{ position: [0, 0, 1.2] }} className="bg-black"> <Star color1={color1} color2={color2} size={1} noLensFlare showSprite /> </Canvas> );};