feat add model loading diagnostics
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import { Grid, TransformControls, useGLTF } from "@react-three/drei";
|
||||
import { Grid, TransformControls } from "@react-three/drei";
|
||||
import type { ThreeEvent } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
|
||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import type { SceneData, MapNode, TransformMode } from "@/types/editor/editor";
|
||||
|
||||
interface EditorMapProps {
|
||||
@@ -258,7 +259,12 @@ function EditorModelNode({
|
||||
const originalMaterialsRef = useRef(
|
||||
new Map<THREE.Mesh, THREE.Material | THREE.Material[]>(),
|
||||
);
|
||||
const { scene } = useGLTF(modelUrl);
|
||||
const { scene } = useLoggedGLTF(modelUrl, {
|
||||
scope: "EditorMap.EditorModelNode",
|
||||
position: node.position,
|
||||
rotation: node.rotation,
|
||||
scale: node.scale,
|
||||
});
|
||||
const sceneInstance = useClonedObject(scene);
|
||||
const pointerHandlers = createEditorNodePointerHandlers(
|
||||
index,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import gsap from "gsap";
|
||||
import * as THREE from "three";
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
REPAIR_CASE_ROTATION_RESET_SPEED,
|
||||
} from "@/data/gameplay/repairCaseConfig";
|
||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import type { ModelTransformProps } from "@/types/three/three";
|
||||
import { toVector3Scale } from "@/utils/three/scale";
|
||||
|
||||
@@ -42,7 +42,12 @@ export function RepairCaseModel({
|
||||
scale = 1,
|
||||
}: RepairCaseModelProps): React.JSX.Element {
|
||||
const camera = useThree((state) => state.camera);
|
||||
const { scene } = useGLTF(modelPath);
|
||||
const { scene } = useLoggedGLTF(modelPath, {
|
||||
scope: "RepairCaseModel",
|
||||
position,
|
||||
rotation,
|
||||
scale,
|
||||
});
|
||||
const model = useClonedObject(scene);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const lidRef = useRef<THREE.Object3D | null>(null);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "@/data/gameplay/repairCaseConfig";
|
||||
import { AudioManager } from "@/managers/AudioManager";
|
||||
import type { Vector3Tuple } from "@/types/three/three";
|
||||
import { logModelLoadError } from "@/utils/three/modelLoadLogger";
|
||||
|
||||
interface RepairCaseErrorBoundaryProps {
|
||||
children: ReactNode;
|
||||
@@ -31,7 +32,15 @@ class RepairCaseErrorBoundary extends Component<
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error): void {
|
||||
console.warn("Failed to load repair case model", error);
|
||||
logModelLoadError(
|
||||
{
|
||||
modelPath: REPAIR_CASE_MODEL_PATH,
|
||||
scope: "RepairCaseObject",
|
||||
position: [0, -0.45, 0],
|
||||
scale: 1.5,
|
||||
},
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
render(): ReactNode {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { RigidBody } from "@react-three/rapier";
|
||||
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import {
|
||||
TRIGGER_DEFAULT_COLLIDERS,
|
||||
TRIGGER_DEFAULT_LABEL,
|
||||
@@ -38,7 +38,10 @@ function SpawnedModelInstance({
|
||||
path: string;
|
||||
position: Vector3Tuple;
|
||||
}): React.JSX.Element {
|
||||
const { scene } = useGLTF(path);
|
||||
const { scene } = useLoggedGLTF(path, {
|
||||
scope: "TriggerObject.SpawnedModel",
|
||||
position,
|
||||
});
|
||||
const model = useClonedObject(scene);
|
||||
|
||||
return <primitive object={model} position={position} />;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useGLTF, useAnimations } from "@react-three/drei";
|
||||
import { useAnimations } from "@react-three/drei";
|
||||
import type { AnimationAction } from "three";
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
AnimatedModelContext,
|
||||
type AnimatedModelContextValue,
|
||||
} from "@/components/three/models/useAnimatedModel";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import type { Vector3Tuple } from "@/types/three/three";
|
||||
|
||||
export interface AnimatedModelConfig {
|
||||
@@ -40,7 +41,12 @@ export function AnimatedModel({
|
||||
children,
|
||||
}: AnimatedModelProps): React.JSX.Element {
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const { scene, animations } = useGLTF(modelPath);
|
||||
const { scene, animations } = useLoggedGLTF(modelPath, {
|
||||
scope: "AnimatedModel",
|
||||
position,
|
||||
rotation,
|
||||
scale,
|
||||
});
|
||||
const model = useMemo(() => scene.clone(true), [scene]);
|
||||
const { actions, names, mixer } = useAnimations(animations, groupRef);
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { Component, useEffect, useMemo } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||
import { ExplodedModel } from "@/utils/three/ExplodedModel";
|
||||
import type { ModelTransformProps, Vector3Tuple } from "@/types/three/three";
|
||||
import { logModelLoadError } from "@/utils/three/modelLoadLogger";
|
||||
import { toVector3Scale } from "@/utils/three/scale";
|
||||
|
||||
interface ModelErrorBoundaryProps {
|
||||
children: ReactNode;
|
||||
modelPath: string;
|
||||
position?: Vector3Tuple | undefined;
|
||||
}
|
||||
|
||||
@@ -30,7 +32,14 @@ class ModelErrorBoundary extends Component<
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error): void {
|
||||
console.warn("Failed to load explodable model", error);
|
||||
logModelLoadError(
|
||||
{
|
||||
modelPath: this.props.modelPath,
|
||||
scope: "ExplodableModel",
|
||||
position: this.props.position,
|
||||
},
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
render(): ReactNode {
|
||||
@@ -52,7 +61,11 @@ export function ExplodableModel(
|
||||
props: ExplodableModelInnerProps,
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<ModelErrorBoundary key={props.modelPath} position={props.position}>
|
||||
<ModelErrorBoundary
|
||||
key={props.modelPath}
|
||||
modelPath={props.modelPath}
|
||||
position={props.position}
|
||||
>
|
||||
<ExplodableModelInner {...props} />
|
||||
</ModelErrorBoundary>
|
||||
);
|
||||
@@ -66,7 +79,12 @@ function ExplodableModelInner({
|
||||
scale = 1,
|
||||
splitDistance = 1.2,
|
||||
}: ExplodableModelInnerProps): React.JSX.Element {
|
||||
const { scene } = useGLTF(modelPath);
|
||||
const { scene } = useLoggedGLTF(modelPath, {
|
||||
scope: "ExplodableModel",
|
||||
position,
|
||||
rotation,
|
||||
scale,
|
||||
});
|
||||
const model = useClonedObject(scene);
|
||||
const explodedModel = useMemo(
|
||||
() => new ExplodedModel(model, { distance: splitDistance }),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from "react";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
import type { Vector3Tuple } from "@/types/three/three";
|
||||
|
||||
export interface SimpleModelConfig {
|
||||
@@ -24,7 +24,12 @@ export function SimpleModel({
|
||||
receiveShadow = true,
|
||||
children,
|
||||
}: SimpleModelProps): React.JSX.Element {
|
||||
const { scene } = useGLTF(modelPath);
|
||||
const { scene } = useLoggedGLTF(modelPath, {
|
||||
scope: "SimpleModel",
|
||||
position,
|
||||
rotation,
|
||||
scale,
|
||||
});
|
||||
const model = useMemo(() => scene.clone(true), [scene]);
|
||||
|
||||
const parsedScale =
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useGLTF } from "@react-three/drei";
|
||||
import { useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||
|
||||
interface SkyModelProps {
|
||||
modelPath: string;
|
||||
@@ -13,7 +14,10 @@ const SKY_MODEL_SCALE = 1;
|
||||
export function SkyModel({ modelPath }: SkyModelProps): React.JSX.Element {
|
||||
const camera = useThree((state) => state.camera);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const { scene } = useGLTF(modelPath);
|
||||
const { scene } = useLoggedGLTF(modelPath, {
|
||||
scope: "SkyModel",
|
||||
scale: SKY_MODEL_SCALE,
|
||||
});
|
||||
const model = useClonedObject(scene);
|
||||
|
||||
useFrame(() => {
|
||||
|
||||
Reference in New Issue
Block a user