format with Prettier

This commit is contained in:
Brian Beck 2025-11-29 09:08:20 -08:00
parent c5c43d92d9
commit c8391a1056
37 changed files with 1013 additions and 91 deletions

5
.prettierignore Normal file
View file

@ -0,0 +1,5 @@
.claude/
docs/
generated/
public/manifest.json
package-lock.json

1
.prettierrc Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -12,19 +12,18 @@
Click inside the map preview area to capture the mouse. Click inside the map preview area to capture the mouse.
| Key | Action | | Key | Action |
|-----|--------| | ---------------------------------------- | -------------------- |
| <kbd>W</kbd> | Forward | | <kbd>W</kbd> | Forward |
| <kbd>A</kbd> | Left | | <kbd>A</kbd> | Left |
| <kbd>S</kbd> | Backward | | <kbd>S</kbd> | Backward |
| <kbd>D</kbd> | Right | | <kbd>D</kbd> | Right |
| <kbd>Space</kbd> | Up | | <kbd>Space</kbd> | Up |
| <kbd>Shift</kbd> | Down | | <kbd>Shift</kbd> | Down |
| <kbd>Esc</kbd> | Release mouse | | <kbd>Esc</kbd> | Release mouse |
| <small>Left click</small> | Next observer camera | | <small>Left click</small> | Next observer camera |
| △ <small>Scroll/mouse wheel up</small> | Increase speed | | △ <small>Scroll/mouse wheel up</small> | Increase speed |
| ▽ <small>Scroll/mouse wheel down</small> | Decrease speed | | ▽ <small>Scroll/mouse wheel down</small> | Decrease speed |
## Development ## Development

View file

@ -23,7 +23,7 @@ function MapInspector() {
// Initialize state from query params // Initialize state from query params
const [missionName, setMissionName] = useState( const [missionName, setMissionName] = useState(
searchParams.get("mission") || "TWL2_WoodyMyrk" searchParams.get("mission") || "TWL2_WoodyMyrk",
); );
// Update query params when state changes // Update query params when state changes

View file

@ -6,8 +6,18 @@ body {
} }
html { html {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, font-family:
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Open Sans",
"Helvetica Neue",
sans-serif;
font-size: 100%; font-size: 100%;
} }

890
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,9 +11,13 @@
"build": "next build && touch docs/.nojekyll", "build": "next build && touch docs/.nojekyll",
"clean": "rimraf .next", "clean": "rimraf .next",
"deploy": "npm run build && git add -f docs && git commit -m \"Deploy\" && git push", "deploy": "npm run build && git add -f docs && git commit -m \"Deploy\" && git push",
"format": "prettier --write .",
"postbuild": "git checkout -- public/base", "postbuild": "git checkout -- public/base",
"prebuild": "npm run clean && git checkout -- docs && rimraf public/base && mv docs/base public/", "prebuild": "npm run clean && git checkout -- docs && rimraf public/base && mv docs/base public/",
"start": "next dev --turbopack" "start": "next dev --turbopack",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@react-three/drei": "^10.7.6", "@react-three/drei": "^10.7.6",
@ -35,8 +39,10 @@
"@types/three": "^0.180.0", "@types/three": "^0.180.0",
"@types/unzipper": "^0.10.11", "@types/unzipper": "^0.10.11",
"peggy": "^5.0.6", "peggy": "^5.0.6",
"prettier": "^3.7.1",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"tsx": "^4.20.5", "tsx": "^4.20.5",
"typescript": "5.9.2" "typescript": "5.9.2",
"vitest": "^4.0.14"
} }
} }

View file

@ -43,7 +43,7 @@ async function run({ onlyNew }: { onlyNew: boolean }) {
"--", // args after here go to the script "--", // args after here go to the script
...inputFiles, ...inputFiles,
], ],
{ stdio: "inherit" } { stdio: "inherit" },
); );
} }

View file

