feat: Enhance asset and human event handling with animation and loop capabilities

This commit is contained in:
2025-07-02 17:31:17 +05:30
parent 2f0acbda3c
commit 424df54ff7
8 changed files with 192 additions and 170 deletions

View File

@@ -1,4 +1,4 @@
import * as THREE from "three"
import * as THREE from "three"
import { useEffect } from 'react'
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
@@ -226,7 +226,8 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle",
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "storageUnit",
point: {
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
@@ -242,6 +243,36 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
}
};
addEvent(storageEvent);
} else if (item.eventData.type === 'Human') {
const humanEvent: HumanEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "human",
point: {
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "animation",
animation: null,
loopAnimation: true,
loadCapacity: 1,
travelPoints: {
startPoint: null,
endPoint: null,
},
triggers: []
}
]
}
}
addEvent(humanEvent);
}
} else {
assets.push({

View File

@@ -162,6 +162,7 @@ async function handleModelLoad(
// SOCKET
if (selectedItem.type) {
console.log('selectedItem: ', selectedItem);
const data = PointsCalculator(
selectedItem.type,
gltf.scene.clone(),
@@ -170,7 +171,7 @@ async function handleModelLoad(
if (!data || !data.points) return;
const eventData: any = { type: selectedItem.type, };
const eventData: any = { type: selectedItem.type };
if (selectedItem.type === "Conveyor") {
const ConveyorEvent: ConveyorEventSchema = {
@@ -378,6 +379,7 @@ async function handleModelLoad(
actionName: "Action 1",
actionType: "animation",
animation: null,
loopAnimation: true,
loadCapacity: 1,
travelPoints: {
startPoint: null,
@@ -416,6 +418,7 @@ async function handleModelLoad(
userId: userId,
};
console.log('completeData: ', completeData);
socket.emit("v1:model-asset:add", completeData);
const asset: Asset = {

View File

@@ -6,7 +6,7 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
import { CameraControls, Html } from '@react-three/drei';
import { CameraControls } from '@react-three/drei';
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
@@ -15,6 +15,7 @@ import { useParams } from 'react-router-dom';
import { getUserData } from '../../../../../functions/getUserData';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useVersionContext } from '../../../version/versionContext';
import { SkeletonUtils } from 'three-stdlib';
function Model({ asset }: { readonly asset: Asset }) {
const { camera, controls, gl } = useThree();
@@ -23,7 +24,7 @@ function Model({ asset }: { readonly asset: Asset }) {
const { subModule } = useSubModuleStore();
const { activeModule } = useModuleStore();
const { assetStore, eventStore, productStore } = useSceneContext();
const { assets, removeAsset, setAnimations } = assetStore();
const { removeAsset, setAnimations, resetAnimation } = assetStore();
const { setTop } = useTopData();
const { setLeft } = useLeftData();
const { getIsEventInProduct } = productStore();
@@ -33,7 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) {
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
const { socket } = useSocketStore();
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
const { setSelectedFloorItem } = useSelectedFloorItem();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { limitDistance } = useLimitDistance();
const { renderDistance } = useRenderDistance();
const [isRendered, setIsRendered] = useState(false);
@@ -46,13 +47,15 @@ function Model({ asset }: { readonly asset: Asset }) {
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { userId, organization } = getUserData();
const [animationNames, setAnimationNames] = useState<string[]>([]);
const mixerRef = useRef<THREE.AnimationMixer>();
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
useEffect(() => {
setDeletableFloorItem(null);
}, [activeModule, toolMode])
if (selectedFloorItem === null) {
resetAnimation(asset.modelUuid);
}
}, [activeModule, toolMode, selectedFloorItem])
useEffect(() => {
const loader = new GLTFLoader();
@@ -62,40 +65,21 @@ function Model({ asset }: { readonly asset: Asset }) {
loader.setDRACOLoader(dracoLoader);
const loadModel = async () => {
try {
// Check Cache
// const assetId = asset.assetId;
// const cachedModel = THREE.Cache.get(assetId);
// if (cachedModel) {
// setGltfScene(cachedModel.scene.clone());
// calculateBoundingBox(cachedModel.scene);
// return;
// }
// Check Cache
// const assetId = asset.assetId;
// console.log('assetId: ', assetId);
// const cachedModel = THREE.Cache.get(assetId);
// console.log('cachedModel: ', cachedModel);
// if (cachedModel) {
// setGltfScene(cachedModel.scene.clone());
// calculateBoundingBox(cachedModel.scene);
// return;
// }
const assetId = asset.assetId;
const cachedModel = THREE.Cache.get(assetId);
if (cachedModel) {
const clonedScene = cachedModel.scene.clone();
clonedScene.animations = cachedModel.animations || [];
setGltfScene(clonedScene);
calculateBoundingBox(clonedScene);
if (cachedModel.animations && clonedScene.animations.length > 0) {
const animationName = clonedScene.animations.map((clip: any) => clip.name);
setAnimationNames(animationName)
const clone: any = SkeletonUtils.clone(cachedModel.scene);
clone.animations = cachedModel.animations || [];
setGltfScene(clone);
calculateBoundingBox(clone);
if (cachedModel.animations && clone.animations.length > 0) {
const animationName = clone.animations.map((clip: any) => clip.name);
setAnimations(asset.modelUuid, animationName)
mixerRef.current = new THREE.AnimationMixer(clonedScene);
mixerRef.current = new THREE.AnimationMixer(clone);
clonedScene.animations.forEach((animation: any) => {
clone.animations.forEach((animation: any) => {
const action = mixerRef.current!.clipAction(animation);
actions.current[animation.name] = action;
});
@@ -293,28 +277,27 @@ function Model({ asset }: { readonly asset: Asset }) {
clearSelectedAsset()
}
}
useFrame((_, delta) => {
if (mixerRef.current) {
mixerRef.current.update(delta);
}
});
useEffect(() => {
if (asset.animationState && asset.animationState.playing) {
if (asset.animationState && asset.animationState.isPlaying) {
if (!mixerRef.current) return;
Object.values(actions.current).forEach((action) => action.stop());
const action = actions.current[asset.animationState.current];
if (action && asset.animationState?.playing) {
action.reset().setLoop(THREE.LoopOnce, 1).play();
if (action && asset.animationState?.isPlaying) {
const loopMode = asset.animationState.loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce;
action.reset().setLoop(loopMode, loopMode === THREE.LoopRepeat ? Infinity : 1).play();
}
} else {
Object.values(actions.current).forEach((action) => action.stop());
}
}, [asset.animationState])
return (