import { Component, type ReactNode } from "react";
import type { CharacterRigState, MotionClip } from "../schema/directorProject";
import { PrimitiveMannequin } from "./PrimitiveMannequin";
import { UE4MannequinModel } from "./UE4MannequinModel";
import { GltfCharacterModel } from "./GltfCharacterModel";
import type { CharacterBodyType } from "./mannequin/bodyTypes";
import { getActiveMotionClipAtTime, resolveMotionClipEnd } from "./mannequin/motion";
interface CharacterModelProps {
bodyType?: CharacterBodyType;
color?: string;
onLabelAnchorYChange?: (anchorY: number) => void;
rigState?: CharacterRigState;
motionTime?: number;
characterId?: string;
/** 动作片段起点(秒):基础动作只在该时间区间内驱动角色,缺省视为时间轴开头 */
motionStartTime?: number;
/** 动作片段终点(秒):缺省视为时间轴末尾 */
motionEndTime?: number;
/** 时间轴上的动作片段序列(多段动作)。存在时按播放时间取当前片段覆盖上面的单一 motion。 */
motionClips?: MotionClip[];
/** 时间轴总时长(秒),用于解析到末尾的动作片段。 */
duration: number;
/** 当 rigState.modelAssetId 指向一个导入的 GLB/GLTF 资产时,其可访问的 url(用于渲染该角色几何)。 */
modelAssetUrl?: string;
}
class CharacterModelBoundary extends Component<
{
fallback: ReactNode;
children: ReactNode;
},
{
hasError: boolean;
}
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
return this.state.hasError ? this.props.fallback : this.props.children;
}
}
export function CharacterModel({ bodyType, color, onLabelAnchorYChange, rigState, motionTime, characterId, motionStartTime, motionEndTime, modelAssetUrl, motionClips, duration }: CharacterModelProps) {
// 动作序列:按当前播放时间取出应生效的片段(后段覆盖前段),用它覆盖单一 motion 字段。
// 无片段 / 时间不在任何片段内 → 回退到旧的单一段落(rigState.motion + motionStartTime/EndTime)。
const activeClip = getActiveMotionClipAtTime(motionClips, motionTime ?? 0, duration);
const resolvedRigState: CharacterRigState | undefined = activeClip && rigState
? { ...rigState, motion: activeClip }
: rigState;
const resolvedStart = activeClip ? activeClip.start : motionStartTime;
const resolvedEnd = activeClip ? resolveMotionClipEnd(activeClip, duration) : motionEndTime;
const fallback = ;
// 导入的 GLB/GLTF 人形角色:几何来自资产,用通用人形骨骼映射驱动程序化动作。
if (rigState?.modelAssetId && modelAssetUrl) {
return (
);
}
if (rigState?.rigType !== "ue4-mannequin") {
return fallback;
}
return (
);
}