@ -27,7 +27,7 @@ async function run() {
// "--no-anims", // "--no-anims",
// "--only-visible", // "--only-visible",
], ],
{ stdio: "inherit" } { stdio: "inherit" },
); );
} }
} }

View file

@ -23,7 +23,7 @@ async function buildExtractedGameDataFolder() {
archives.set(source, archive); archives.set(source, archive);
} }
const entry = archive.files.find( const entry = archive.files.find(
(entry) => normalizePath(entry.path) === filePath (entry) => normalizePath(entry.path) === filePath,
); );
const inFile = `${inputBaseDir}/${source}:${filePath}`; const inFile = `${inputBaseDir}/${source}:${filePath}`;
if (!entry) { if (!entry) {

View file

@ -24,7 +24,7 @@ async function walkDirectory(
entry: Dirent<string>; entry: Dirent<string>;
fullPath: string; fullPath: string;
}) => boolean | Promise<boolean>; }) => boolean | Promise<boolean>;
} },
): Promise<void> { ): Promise<void> {
const entries = await fs.readdir(dir, { withFileTypes: true }); const entries = await fs.readdir(dir, { withFileTypes: true });
@ -102,12 +102,12 @@ async function buildManifest() {
archiveDirs = orderBy( archiveDirs = orderBy(
archiveDirs, archiveDirs,
[(fullPath) => path.basename(fullPath).toLowerCase()], [(fullPath) => path.basename(fullPath).toLowerCase()],
["asc"] ["asc"],
); );
for (const archivePath of archiveDirs) { for (const archivePath of archiveDirs) {
const relativeArchivePath = normalizePath( const relativeArchivePath = normalizePath(
path.relative(`${baseDir}/@vl2`, archivePath) path.relative(`${baseDir}/@vl2`, archivePath),
); );
await walkDirectory(archivePath, { await walkDirectory(archivePath, {
onFile: ({ dir, entry, fullPath }) => { onFile: ({ dir, entry, fullPath }) => {
@ -140,7 +140,7 @@ async function buildManifest() {
.map((source) => ` ❗️ ${source}`) .map((source) => ` ❗️ ${source}`)
.join("") .join("")
: "" : ""
}` }`,
); );
const resolvedPath = lastSource const resolvedPath = lastSource

View file

@ -30,7 +30,7 @@ async function run() {
.map((f) => f.match(/^textures\/skins\/(.+)\.ifl$/)) .map((f) => f.match(/^textures\/skins\/(.+)\.ifl$/))
.filter(Boolean) .filter(Boolean)
.map((match) => match[1]) .map((match) => match[1])
.join("\n") .join("\n"),
); );
return; return;
} else if ( } else if (
@ -38,7 +38,7 @@ async function run() {
(!values.name && !positionals[0]) (!values.name && !positionals[0])
) { ) {
console.error( console.error(
"Must specify exactly one of --name (-n) or a positional filename." "Must specify exactly one of --name (-n) or a positional filename.",
); );
return 1; return 1;
} }
@ -53,7 +53,7 @@ async function run() {
inspect(parseImageFrameList(missionScript), { inspect(parseImageFrameList(missionScript), {
colors: true, colors: true,
depth: Infinity, depth: Infinity,
}) }),
); );
} }

View file

@ -6,12 +6,12 @@ const interiorFile = process.argv[2];
const interiorBuffer = fs.readFileSync(interiorFile); const interiorBuffer = fs.readFileSync(interiorFile);
const interiorArrayBuffer = interiorBuffer.buffer.slice( const interiorArrayBuffer = interiorBuffer.buffer.slice(
interiorBuffer.byteOffset, interiorBuffer.byteOffset,
interiorBuffer.byteOffset + interiorBuffer.byteLength interiorBuffer.byteOffset + interiorBuffer.byteLength,
); );
console.log( console.log(
inspect(parseInteriorBuffer(interiorArrayBuffer), { inspect(parseInteriorBuffer(interiorArrayBuffer), {
colors: true, colors: true,
depth: Infinity, depth: Infinity,
}) }),
); );

View file

@ -30,7 +30,7 @@ async function run() {
.map((f) => f.match(/^missions\/(.+)\.mis$/)) .map((f) => f.match(/^missions\/(.+)\.mis$/))
.filter(Boolean) .filter(Boolean)
.map((match) => match[1]) .map((match) => match[1])
.join("\n") .join("\n"),
); );
return; return;
} else if ( } else if (
@ -38,7 +38,7 @@ async function run() {
(!values.name && !positionals[0]) (!values.name && !positionals[0])
) { ) {
console.error( console.error(
"Must specify exactly one of --name (-n) or a positional filename." "Must specify exactly one of --name (-n) or a positional filename.",
); );
return 1; return 1;
} }
@ -53,7 +53,7 @@ async function run() {
inspect(parseMissionScript(missionScript), { inspect(parseMissionScript(missionScript), {
colors: true, colors: true,
depth: Infinity, depth: Infinity,
}) }),
); );
} }

