mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-02-25 01:23:57 +00:00
add TorqueScript transpiler and runtime
This commit is contained in:
parent
c8391a1056
commit
7d10fb7dee
49 changed files with 12324 additions and 2075 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import { memo, useEffect, useRef } from "react";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
import { PositionalAudio, Vector3 } from "three";
|
||||
import { ConsoleObject, getPosition, getProperty } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty } from "../mission";
|
||||
import { audioToUrl } from "../loaders";
|
||||
import { useAudio } from "./AudioContext";
|
||||
import { useDebug, useSettings } from "./SettingsProvider";
|
||||
|
|
@ -35,24 +36,16 @@ function getCachedAudioBuffer(
|
|||
export const AudioEmitter = memo(function AudioEmitter({
|
||||
object,
|
||||
}: {
|
||||
object: ConsoleObject;
|
||||
object: TorqueObject;
|
||||
}) {
|
||||
const { debugMode } = useDebug();
|
||||
const fileName = getProperty(object, "fileName")?.value ?? "";
|
||||
const volume = parseFloat(getProperty(object, "volume")?.value ?? "1");
|
||||
const minDistance = parseFloat(
|
||||
getProperty(object, "minDistance")?.value ?? "1",
|
||||
);
|
||||
const maxDistance = parseFloat(
|
||||
getProperty(object, "maxDistance")?.value ?? "1",
|
||||
);
|
||||
const minLoopGap = parseFloat(
|
||||
getProperty(object, "minLoopGap")?.value ?? "0",
|
||||
);
|
||||
const maxLoopGap = parseFloat(
|
||||
getProperty(object, "maxLoopGap")?.value ?? "0",
|
||||
);
|
||||
const is3D = parseInt(getProperty(object, "is3D")?.value ?? "0");
|
||||
const fileName = getProperty(object, "fileName") ?? "";
|
||||
const volume = getProperty(object, "volume") ?? 1;
|
||||
const minDistance = getProperty(object, "minDistance") ?? 1;
|
||||
const maxDistance = getProperty(object, "maxDistance") ?? 1;
|
||||
const minLoopGap = getProperty(object, "minLoopGap") ?? 0;
|
||||
const maxLoopGap = getProperty(object, "maxLoopGap") ?? 0;
|
||||
const is3D = getProperty(object, "is3D") ?? 0;
|
||||
|
||||
const [x, y, z] = getPosition(object);
|
||||
const { scene, camera } = useThree();
|
||||
|
|
|
|||
|
|
@ -1,20 +1,14 @@
|
|||
import { useEffect, useId, useMemo, useRef } from "react";
|
||||
import { PerspectiveCamera } from "@react-three/drei";
|
||||
import { useEffect, useId, useMemo } from "react";
|
||||
import { useCameras } from "./CamerasProvider";
|
||||
import { useSettings } from "./SettingsProvider";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
} from "../mission";
|
||||
import { Quaternion, Vector3 } from "three";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation } from "../mission";
|
||||
import { Vector3 } from "three";
|
||||
|
||||
export function Camera({ object }: { object: ConsoleObject }) {
|
||||
export function Camera({ object }: { object: TorqueObject }) {
|
||||
const { registerCamera, unregisterCamera } = useCameras();
|
||||
const id = useId();
|
||||
|
||||
const dataBlock = getProperty(object, "dataBlock").value;
|
||||
const dataBlock = getProperty(object, "dataBlock");
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
|
|
|
|||
|
|
@ -72,8 +72,6 @@ export function DebugPlaceholder({ color }: { color: string }) {
|
|||
return debugMode ? <ShapePlaceholder color={color} /> : null;
|
||||
}
|
||||
|
||||
export type StaticShapeType = "StaticShape" | "TSStatic" | "Item" | "Turret";
|
||||
|
||||
export const ShapeModel = memo(function ShapeModel() {
|
||||
const { shapeName } = useShapeInfo();
|
||||
const { debugMode } = useDebug();
|
||||
|
|
|
|||
|
|
@ -3,13 +3,8 @@ import { ErrorBoundary } from "react-error-boundary";
|
|||
import { Mesh } from "three";
|
||||
import { useGLTF, useTexture } from "@react-three/drei";
|
||||
import { BASE_URL, interiorTextureToUrl, interiorToUrl } from "../loaders";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { setupColor } from "../textureUtils";
|
||||
import { FloatingLabel } from "./FloatingLabel";
|
||||
import { useDebug } from "./SettingsProvider";
|
||||
|
|
@ -93,9 +88,9 @@ function DebugInteriorPlaceholder() {
|
|||
export const InteriorInstance = memo(function InteriorInstance({
|
||||
object,
|
||||
}: {
|
||||
object: ConsoleObject;
|
||||
object: TorqueObject;
|
||||
}) {
|
||||
const interiorFile = getProperty(object, "interiorFile").value;
|
||||
const interiorFile = getProperty(object, "interiorFile");
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const scale = useMemo(() => getScale(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
import { Suspense, useMemo } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { DebugPlaceholder, ShapeModel, ShapePlaceholder } from "./GenericShape";
|
||||
import { ShapeInfoProvider } from "./ShapeInfoProvider";
|
||||
import { useSimGroup } from "./SimGroup";
|
||||
|
|
@ -61,9 +56,9 @@ const TEAM_NAMES = {
|
|||
2: "Inferno",
|
||||
};
|
||||
|
||||
export function Item({ object }: { object: ConsoleObject }) {
|
||||
export function Item({ object }: { object: TorqueObject }) {
|
||||
const simGroup = useSimGroup();
|
||||
const dataBlock = getProperty(object, "dataBlock").value;
|
||||
const dataBlock = getProperty(object, "dataBlock") ?? "";
|
||||
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const scale = useMemo(() => getScale(object), [object]);
|
||||
|
|
|
|||
|
|
@ -1,21 +1,74 @@
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { loadMission } from "../loaders";
|
||||
import {
|
||||
executeMission,
|
||||
type ParsedMission,
|
||||
type ExecutedMission,
|
||||
} from "../mission";
|
||||
import { createScriptLoader } from "../torqueScript/scriptLoader.browser";
|
||||
import { renderObject } from "./renderObject";
|
||||
import { memo } from "react";
|
||||
import { memo, useEffect, useState } from "react";
|
||||
|
||||
function useMission(name: string) {
|
||||
const loadScript = createScriptLoader();
|
||||
|
||||
function useParsedMission(name: string) {
|
||||
return useQuery({
|
||||
queryKey: ["mission", name],
|
||||
queryKey: ["parsedMission", name],
|
||||
queryFn: () => loadMission(name),
|
||||
});
|
||||
}
|
||||
|
||||
export const Mission = memo(function Mission({ name }: { name: string }) {
|
||||
const { data: mission } = useMission(name);
|
||||
function useExecutedMission(parsedMission: ParsedMission | undefined) {
|
||||
const [executedMission, setExecutedMission] = useState<
|
||||
ExecutedMission | undefined
|
||||
>();
|
||||
|
||||
if (!mission) {
|
||||
useEffect(() => {
|
||||
if (!parsedMission) {
|
||||
setExecutedMission(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear previous mission immediately to avoid rendering with destroyed runtime
|
||||
setExecutedMission(undefined);
|
||||
|
||||
let cancelled = false;
|
||||
let result: ExecutedMission | undefined;
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const executed = await executeMission(parsedMission, { loadScript });
|
||||
if (cancelled) {
|
||||
executed.runtime.destroy();
|
||||
} else {
|
||||
result = executed;
|
||||
setExecutedMission(executed);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!cancelled) {
|
||||
console.error("Failed to execute mission:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
result?.runtime.destroy();
|
||||
};
|
||||
}, [parsedMission]);
|
||||
|
||||
return executedMission;
|
||||
}
|
||||
|
||||
export const Mission = memo(function Mission({ name }: { name: string }) {
|
||||
const { data: parsedMission } = useParsedMission(name);
|
||||
const executedMission = useExecutedMission(parsedMission);
|
||||
|
||||
if (!executedMission) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mission.objects.map((object, i) => renderObject(object, i));
|
||||
return executedMission.objects.map((object, i) => renderObject(object, i));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { createContext, useContext, useMemo } from "react";
|
||||
import { ConsoleObject } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { renderObject } from "./renderObject";
|
||||
|
||||
export type SimGroupContextType = {
|
||||
object: ConsoleObject;
|
||||
object: TorqueObject;
|
||||
parent: SimGroupContextType;
|
||||
hasTeams: boolean;
|
||||
team: null | number;
|
||||
|
|
@ -15,7 +15,7 @@ export function useSimGroup() {
|
|||
return useContext(SimGroupContext);
|
||||
}
|
||||
|
||||
export function SimGroup({ object }: { object: ConsoleObject }) {
|
||||
export function SimGroup({ object }: { object: TorqueObject }) {
|
||||
const parent = useSimGroup();
|
||||
|
||||
const simGroup: SimGroupContextType = useMemo(() => {
|
||||
|
|
@ -26,12 +26,14 @@ export function SimGroup({ object }: { object: ConsoleObject }) {
|
|||
hasTeams = true;
|
||||
if (parent.team != null) {
|
||||
team = parent.team;
|
||||
} else if (object.instanceName) {
|
||||
const match = object.instanceName.match(/^team(\d+)$/i);
|
||||
team = parseInt(match[1], 10);
|
||||
} else if (object._name) {
|
||||
const match = object._name.match(/^team(\d+)$/i);
|
||||
if (match) {
|
||||
team = parseInt(match[1], 10);
|
||||
}
|
||||
}
|
||||
} else if (object.instanceName) {
|
||||
hasTeams = object.instanceName.toLowerCase() === "teams";
|
||||
} else if (object._name) {
|
||||
hasTeams = object._name.toLowerCase() === "teams";
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -49,7 +51,7 @@ export function SimGroup({ object }: { object: ConsoleObject }) {
|
|||
|
||||
return (
|
||||
<SimGroupContext.Provider value={simGroup}>
|
||||
{object.children.map((child, i) => renderObject(child, i))}
|
||||
{(object._children ?? []).map((child, i) => renderObject(child, i))}
|
||||
</SimGroupContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import { Suspense, useMemo, useEffect, useRef } from "react";
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useCubeTexture } from "@react-three/drei";
|
||||
import { Color, ShaderMaterial, BackSide, Euler } from "three";
|
||||
import { ConsoleObject, getProperty, getRotation } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getProperty } from "../mission";
|
||||
import { useSettings } from "./SettingsProvider";
|
||||
import { BASE_URL, getUrlForPath, loadDetailMapList } from "../loaders";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
|
|
@ -139,27 +140,27 @@ export function SkyBox({
|
|||
);
|
||||
}
|
||||
|
||||
export function Sky({ object }: { object: ConsoleObject }) {
|
||||
export function Sky({ object }: { object: TorqueObject }) {
|
||||
const { fogEnabled } = useSettings();
|
||||
|
||||
// Skybox textures.
|
||||
const materialList = getProperty(object, "materialList")?.value;
|
||||
const materialList = getProperty(object, "materialList");
|
||||
|
||||
// Fog parameters.
|
||||
// TODO: There can be multiple fog volumes/layers. Render simple fog for now.
|
||||
const fogDistance = useMemo(() => {
|
||||
const distanceString = getProperty(object, "fogDistance")?.value;
|
||||
if (distanceString) {
|
||||
return parseFloat(distanceString);
|
||||
}
|
||||
return getProperty(object, "fogDistance");
|
||||
}, [object]);
|
||||
|
||||
const fogColor = useMemo(() => {
|
||||
const colorString = getProperty(object, "fogColor")?.value;
|
||||
const colorString = getProperty(object, "fogColor");
|
||||
if (colorString) {
|
||||
// `colorString` might specify an alpha value, but three.js doesn't
|
||||
// support opacity on fog or scene backgrounds, so ignore it.
|
||||
const [r, g, b] = colorString.split(" ").map((s) => parseFloat(s));
|
||||
// Note: This is a space-separated string, so we split and parse each component.
|
||||
const [r, g, b] = colorString
|
||||
.split(" ")
|
||||
.map((s: string) => parseFloat(s));
|
||||
return [
|
||||
new Color().setRGB(r, g, b),
|
||||
new Color().setRGB(r, g, b).convertSRGBToLinear(),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
import { Suspense, useMemo } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { DebugPlaceholder, ShapeModel, ShapePlaceholder } from "./GenericShape";
|
||||
import { ShapeInfoProvider } from "./ShapeInfoProvider";
|
||||
|
||||
|
|
@ -20,6 +15,8 @@ const dataBlockToShapeName = {
|
|||
GeneratorLarge: "station_generator_large.dts",
|
||||
InteriorFlagStand: "int_flagstand.dts",
|
||||
LightMaleHuman_Dead: "light_male_dead.dts",
|
||||
MediumMaleHuman_Dead: "medium_male_dead.dts",
|
||||
HeavyMaleHuman_Dead: "heavy_male_dead.dts",
|
||||
LogoProjector: "teamlogo_projector.dts",
|
||||
SensorLargePulse: "sensor_pulse_large.dts",
|
||||
SensorMediumPulse: "sensor_pulse_medium.dts",
|
||||
|
|
@ -44,8 +41,8 @@ function getDataBlockShape(dataBlock: string) {
|
|||
return _caseInsensitiveLookup[dataBlock.toLowerCase()];
|
||||
}
|
||||
|
||||
export function StaticShape({ object }: { object: ConsoleObject }) {
|
||||
const dataBlock = getProperty(object, "dataBlock").value;
|
||||
export function StaticShape({ object }: { object: TorqueObject }) {
|
||||
const dataBlock = getProperty(object, "dataBlock") ?? "";
|
||||
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,29 @@
|
|||
import { useMemo } from "react";
|
||||
import { Color } from "three";
|
||||
import { ConsoleObject, getProperty } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getProperty } from "../mission";
|
||||
|
||||
export function Sun({ object }: { object: ConsoleObject }) {
|
||||
export function Sun({ object }: { object: TorqueObject }) {
|
||||
const direction = useMemo(() => {
|
||||
const directionStr = getProperty(object, "direction")?.value ?? "0 0 -1";
|
||||
const [x, y, z] = directionStr.split(" ").map((s) => parseFloat(s));
|
||||
const directionStr = getProperty(object, "direction") ?? "0 0 -1";
|
||||
// Note: This is a space-separated string, so we split and parse each component.
|
||||
const [x, y, z] = directionStr.split(" ").map((s: string) => parseFloat(s));
|
||||
// Scale the direction vector to position the light far from the scene
|
||||
const scale = 5000;
|
||||
return [x * scale, y * scale, z * scale] as [number, number, number];
|
||||
}, [object]);
|
||||
|
||||
const color = useMemo(() => {
|
||||
const colorStr = getProperty(object, "color")?.value ?? "1 1 1 1";
|
||||
const [r, g, b] = colorStr.split(" ").map((s) => parseFloat(s));
|
||||
const colorStr = getProperty(object, "color") ?? "1 1 1 1";
|
||||
// Note: This is a space-separated string, so we split and parse each component.
|
||||
const [r, g, b] = colorStr.split(" ").map((s: string) => parseFloat(s));
|
||||
return [r, g, b] as [number, number, number];
|
||||
}, [object]);
|
||||
|
||||
const ambient = useMemo(() => {
|
||||
const ambientStr = getProperty(object, "ambient")?.value ?? "0.5 0.5 0.5 1";
|
||||
const [r, g, b] = ambientStr.split(" ").map((s) => parseFloat(s));
|
||||
const ambientStr = getProperty(object, "ambient") ?? "0.5 0.5 0.5 1";
|
||||
// Note: This is a space-separated string, so we split and parse each component.
|
||||
const [r, g, b] = ambientStr.split(" ").map((s: string) => parseFloat(s));
|
||||
return [r, g, b] as [number, number, number];
|
||||
}, [object]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
import { Suspense, useMemo } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { DebugPlaceholder, ShapeModel, ShapePlaceholder } from "./GenericShape";
|
||||
import { ShapeInfoProvider } from "./ShapeInfoProvider";
|
||||
|
||||
export function TSStatic({ object }: { object: ConsoleObject }) {
|
||||
const shapeName = getProperty(object, "shapeName").value;
|
||||
export function TSStatic({ object }: { object: TorqueObject }) {
|
||||
const shapeName = getProperty(object, "shapeName");
|
||||
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
|
|
|
|||
|
|
@ -15,13 +15,8 @@ import {
|
|||
import { useTexture } from "@react-three/drei";
|
||||
import { uint16ToFloat32 } from "../arrayUtils";
|
||||
import { loadTerrain, terrainTextureToUrl } from "../loaders";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import {
|
||||
setupColor,
|
||||
setupMask,
|
||||
|
|
@ -204,28 +199,19 @@ function TerrainMaterial({
|
|||
export const TerrainBlock = memo(function TerrainBlock({
|
||||
object,
|
||||
}: {
|
||||
object: ConsoleObject;
|
||||
object: TorqueObject;
|
||||
}) {
|
||||
const terrainFile: string = getProperty(object, "terrainFile").value;
|
||||
const terrainFile = getProperty(object, "terrainFile");
|
||||
|
||||
const squareSize = useMemo(() => {
|
||||
const squareSizeString: string | undefined = getProperty(
|
||||
object,
|
||||
"squareSize",
|
||||
)?.value;
|
||||
return squareSizeString
|
||||
? parseInt(squareSizeString, 10)
|
||||
: DEFAULT_SQUARE_SIZE;
|
||||
return getProperty(object, "squareSize") ?? DEFAULT_SQUARE_SIZE;
|
||||
}, [object]);
|
||||
|
||||
const emptySquares: number[] = useMemo(() => {
|
||||
const emptySquaresString: string | undefined = getProperty(
|
||||
object,
|
||||
"emptySquares",
|
||||
)?.value;
|
||||
|
||||
return emptySquaresString
|
||||
? emptySquaresString.split(" ").map((s) => parseInt(s, 10))
|
||||
const emptySquaresValue = getProperty(object, "emptySquares");
|
||||
// Note: This is a space-separated string, so we split and parse each component.
|
||||
return emptySquaresValue
|
||||
? emptySquaresValue.split(" ").map((s: string) => parseInt(s, 10))
|
||||
: [];
|
||||
}, [object]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
import { Suspense, useMemo } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { DebugPlaceholder, ShapeModel, ShapePlaceholder } from "./GenericShape";
|
||||
import { ShapeInfoProvider } from "./ShapeInfoProvider";
|
||||
|
||||
|
|
@ -34,9 +29,9 @@ function getDataBlockShape(dataBlock: string) {
|
|||
return _caseInsensitiveLookup[dataBlock.toLowerCase()];
|
||||
}
|
||||
|
||||
export function Turret({ object }: { object: ConsoleObject }) {
|
||||
const dataBlock = getProperty(object, "dataBlock").value;
|
||||
const initialBarrel = getProperty(object, "initialBarrel")?.value;
|
||||
export function Turret({ object }: { object: TorqueObject }) {
|
||||
const dataBlock = getProperty(object, "dataBlock") ?? "";
|
||||
const initialBarrel = getProperty(object, "initialBarrel");
|
||||
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,8 @@ import { memo, Suspense, useEffect, useMemo } from "react";
|
|||
import { useTexture } from "@react-three/drei";
|
||||
import { BoxGeometry, DoubleSide } from "three";
|
||||
import { textureToUrl } from "../loaders";
|
||||
import {
|
||||
ConsoleObject,
|
||||
getPosition,
|
||||
getProperty,
|
||||
getRotation,
|
||||
getScale,
|
||||
} from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty, getRotation, getScale } from "../mission";
|
||||
import { setupColor } from "../textureUtils";
|
||||
|
||||
export function WaterMaterial({
|
||||
|
|
@ -35,14 +30,14 @@ export function WaterMaterial({
|
|||
export const WaterBlock = memo(function WaterBlock({
|
||||
object,
|
||||
}: {
|
||||
object: ConsoleObject;
|
||||
object: TorqueObject;
|
||||
}) {
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const q = useMemo(() => getRotation(object), [object]);
|
||||
const [scaleX, scaleY, scaleZ] = useMemo(() => getScale(object), [object]);
|
||||
|
||||
const surfaceTexture =
|
||||
getProperty(object, "surfaceTexture")?.value ?? "liquidTiles/BlueWater";
|
||||
getProperty(object, "surfaceTexture") ?? "liquidTiles/BlueWater";
|
||||
|
||||
const geometry = useMemo(() => {
|
||||
const geom = new BoxGeometry(scaleX, scaleY, scaleZ);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { useMemo } from "react";
|
||||
import { ConsoleObject, getPosition, getProperty } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { getPosition, getProperty } from "../mission";
|
||||
import { FloatingLabel } from "./FloatingLabel";
|
||||
import { useSimGroup } from "./SimGroup";
|
||||
|
||||
export function WayPoint({ object }: { object: ConsoleObject }) {
|
||||
export function WayPoint({ object }: { object: TorqueObject }) {
|
||||
const simGroup = useSimGroup();
|
||||
const position = useMemo(() => getPosition(object), [object]);
|
||||
const label = getProperty(object, "name")?.value;
|
||||
const label = getProperty(object, "name");
|
||||
|
||||
return label ? (
|
||||
<FloatingLabel position={position} opacity={0.6}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ConsoleObject } from "../mission";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
import { TerrainBlock } from "./TerrainBlock";
|
||||
import { WaterBlock } from "./WaterBlock";
|
||||
import { SimGroup } from "./SimGroup";
|
||||
|
|
@ -29,7 +29,7 @@ const componentMap = {
|
|||
WayPoint,
|
||||
};
|
||||
|
||||
export function renderObject(object: ConsoleObject, key: string | number) {
|
||||
const Component = componentMap[object.className];
|
||||
export function renderObject(object: TorqueObject, key: string | number) {
|
||||
const Component = componentMap[object._className];
|
||||
return Component ? <Component key={key} object={object} /> : null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue