diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator2.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator2.tsx index 3747451..2d49e68 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator2.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator2.tsx @@ -1,11 +1,12 @@ import { useFrame, useThree } from "@react-three/fiber"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; import { Quaternion, Vector3 } from "three"; import { useAnimationPlaySpeed, usePlayButtonStore, } from "../../../../../store/usePlayButtonStore"; import { usePathManager } from "../../pathCreator/function/usePathManager"; +import { useCreatedPaths } from "../../../../../store/builder/store"; interface VehicleAnimatorProps { vehiclesData: VehicleStructure[]; @@ -21,6 +22,7 @@ export default function VehicleAnimator2({ const { scene } = useThree(); const { speed } = useAnimationPlaySpeed(); const { isPlaying } = usePlayButtonStore(); + const { paths, allPaths, setAllPaths } = useCreatedPaths(); const vehicleMovementState = useRef< Record< string, @@ -34,138 +36,33 @@ export default function VehicleAnimator2({ > >({}); const managerRef = useRef(); - // const manager = usePathManager(managerData?.pathId, managerData?.vehicleId); + // Initialize all paths into allPaths store + useEffect(() => { + if (!paths || paths.length === 0) return; - // useFrame((_, delta) => { - // if (!isPlaying) return; + const newPaths = useCreatedPaths.getState().paths.map((val: any) => ({ + pathId: val.pathId, + isAvailable: true, + vehicleId: null, + })); + const merged = [...useCreatedPaths.getState().allPaths]; + newPaths.forEach((p: any) => { + if (!merged.find((m) => m.pathId === p.pathId)) { + merged.push(p); + } + }); - // vehiclesData.forEach((vehicle) => { - // const { vehicleId, route } = vehicle; - - // if ( - // !route || - // route.length === 0 || - // !route[0].pathPoints || - // route[0].pathPoints.length < 2 - // ) { - // return; - // } - - // const mesh = scene.getObjectByProperty("uuid", vehicleId); // or getObjectByName - // if (!mesh) return; - // const currentPath = route[0]; - // const pathPoints = currentPath.pathPoints; - // const currentPathId = currentPath.pathId; - - // // ✅ Call your function here - // setManagerData({ pathId: currentPathId, vehicleId: vehicleId }); - // const pathStart = new Vector3(...pathPoints[0].position); - // const uuid = vehicleId; - - // // Initialize movement state - // if (!vehicleMovementState.current[uuid]) { - // vehicleMovementState.current[uuid] = { - // index: 0, - // progress: 0, - // hasStarted: false, - // }; - // } - - // const state = vehicleMovementState.current[uuid]; - - // // ✳️ Step 1: Move to start point first - // if (!state.hasStarted) { - // const distanceToStart = mesh.position.distanceTo(pathStart); - // const step = speed * delta; - - // if (distanceToStart <= step) { - // mesh.position.copy(pathStart); - // mesh.quaternion.identity(); - // state.hasStarted = true; - // return; - // } - - // const direction = pathStart.clone().sub(mesh.position); - // const distance = direction.length(); - - // if (distance > step) { - // direction.normalize(); - // mesh.position.add(direction.clone().multiplyScalar(step)); - - // const forward = new Vector3(0, 0, 1); - // const targetQuat = new Quaternion().setFromUnitVectors( - // forward, - // direction - // ); - // mesh.quaternion.slerp(targetQuat, 0.1); - // } else { - // mesh.position.copy(pathStart); - // mesh.quaternion.identity(); - // state.hasStarted = true; - // state.index = 0; - // state.progress = 0; - // } - - // return; - // } - - // // ✳️ Step 2: Move along the route - // const currentPoint = new Vector3(...pathPoints[state.index].position); - // const nextPoint = new Vector3(...pathPoints[state.index + 1].position); - - // const segmentVector = new Vector3().subVectors(nextPoint, currentPoint); - // const segmentLength = segmentVector.length(); - // const direction = segmentVector.clone().normalize(); - - // const moveDistance = speed * delta; - // state.progress += moveDistance / segmentLength; - - // if (state.progress >= 1) { - // state.index++; - // state.progress = 0; - - // if (state.index >= pathPoints.length - 1) { - // // Stop at the end - // state.index = pathPoints.length - 2; - // state.progress = 1; - // } - // } - - // // Interpolate position - // const newPos = new Vector3().lerpVectors( - // currentPoint, - // nextPoint, - // state.progress - // ); - // mesh.position.copy(newPos); - - // // Smooth rotation - // const forward = new Vector3(0, 0, 1); - // const targetQuat = new Quaternion().setFromUnitVectors( - // forward, - // direction - // ); - // mesh.quaternion.slerp(targetQuat, 0.1); - // }); - // }); - // ✅ Shared waypoint reservation system - const reservedWaypoints = new Set(); - - function tryReserveWaypoint(vehicleId: string, waypointId: string) { - if (reservedWaypoints.has(waypointId)) return false; // already reserved - reservedWaypoints.add(waypointId); - return true; - } - - function releaseWaypoint(waypointId: string) { - reservedWaypoints.delete(waypointId); - } + if (merged.length !== useCreatedPaths.getState().allPaths.length) { + setAllPaths(merged); + } + }, [paths, allPaths, setAllPaths]); useFrame((_, delta) => { if (!isPlaying) return; vehiclesData.forEach((vehicle) => { const { vehicleId, route } = vehicle; + if (!route || route.length === 0) return; const mesh = scene.getObjectByProperty("uuid", vehicleId); @@ -173,7 +70,7 @@ export default function VehicleAnimator2({ const uuid = vehicleId; - // ✅ Initialize state + // ✅ Initialize state if not already if (!vehicleMovementState.current[uuid]) { vehicleMovementState.current[uuid] = { index: 0, @@ -196,7 +93,9 @@ export default function VehicleAnimator2({ let pathPoints = currentPath.pathPoints; const pathStart = new Vector3(...pathPoints[0].position); - // Step 1: move mesh to start + /** + * 🟢 STEP 1: Move vehicle to the starting point of its first path + */ if (!state.hasStarted) { const distanceToStart = mesh.position.distanceTo(pathStart); const step = speed * delta; @@ -221,14 +120,9 @@ export default function VehicleAnimator2({ return; } - // ✅ Conflict Resolution: Check reservation before moving - const nextWaypointId = `${currentPath.pathId}-${state.pointIndex + 1}`; - if (!tryReserveWaypoint(uuid, nextWaypointId)) { - // ⏸ Wait here until waypoint becomes free - return; - } - - // Step 2: Move along current path + /** + * 🟢 STEP 2: Move along path once at start + */ const currentPoint = new Vector3( ...pathPoints[state.pointIndex].position ); @@ -244,30 +138,19 @@ export default function VehicleAnimator2({ state.progress += moveDistance / segmentLength; if (state.progress >= 1) { - // ✅ Release waypoint once passed - releaseWaypoint(nextWaypointId); - state.pointIndex++; state.progress = 0; - // ✅ reached end of current path → switch to next path if (state.pointIndex >= pathPoints.length - 1) { state.pathIndex++; state.pointIndex = 0; - state.progress = 0; - // 🔥 refresh path data after advancing - if (state.pathIndex < route.length) { - currentPath = route[state.pathIndex]; - pathPoints = currentPath.pathPoints; - } else { - // ✅ Finished ALL paths → stop - state.pathIndex = route.length - 1; - const lastPath = route[state.pathIndex]; - const lastPts = lastPath.pathPoints; - state.pointIndex = lastPts.length - 2; - state.progress = 1; + if (state.pathIndex >= route.length) { + return; } + + currentPath = route[state.pathIndex]; + pathPoints = currentPath.pathPoints; } } @@ -286,151 +169,129 @@ export default function VehicleAnimator2({ direction ); mesh.quaternion.slerp(targetQuat, 0.1); + const pathCheck = handlePathCheck(currentPath.pathId, vehicleId); + console.log("pathCheck: ", pathCheck); + // + // 🟢 Log current pathId while moving + // console.log( + // `🚗 Vehicle ${uuid} moving on pathId: ${currentPath.pathId}`, + // "→", + // newPos.toArray() + // ); }); }); + // const handlePathCheck = (pathId: string, vehicleId: string) => { + // const { paths, allPaths, setAllPaths } = useCreatedPaths.getState(); - // useFrame((_, delta) => { - // if (!isPlaying) return; + // const normalize = (v: any) => String(v ?? "").trim(); - // vehiclesData.forEach((vehicle) => { - // console.log("vehiclesData: ", vehiclesData); - // const { vehicleId, route } = vehicle; - // if (!route || route.length === 0) return; + // // Find path + // const path = paths.find( + // (p: any) => normalize(p.pathId) === normalize(pathId) + // ); + // if (!path) { + // + // return false; + // } - // const mesh = scene.getObjectByProperty("uuid", vehicleId); - // if (!mesh) return; - - // const uuid = vehicleId; - - // // ✅ Initialize state - // if (!vehicleMovementState.current[uuid]) { - // vehicleMovementState.current[uuid] = { - // index: 0, - // pointIndex: 0, - // pathIndex: 0, - // progress: 0, - // hasStarted: false, - // }; - // } - - // const state = vehicleMovementState.current[uuid]; - // let currentPath = route[state.pathIndex]; - // if ( - // !currentPath || - // !currentPath.pathPoints || - // currentPath.pathPoints.length < 2 - // ) - // return; - - // let pathPoints = currentPath.pathPoints; - // const pathStart = new Vector3(...pathPoints[0].position); - - // // Step 1: move mesh to start - // if (!state.hasStarted) { - // const distanceToStart = mesh.position.distanceTo(pathStart); - // const step = speed * delta; - - // if (distanceToStart <= step) { - // mesh.position.copy(pathStart); - // mesh.quaternion.identity(); - // state.hasStarted = true; - // return; - // } - - // const direction = pathStart.clone().sub(mesh.position).normalize(); - // mesh.position.add(direction.clone().multiplyScalar(step)); - - // const forward = new Vector3(0, 0, 1); - // const targetQuat = new Quaternion().setFromUnitVectors( - // forward, - // direction - // ); - // mesh.quaternion.slerp(targetQuat, 0.1); - - // return; - // } - // // managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid }; - // // // ✅ only setState when pathId actually changes - // // if (managerData?.pathId !== currentPath.pathId) { - // // setManagerData({ pathId: currentPath.pathId, vehicleId: uuid }); - // // } - // if ( - // !managerRef.current || - // managerRef.current.pathId !== currentPath.pathId || - // managerRef.current.vehicleId !== uuid - // ) { - // managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid }; - // } - // // Step 2: Move along current path - // const currentPoint = new Vector3( - // ...pathPoints[state.pointIndex].position - // ); - // const nextPoint = new Vector3( - // ...pathPoints[state.pointIndex + 1].position + // // If path already reserved → always reject + // if (!path.isAvailable) { + // console.log( + // `🚨 Path ${pathId} is already reserved by vehicle ${vehicleId}` // ); + // return false; + // } + // - // const segmentVector = new Vector3().subVectors(nextPoint, currentPoint); - // const segmentLength = segmentVector.length(); - // const direction = segmentVector.clone().normalize(); + // // Reserve the path for this vehicle + // const updated = allPaths.map((p: any) => + // normalize(p.pathId) === normalize(pathId) + // ? { ...p, vehicleId, isAvailable: false } + // : p + // ); - // console.log("speed: ", speed); - // const moveDistance = speed * delta; - // state.progress += moveDistance / segmentLength; + // setAllPaths(updated); - // if (state.progress >= 1) { - // state.pointIndex++; - // state.progress = 0; + // + // return true; + // }; - // // ✅ reached end of current path → switch to next path - // if (state.pointIndex >= pathPoints.length - 1) { - // state.pathIndex++; - // state.pointIndex = 0; - // state.progress = 0; + const handlePathCheck = (pathId: string, vehicleId: string) => { + const normalize = (v: any) => String(v ?? "").trim(); - // // 🔥 refresh path data after advancing - // if (state.pathIndex < route.length) { - // currentPath = route[state.pathIndex]; - // pathPoints = currentPath.pathPoints; - // } else { - // // ✅ Finished ALL paths → stop - // state.pathIndex = route.length - 1; - // const lastPath = route[state.pathIndex]; - // const lastPts = lastPath.pathPoints; - // state.pointIndex = lastPts.length - 2; - // state.progress = 1; - // } - // } - // } + // Find path + const path = useCreatedPaths + .getState() + .allPaths.find((p: any) => normalize(p.pathId) === normalize(pathId)); - // // Interpolate position - // const newPos = new Vector3().lerpVectors( - // new Vector3(...pathPoints[state.pointIndex].position), - // new Vector3(...pathPoints[state.pointIndex + 1].position), - // state.progress - // ); - // mesh.position.copy(newPos); + if (!path) { + return false; + } - // // Smooth rotation - // const forward = new Vector3(0, 0, 1); - // const targetQuat = new Quaternion().setFromUnitVectors( - // forward, - // direction - // ); - // mesh.quaternion.slerp(targetQuat, 0.1); - // }); - // }); + // If path already reserved → reject always + + if (!path.isAvailable) { + // console.warn( + // `🚨 Path ${pathId} is already reserved by vehicle ${vehicleId}` + // ); + echo.warn(`Path ${pathId}`); + return false; + } else { + console.log("path is reserved"); + } + + // Reserve the path properly with vehicleId + const updated = allPaths.map((p: any) => + normalize(p.pathId) === normalize(pathId) + ? { ...p, vehicleId, isAvailable: false } + : p + ); + + console.log("updated: ", updated); + setAllPaths(updated); + + return true; + }; // const manager = usePathManager( // managerRef.current?.pathId, // managerRef.current?.vehicleId // ); - // useEffect(() => { - // console.log("managerRef.current: ", managerRef.current); - // if (managerRef.current) { - // console.log("Path manager updated:", manager); - // } - // }, [manager, managerRef.current]); - return null; } + +// const handlePathCheck = (pathId: string, vehicleId: string) => { +// const allPaths = useCreatedPaths.getState().allPaths; +// // find the path we’re checking +// const path = allPaths.find((p: any) => p.pathId === pathId); + +// if (!path) { +// +// return false; +// } + +// // if path is available, update it with vehicleId and mark unavailable +// if (path.isAvailable) { +// const updated = allPaths.map((p: any) => +// p.pathId === pathId ? { ...p, vehicleId, isAvailable: false } : p +// ); + +// +// // + +// // setAllPaths(updated); // uncomment if you want to persist update + +// return true; // path was available +// } + +// +// return false; // path not available +// }; + +// useEffect(() => { +// +// if (managerRef.current) { +// +// } +// }, [manager, managerRef.current]); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance2.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance2.tsx index b64a246..a9a2fe8 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance2.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance2.tsx @@ -234,10 +234,6 @@ export default function VehicleInstance2({ const index = vehiclesDataRef.current.findIndex( (v) => v.vehicleId === modelUuid ); - console.log( - "vehiclesDataRef.current: ", - vehiclesDataRef.current - ); if (index !== -1) { const updatedVehicles = [...vehiclesDataRef.current]; @@ -265,6 +261,7 @@ export default function VehicleInstance2({ useEffect(() => { const canvasElement = gl.domElement; canvasElement.addEventListener("contextmenu", handleContextMenu); + console.log("vehiclesDataRef.current: ", vehiclesDataRef.current); return () => { canvasElement.removeEventListener("contextmenu", handleContextMenu); }; diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 13d885f..4a5c528 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -21,11 +21,7 @@ function VehicleInstances() { selectedPointId: val.point.uuid, })); setVehiclesData(updatedVehicles); - }, [vehicles]); - - useEffect(() => { - console.log("vehiclesData", vehiclesData); - }, [vehiclesData]); + }, []); return ( <> diff --git a/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx b/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx index 44c4d82..25f8360 100644 --- a/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx +++ b/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx @@ -63,7 +63,6 @@ export default function PathCreator() { const POINT_SNAP_THRESHOLD = 0.5; const CAN_POINT_SNAP = true; - useEffect(() => {}, [paths]); const getAllOtherPathPoints = useCallback((): PointData[] => { if (draftPoints.length === 0) return []; @@ -145,7 +144,6 @@ export default function PathCreator() { ]; }); - useEffect(() => {}, [paths]); const getPathPointById = (uuid: any) => { for (const path of paths) {