View file

@ -30,7 +30,7 @@ async function run() {
.map((f) => f.match(/^terrains\/(.+)\.ter$/)) .map((f) => f.match(/^terrains\/(.+)\.ter$/))
.filter(Boolean) .filter(Boolean)
.map((match) => match[1]) .map((match) => match[1])
.join("\n") .join("\n"),
); );
return; return;
} else if ( } else if (
@ -38,7 +38,7 @@ async function run() {
(!values.name && !positionals[0]) (!values.name && !positionals[0])
) { ) {
console.error( console.error(
"Must specify exactly one of --name (-n) or a positional filename." "Must specify exactly one of --name (-n) or a positional filename.",
); );
return 1; return 1;
} }
@ -51,14 +51,14 @@ async function run() {
const terrainBuffer = fs.readFileSync(terrainFile); const terrainBuffer = fs.readFileSync(terrainFile);
const terrainArrayBuffer = terrainBuffer.buffer.slice( const terrainArrayBuffer = terrainBuffer.buffer.slice(
terrainBuffer.byteOffset, terrainBuffer.byteOffset,
terrainBuffer.byteOffset + terrainBuffer.byteLength terrainBuffer.byteOffset + terrainBuffer.byteLength,
); );
console.log( console.log(
inspect(parseTerrainBuffer(terrainArrayBuffer), { inspect(parseTerrainBuffer(terrainArrayBuffer), {
colors: true, colors: true,
depth: Infinity, depth: Infinity,
}) }),
); );
} }

View file

@ -62,7 +62,7 @@ async function run({
console.log(property.value); console.log(property.value);
} else { } else {
console.log( console.log(
`${baseName} > ${consoleObject.className} > ${property.target.name} = ${property.value}` `${baseName} > ${consoleObject.className} > ${property.target.name} = ${property.value}`,
); );
} }
} }

View file

@ -32,7 +32,7 @@ export function AudioProvider({ children }: { children: ReactNode }) {
// Create listener if not already present // Create listener if not already present
let listener = camera.children.find( let listener = camera.children.find(
(child) => child instanceof AudioListener (child) => child instanceof AudioListener,
) as AudioListener | undefined; ) as AudioListener | undefined;
if (!listener) { if (!listener) {

View file

@ -13,7 +13,7 @@ const audioBufferCache = new Map<string, AudioBuffer>();
function getCachedAudioBuffer( function getCachedAudioBuffer(
audioUrl: string, audioUrl: string,
audioLoader: any, audioLoader: any,
onLoad: (buffer: AudioBuffer) => void onLoad: (buffer: AudioBuffer) => void,
) { ) {
if (audioBufferCache.has(audioUrl)) { if (audioBufferCache.has(audioUrl)) {
onLoad(audioBufferCache.get(audioUrl)!); onLoad(audioBufferCache.get(audioUrl)!);
@ -27,7 +27,7 @@ function getCachedAudioBuffer(
undefined, undefined,
(err: any) => { (err: any) => {
console.error("AudioEmitter: Audio load error", audioUrl, err); console.error("AudioEmitter: Audio load error", audioUrl, err);
} },
); );
} }
} }
@ -41,16 +41,16 @@ export const AudioEmitter = memo(function AudioEmitter({
const fileName = getProperty(object, "fileName")?.value ?? ""; const fileName = getProperty(object, "fileName")?.value ?? "";
const volume = parseFloat(getProperty(object, "volume")?.value ?? "1"); const volume = parseFloat(getProperty(object, "volume")?.value ?? "1");
const minDistance = parseFloat( const minDistance = parseFloat(
getProperty(object, "minDistance")?.value ?? "1" getProperty(object, "minDistance")?.value ?? "1",
); );
const maxDistance = parseFloat( const maxDistance = parseFloat(
getProperty(object, "maxDistance")?.value ?? "1" getProperty(object, "maxDistance")?.value ?? "1",
); );
const minLoopGap = parseFloat( const minLoopGap = parseFloat(
getProperty(object, "minLoopGap")?.value ?? "0" getProperty(object, "minLoopGap")?.value ?? "0",
); );
const maxLoopGap = parseFloat( const maxLoopGap = parseFloat(
getProperty(object, "maxLoopGap")?.value ?? "0" getProperty(object, "maxLoopGap")?.value ?? "0",
); );
const is3D = parseInt(getProperty(object, "is3D")?.value ?? "0"); const is3D = parseInt(getProperty(object, "is3D")?.value ?? "0");

View file

@ -71,7 +71,7 @@ export function CamerasProvider({ children }: { children: ReactNode }) {
setCameraIndex(index); setCameraIndex(index);
} }
}, },
[cameraCount] [cameraCount],
); );
useEffect(() => { useEffect(() => {
@ -83,7 +83,7 @@ export function CamerasProvider({ children }: { children: ReactNode }) {
// Apply coordinate system correction for Torque3D to Three.js // Apply coordinate system correction for Torque3D to Three.js
const correction = new Quaternion().setFromAxisAngle( const correction = new Quaternion().setFromAxisAngle(
new Vector3(0, 1, 0), new Vector3(0, 1, 0),
-Math.PI / 2 -Math.PI / 2,
); );
camera.quaternion.copy(cameraInfo.rotation).multiply(correction); camera.quaternion.copy(cameraInfo.rotation).multiply(correction);
} }
@ -97,7 +97,7 @@ export function CamerasProvider({ children }: { children: ReactNode }) {
setCameraIndex: setCamera, setCameraIndex: setCamera,
cameraCount, cameraCount,
}), }),
[registerCamera, unregisterCamera, nextCamera, setCamera, cameraCount] [registerCamera, unregisterCamera, nextCamera, setCamera, cameraCount],
); );
return ( return (

View file

@ -81,7 +81,7 @@ export const ShapeModel = memo(function ShapeModel() {
const hullBoneIndices = useMemo(() => { const hullBoneIndices = useMemo(() => {
const skeletonsFound = Object.values(nodes).filter( const skeletonsFound = Object.values(nodes).filter(
(node: any) => node.skeleton (node: any) => node.skeleton,
); );
if (skeletonsFound.length > 0) { if (skeletonsFound.length > 0) {
@ -97,12 +97,12 @@ export const ShapeModel = memo(function ShapeModel() {
([name, node]: [string, any]) => ([name, node]: [string, any]) =>
node.material && node.material &&
node.material.name !== "Unassigned" && node.material.name !== "Unassigned" &&
!node.name.match(/^Hulk/i) !node.name.match(/^Hulk/i),
) )
.map(([name, node]: [string, any]) => { .map(([name, node]: [string, any]) => {
const geometry = filterGeometryByVertexGroups( const geometry = filterGeometryByVertexGroups(
node.geometry, node.geometry,
hullBoneIndices hullBoneIndices,
); );
return { node, geometry }; return { node, geometry };
}); });

View file

@ -47,7 +47,7 @@ const groupedMissions = getMissionList().reduce(
missionName: string; missionName: string;
displayName: string; displayName: string;
}> }>
>() >(),
); );
groupedMissions.forEach((groupMissions, groupName) => { groupedMissions.forEach((groupMissions, groupName) => {
@ -59,8 +59,8 @@ groupedMissions.forEach((groupMissions, groupName) => {
(missionInfo) => (missionInfo) =>
(missionInfo.displayName || missionInfo.missionName).toLowerCase(), (missionInfo.displayName || missionInfo.missionName).toLowerCase(),
], ],
["asc"] ["asc"],
) ),
); );
}); });
@ -90,7 +90,7 @@ export function InspectorControls({
groupName === "Official" ? 0 : groupName == null ? 2 : 1, groupName === "Official" ? 0 : groupName == null ? 2 : 1,
([groupName]) => (groupName ? groupName.toLowerCase() : ""), ([groupName]) => (groupName ? groupName.toLowerCase() : ""),
], ],
["asc", "asc"] ["asc", "asc"],
); );
return groups; return groups;
}, []); }, []);
@ -125,7 +125,7 @@ export function InspectorControls({
</option> </option>
))} ))}
</Fragment> </Fragment>
) ),
)} )}
</select> </select>
<div className="CheckboxField"> <div className="CheckboxField">

View file

@ -65,7 +65,7 @@ export const InteriorModel = memo(
{Object.entries(nodes) {Object.entries(nodes)
.filter( .filter(
([name, node]: [string, any]) => ([name, node]: [string, any]) =>
!node.material || !node.material.name.match(/\.\d+$/) !node.material || !node.material.name.match(/\.\d+$/),
) )
.map(([name, node]: [string, any]) => ( .map(([name, node]: [string, any]) => (
<InteriorMesh key={name} node={node} /> <InteriorMesh key={name} node={node} />
@ -73,7 +73,7 @@ export const InteriorModel = memo(
{debugMode ? <FloatingLabel>{interiorFile}</FloatingLabel> : null} {debugMode ? <FloatingLabel>{interiorFile}</FloatingLabel> : null}
</group> </group>
); );
} },
); );
function InteriorPlaceholder({ color }: { color: string }) { function InteriorPlaceholder({ color }: { color: string }) {

View file

@ -50,7 +50,7 @@ function getDataBlockShape(dataBlock: string) {
_caseInsensitiveLookup = Object.fromEntries( _caseInsensitiveLookup = Object.fromEntries(
Object.entries(dataBlockToShapeName).map(([key, value]) => { Object.entries(dataBlockToShapeName).map(([key, value]) => {
return [key.toLowerCase(), value]; return [key.toLowerCase(), value];
}) }),
); );
} }
return _caseInsensitiveLookup[dataBlock.toLowerCase()]; return _caseInsensitiveLookup[dataBlock.toLowerCase()];

View file

@ -98,7 +98,7 @@ function CameraMovement() {
// updates while mouse wheels have fewer updates but large deltas. // updates while mouse wheels have fewer updates but large deltas.
Math.max( Math.max(
MIN_SPEED_ADJUSTMENT, MIN_SPEED_ADJUSTMENT,
Math.min(MAX_SPEED_ADJUSTMENT, Math.abs(e.deltaY * 0.01)) Math.min(MAX_SPEED_ADJUSTMENT, Math.abs(e.deltaY * 0.01)),
) * direction; ) * direction;
setSpeedMultiplier((prev) => { setSpeedMultiplier((prev) => {

View file

@ -48,17 +48,17 @@ export function SettingsProvider({ children }: { children: ReactNode }) {
audioEnabled, audioEnabled,
setAudioEnabled, setAudioEnabled,
}), }),
[fogEnabled, speedMultiplier, fov, audioEnabled] [fogEnabled, speedMultiplier, fov, audioEnabled],
); );
const debugContext = useMemo( const debugContext = useMemo(
() => ({ debugMode, setDebugMode }), () => ({ debugMode, setDebugMode }),
[debugMode, setDebugMode] [debugMode, setDebugMode],
); );
const controlsContext = useMemo( const controlsContext = useMemo(
() => ({ speedMultiplier, setSpeedMultiplier }), () => ({ speedMultiplier, setSpeedMultiplier }),
[speedMultiplier, setSpeedMultiplier] [speedMultiplier, setSpeedMultiplier],
); );
// Read persisted settings from localStoarge. // Read persisted settings from localStoarge.

View file

@ -49,7 +49,7 @@ export function SkyBox({
FALLBACK_URL, FALLBACK_URL,
FALLBACK_URL, FALLBACK_URL,
], ],
[detailMapList] [detailMapList],
); );
const skyBox = useCubeTexture(skyBoxFiles, { path: "" }); const skyBox = useCubeTexture(skyBoxFiles, { path: "" });

View file

@ -38,7 +38,7 @@ function getDataBlockShape(dataBlock: string) {
_caseInsensitiveLookup = Object.fromEntries( _caseInsensitiveLookup = Object.fromEntries(
Object.entries(dataBlockToShapeName).map(([key, value]) => { Object.entries(dataBlockToShapeName).map(([key, value]) => {
return [key.toLowerCase(), value]; return [key.toLowerCase(), value];
}) }),
); );
} }
return _caseInsensitiveLookup[dataBlock.toLowerCase()]; return _caseInsensitiveLookup[dataBlock.toLowerCase()];

View file

@ -58,12 +58,12 @@ function BlendedTerrainTextures({
textureNames.map((name) => terrainTextureToUrl(name)), textureNames.map((name) => terrainTextureToUrl(name)),
(textures) => { (textures) => {
textures.forEach((tex) => setupColor(tex)); textures.forEach((tex) => setupColor(tex));
} },
); );
const alphaTextures = useMemo( const alphaTextures = useMemo(
() => alphaMaps.map((data) => setupMask(data)), () => alphaMaps.map((data) => setupMask(data)),
[alphaMaps] [alphaMaps],
); );
const tiling = useMemo( const tiling = useMemo(
@ -75,7 +75,7 @@ function BlendedTerrainTextures({
4: 32, 4: 32,
5: 32, 5: 32,
}), }),
[] [],
); );
const onBeforeCompile = useCallback( const onBeforeCompile = useCallback(
@ -89,7 +89,7 @@ function BlendedTerrainTextures({
debugMode, debugMode,
}); });
}, },
[baseTextures, alphaTextures, visibilityMask, tiling, debugMode] [baseTextures, alphaTextures, visibilityMask, tiling, debugMode],
); );
return ( return (
@ -125,7 +125,7 @@ function TerrainMaterial({
256, 256,
256, 256,
RedFormat, RedFormat,
FloatType FloatType,
); );
displacementMap.colorSpace = NoColorSpace; displacementMap.colorSpace = NoColorSpace;
displacementMap.generateMipmaps = false; displacementMap.generateMipmaps = false;
@ -168,7 +168,7 @@ function TerrainMaterial({
terrainSize, terrainSize,
terrainSize, terrainSize,
RedFormat, RedFormat,
UnsignedByteType UnsignedByteType,
); );
visibilityMask.colorSpace = NoColorSpace; visibilityMask.colorSpace = NoColorSpace;
visibilityMask.wrapS = visibilityMask.wrapT = ClampToEdgeWrapping; visibilityMask.wrapS = visibilityMask.wrapT = ClampToEdgeWrapping;
@ -211,7 +211,7 @@ export const TerrainBlock = memo(function TerrainBlock({
const squareSize = useMemo(() => { const squareSize = useMemo(() => {
const squareSizeString: string | undefined = getProperty( const squareSizeString: string | undefined = getProperty(
object, object,
"squareSize" "squareSize",
)?.value; )?.value;
return squareSizeString return squareSizeString
? parseInt(squareSizeString, 10) ? parseInt(squareSizeString, 10)
@ -221,7 +221,7 @@ export const TerrainBlock = memo(function TerrainBlock({
const emptySquares: number[] = useMemo(() => { const emptySquares: number[] = useMemo(() => {
const emptySquaresString: string | undefined = getProperty( const emptySquaresString: string | undefined = getProperty(
object, object,
"emptySquares" "emptySquares",
)?.value; )?.value;
return emptySquaresString return emptySquaresString

View file

@ -28,7 +28,7 @@ function getDataBlockShape(dataBlock: string) {
_caseInsensitiveLookup = Object.fromEntries( _caseInsensitiveLookup = Object.fromEntries(
Object.entries(dataBlockToShapeName).map(([key, value]) => { Object.entries(dataBlockToShapeName).map(([key, value]) => {
return [key.toLowerCase(), value]; return [key.toLowerCase(), value];
}) }),
); );
} }
return _caseInsensitiveLookup[dataBlock.toLowerCase()]; return _caseInsensitiveLookup[dataBlock.toLowerCase()];
@ -54,7 +54,7 @@ export function Turret({ object }: { object: ConsoleObject }) {
} }
if (!barrelShapeName) { if (!barrelShapeName) {
console.error( console.error(
`<Turret> missing shape for initialBarrel dataBlock: ${initialBarrel}` `<Turret> missing shape for initialBarrel dataBlock: ${initialBarrel}`,
); );
} }

View file

@ -4,7 +4,7 @@ import { Object3D } from "three";
import { useWorldPosition } from "./useWorldPosition"; import { useWorldPosition } from "./useWorldPosition";
export function useDistanceFromCamera<T extends Object3D>( export function useDistanceFromCamera<T extends Object3D>(
ref: RefObject<T> ref: RefObject<T>,
): RefObject<number> { ): RefObject<number> {
const { camera } = useThree(); const { camera } = useThree();
const distanceRef = useRef<number>(null); const distanceRef = useRef<number>(null);

View file

@ -3,7 +3,7 @@ import { useRef, RefObject } from "react";
import { Object3D, Vector3 } from "three"; import { Object3D, Vector3 } from "three";
export function useWorldPosition<T extends Object3D>( export function useWorldPosition<T extends Object3D>(
ref: RefObject<T> ref: RefObject<T>,
): RefObject<Vector3 | null> { ): RefObject<Vector3 | null> {
const worldPositionRef = useRef<Vector3 | null>(null); const worldPositionRef = useRef<Vector3 | null>(null);

View file

@ -41,7 +41,7 @@ export function getActualResourcePathUncached(resourcePath: string) {
// First, try exact case-insensitive match // First, try exact case-insensitive match
const foundLowerCase = resourcePaths.find( const foundLowerCase = resourcePaths.find(
(s) => s.toLowerCase() === lowerCased (s) => s.toLowerCase() === lowerCased,
); );
if (foundLowerCase) { if (foundLowerCase) {
return foundLowerCase; return foundLowerCase;
@ -55,7 +55,7 @@ export function getActualResourcePathUncached(resourcePath: string) {
if (pathWithoutNumber !== resourcePath) { if (pathWithoutNumber !== resourcePath) {
// If we stripped a number, try to find the version without it // If we stripped a number, try to find the version without it
const foundWithoutNumber = resourcePaths.find( const foundWithoutNumber = resourcePaths.find(
(s) => s.toLowerCase() === lowerCasedWithoutNumber (s) => s.toLowerCase() === lowerCasedWithoutNumber,
); );
if (foundWithoutNumber) { if (foundWithoutNumber) {
return foundWithoutNumber; return foundWithoutNumber;
@ -69,9 +69,9 @@ export function getActualResourcePathUncached(resourcePath: string) {
s s
.replace( .replace(
/^(textures\/)((lush|desert|badlands|lava|ice|jaggedclaw|terrainTiles)\/)/, /^(textures\/)((lush|desert|badlands|lava|ice|jaggedclaw|terrainTiles)\/)/,
"$1" "$1",
) )
.toLowerCase() === lowerCased .toLowerCase() === lowerCased,
); );
if (foundNested) { if (foundNested) {
return foundNested; return foundNested;

View file

@ -23,7 +23,7 @@ export function getHullBoneIndices(skeleton: any): Set<number> {
*/ */
export function filterGeometryByVertexGroups( export function filterGeometryByVertexGroups(
geometry: any, geometry: any,
hullBoneIndices: Set<number> hullBoneIndices: Set<number>,
): any { ): any {
// If no hull bones or no skinning data, return original geometry // If no hull bones or no skinning data, return original geometry
if (hullBoneIndices.size === 0 || !geometry.attributes.skinIndex) { if (hullBoneIndices.size === 0 || !geometry.attributes.skinIndex) {

View file

@ -55,7 +55,7 @@ function parseInstance(instance) {
default: default:
throw new Error( throw new Error(
`Unhandled value type: ${def.target.name} = ${def.value.type}` `Unhandled value type: ${def.target.name} = ${def.value.type}`,
); );
} }
}), }),
@ -70,7 +70,7 @@ export function parseMissionScript(script) {
// - Remove code-like parts of the script so it's easier to parse. // - Remove code-like parts of the script so it's easier to parse.
script = script.replace( script = script.replace(
/(\/\/--- OBJECT WRITE END ---\s+)(?:.|[\r\n])*$/, /(\/\/--- OBJECT WRITE END ---\s+)(?:.|[\r\n])*$/,
"$1" "$1",
); );
let objectWriteBegin = /(\/\/--- OBJECT WRITE BEGIN ---\s+)/.exec(script); let objectWriteBegin = /(\/\/--- OBJECT WRITE BEGIN ---\s+)/.exec(script);
@ -173,7 +173,7 @@ export function parseMissionScript(script) {
globals: mission.sections globals: mission.sections
.filter((section) => !section.name) .filter((section) => !section.name)
.flatMap((section) => .flatMap((section) =>
section.definitions.filter((def) => def.type === "definition") section.definitions.filter((def) => def.type === "definition"),
), ),
}; };
} }
@ -202,7 +202,7 @@ export function getTerrainBlock(mission: Mission): ConsoleObject {
export function getTerrainFile(mission: Mission) { export function getTerrainFile(mission: Mission) {
const terrainBlock = getTerrainBlock(mission); const terrainBlock = getTerrainBlock(mission);
return terrainBlock.properties.find( return terrainBlock.properties.find(
(prop) => prop.target.name === "terrainFile" (prop) => prop.target.name === "terrainFile",
).value; ).value;
} }

View file

@ -19,7 +19,7 @@ const alphaAsRoughnessShaderModifier = (shader: any) => {
#ifdef USE_MAP #ifdef USE_MAP
roughnessFactor = texture2D(map, vMapUv).a * 1; roughnessFactor = texture2D(map, vMapUv).a * 1;
#endif #endif
` `,
); );
}; };

View file

@ -30,7 +30,7 @@ export function setupMask(data) {
256, 256,
256, 256,
RedFormat, // 1 channel RedFormat, // 1 channel
UnsignedByteType // 8-bit UnsignedByteType, // 8-bit
); );
// Masks should stay linear // Masks should stay linear
@ -132,7 +132,7 @@ float getWireframe(vec2 uv, float gridSize, float lineWidth) {
if (visibility < 0.5) { if (visibility < 0.5) {
discard; discard;
} }
` `,
); );
} }
@ -206,6 +206,6 @@ float getWireframe(vec2 uv, float gridSize, float lineWidth) {
} else { } else {
diffuseColor.rgb = textureColor; diffuseColor.rgb = textureColor;
} }
` `,
); );
} }

13
vitest.config.ts Normal file
View file

@ -0,0 +1,13 @@
import { defineConfig } from "vitest/config";
import { resolve } from "node:path";
export default defineConfig({
test: {
include: ["**/*.spec.ts"],
},
resolve: {
alias: {
"@": resolve(__dirname, "."),
},
},
});