Merge remote-tracking branch 'origin/simulation-agv-v2' into analysis

This commit is contained in:
Gomathi 2025-05-14 14:39:21 +05:30
commit 952602469d
7 changed files with 315 additions and 150 deletions

View File

@ -17,7 +17,6 @@ interface CardProps {
image: string; image: string;
description: string; description: string;
AssetID: string AssetID: string
modelUrl: string
onSelectCard: (cardData: { onSelectCard: (cardData: {
assetName: string; assetName: string;
uploadedOn: number; uploadedOn: number;
@ -38,13 +37,10 @@ const Card: React.FC<CardProps> = ({
image, image,
description, description,
AssetID, AssetID,
modelUrl,
onSelectCard, onSelectCard,
}) => { }) => {
const handleCardSelect = () => { const handleCardSelect = () => {
console.log('assetName: ', assetName);
console.log('AssetID: ', AssetID);
onSelectCard({ onSelectCard({
assetName, uploadedOn, price, rating, views, description, AssetID assetName, uploadedOn, price, rating, views, description, AssetID

View File

@ -45,7 +45,7 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
}) => { }) => {
setSelectedCard(cardData); setSelectedCard(cardData);
const res = await fetchGltfUrl(cardData.assetName, cardData.AssetID); const res = await fetchGltfUrl(cardData.assetName, cardData.AssetID);
console.log("res: ", res); // console.log("res: ", res);
setModelUrl(res.url); setModelUrl(res.url);
}; };
return ( return (
@ -66,7 +66,6 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
AssetID={assetDetail.AssetID} AssetID={assetDetail.AssetID}
image={assetDetail.thumbnail} image={assetDetail.thumbnail}
description={assetDetail.description} description={assetDetail.description}
modelUrl={modelUrl}
/> />
</React.Fragment> </React.Fragment>
))} ))}

View File

@ -33,7 +33,6 @@ const MarketPlace = () => {
try { try {
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6"); const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
setModels(filt.items); setModels(filt.items);
console.log('filt.items: ', filt.items);
setFilteredModels(filt.items); setFilteredModels(filt.items);
setisLoading(false); setisLoading(false);
} catch { } catch {

View File

@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useMachineStore } from '../../../../../store/simulation/useMachineStore'; import { useMachineStore } from '../../../../../store/simulation/useMachineStore';
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import MachineAnimator from '../animator/machineAnimator'; import MachineAnimator from '../animator/machineAnimator';
import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
@ -9,22 +9,94 @@ import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHa
function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) { function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) {
const [currentPhase, setCurrentPhase] = useState<string>('idle'); const [currentPhase, setCurrentPhase] = useState<string>('idle');
let isIncrememtable = useRef<boolean>(true); let isIncrememtable = useRef<boolean>(true);
const idleTimeRef = useRef<number>(0);
const activeTimeRef = useRef<number>(0);
const previousTimeRef = useRef<number | null>(null);
const animationFrameIdRef = useRef<number | null>(null);
const isSpeedRef = useRef<number>(0);
const isPausedRef = useRef<boolean>(false);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { machines, setMachineState, setMachineActive } = useMachineStore(); const { machines, setMachineState, setMachineActive, incrementIdleTime, incrementActiveTime, resetTime } = useMachineStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const { getActionByUuid } = useProductStore(); const { getActionByUuid } = useProductStore();
const { triggerPointActions } = useTriggerHandler(); const { triggerPointActions } = useTriggerHandler();
const { speed } = useAnimationPlaySpeed();
const { isPaused } = usePauseButtonStore();
useEffect(() => {
isPausedRef.current = isPaused;
}, [isPaused]);
useEffect(() => {
isSpeedRef.current = speed;
}, [speed]);
const reset = () => { const reset = () => {
setCurrentPhase("idle"); setCurrentPhase("idle");
console.log("exit");
setMachineState(machineDetail.modelUuid, 'idle'); setMachineState(machineDetail.modelUuid, 'idle');
setMachineActive(machineDetail.modelUuid, false); setMachineActive(machineDetail.modelUuid, false);
isIncrememtable.current = true; isIncrememtable.current = true;
isPausedRef.current = false;
resetTime(machineDetail.modelUuid)
activeTimeRef.current = 0
idleTimeRef.current = 0
previousTimeRef.current = null
if (animationFrameIdRef.current !== null) {
cancelAnimationFrame(animationFrameIdRef.current)
animationFrameIdRef.current = null
}
} }
function machineStatus(modelId: string, status: string) { function machineStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status}`); // console.log(`${modelId} , ${status}`);
} }
function animate(currentTime: number) {
if (previousTimeRef.current === null) {
previousTimeRef.current = currentTime;
}
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
previousTimeRef.current = currentTime;
if (machineDetail.isActive) {
if (!isPausedRef.current) {
activeTimeRef.current += deltaTime * isSpeedRef.current;
// console.log(' activeTimeRef.current: ', activeTimeRef.current);
}
} else {
if (!isPausedRef.current) {
idleTimeRef.current += deltaTime * isSpeedRef.current;
// console.log('idleTimeRef.curre: ', idleTimeRef.current);
}
}
animationFrameIdRef.current = requestAnimationFrame(animate);
}
useEffect(() => {
if (!isPlaying) return
if (!machineDetail.isActive) {
const roundedActiveTime = Math.round(activeTimeRef.current);
// console.log('Final Active Time:', roundedActiveTime, 'seconds');
incrementActiveTime(machineDetail.modelUuid, roundedActiveTime);
activeTimeRef.current = 0;
} else {
const roundedIdleTime = Math.round(idleTimeRef.current);
// console.log('Final Idle Time:', roundedIdleTime, 'seconds');
incrementIdleTime(machineDetail.modelUuid, roundedIdleTime);
idleTimeRef.current = 0;
}
if (animationFrameIdRef.current === null) {
animationFrameIdRef.current = requestAnimationFrame(animate);
}
return () => {
if (animationFrameIdRef.current !== null) {
cancelAnimationFrame(animationFrameIdRef.current);
animationFrameIdRef.current = null;
}
};
}, [machineDetail, isPlaying]);
useEffect(() => { useEffect(() => {
if (isPlaying) { if (isPlaying) {

View File

@ -11,10 +11,7 @@ import { useProductStore } from '../../../../../store/simulation/useProductStore
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
import MaterialAnimator from '../animator/materialAnimator'; import MaterialAnimator from '../animator/materialAnimator';
type Timer = {
start: number | null;
active: boolean;
};
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
const { navMesh } = useNavMesh(); const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
@ -23,20 +20,29 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const { triggerPointActions } = useTriggerHandler(); const { triggerPointActions } = useTriggerHandler();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = useVehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed'); const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const [path, setPath] = useState<[number, number, number][]>([]); const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef<number | null>(null); const pauseTimeRef = useRef<number | null>(null);
const idleTimeRef = useRef<number>(0);
const activeTimeRef = useRef<number>(0);
const isPausedRef = useRef<boolean>(false); const isPausedRef = useRef<boolean>(false);
const isSpeedRef = useRef<number>(0);
let startTime: number; let startTime: number;
let fixedInterval: number; let fixedInterval: number;
const { speed } = useAnimationPlaySpeed(); const { speed } = useAnimationPlaySpeed();
const { isPaused } = usePauseButtonStore(); const { isPaused } = usePauseButtonStore();
const previousTimeRef = useRef<number | null>(null);
const animationFrameIdRef = useRef<number | null>(null);
useEffect(() => { useEffect(() => {
isPausedRef.current = isPaused; isPausedRef.current = isPaused;
}, [isPaused]); }, [isPaused]);
useEffect(() => {
isSpeedRef.current = speed;
}, [speed]);
const computePath = useCallback( const computePath = useCallback(
(start: any, end: any) => { (start: any, end: any) => {
try { try {
@ -54,7 +60,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
); );
function vehicleStatus(modelId: string, status: string) { function vehicleStatus(modelId: string, status: string) {
// // console.log(`${modelId} , ${status}`);
} }
// Function to reset everything // Function to reset everything
@ -68,6 +74,14 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
startTime = 0; startTime = 0;
isPausedRef.current = false; isPausedRef.current = false;
pauseTimeRef.current = 0; pauseTimeRef.current = 0;
resetTime(agvDetail.modelUuid)
activeTimeRef.current = 0
idleTimeRef.current = 0
previousTimeRef.current = null
if (animationFrameIdRef.current !== null) {
cancelAnimationFrame(animationFrameIdRef.current)
animationFrameIdRef.current = null
}
} }
useEffect(() => { useEffect(() => {
@ -115,12 +129,61 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
} }
} }
} else { }
else {
reset() reset()
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [vehicles, currentPhase, path, isPlaying]); }, [vehicles, currentPhase, path, isPlaying]);
function animate(currentTime: number) {
if (previousTimeRef.current === null) {
previousTimeRef.current = currentTime;
}
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
previousTimeRef.current = currentTime;
if (agvDetail.isActive) {
if (!isPausedRef.current) {
activeTimeRef.current += deltaTime * isSpeedRef.current;
}
} else {
if (!isPausedRef.current) {
idleTimeRef.current += deltaTime * isSpeedRef.current; // Scale idle time by speed
}
}
animationFrameIdRef.current = requestAnimationFrame(animate);
}
useEffect(() => {
if (!isPlaying) return
if (!agvDetail.isActive) {
const roundedActiveTime = Math.round(activeTimeRef.current);
// console.log('Final Active Time:', roundedActiveTime, 'seconds');
incrementActiveTime(agvDetail.modelUuid, roundedActiveTime);
activeTimeRef.current = 0;
} else {
const roundedIdleTime = Math.round(idleTimeRef.current);
// console.log('Final Idle Time:', roundedIdleTime, 'seconds');
incrementIdleTime(agvDetail.modelUuid, roundedIdleTime);
idleTimeRef.current = 0;
}
if (animationFrameIdRef.current === null) {
animationFrameIdRef.current = requestAnimationFrame(animate);
}
return () => {
if (animationFrameIdRef.current !== null) {
cancelAnimationFrame(animationFrameIdRef.current);
animationFrameIdRef.current = null;
}
};
}, [agvDetail, isPlaying]);
function handleCallBack() { function handleCallBack() {
if (currentPhase === 'stationed-pickup') { if (currentPhase === 'stationed-pickup') {
setCurrentPhase('picking'); setCurrentPhase('picking');
@ -147,9 +210,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
} }
} }
function startUnloadingProcess() { function startUnloadingProcess() {
if (agvDetail.point.action.triggers.length > 0) { if (agvDetail.point.action.triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid); const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid);
@ -213,7 +273,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
action: VehicleAction action: VehicleAction
) { ) {
startTime = performance.now(); startTime = performance.now();
const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / speed)); const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current));
const unloadLoop = () => { const unloadLoop = () => {
if (isPausedRef.current) { if (isPausedRef.current) {
@ -295,7 +355,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const elapsedTime = performance.now() - startTime; const elapsedTime = performance.now() - startTime;
const unLoadDuration = agvDetail.point.action.unLoadDuration; const unLoadDuration = agvDetail.point.action.unLoadDuration;
fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed)); fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / isSpeedRef.current));
if (elapsedTime >= fixedInterval) { if (elapsedTime >= fixedInterval) {
let droppedMat = droppedMaterial - 1; let droppedMat = droppedMaterial - 1;
@ -333,3 +393,9 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
} }
export default VehicleInstance; export default VehicleInstance;

View File

@ -1,154 +1,176 @@
import { create } from 'zustand'; import { create } from "zustand";
import { immer } from 'zustand/middleware/immer'; import { immer } from "zustand/middleware/immer";
interface MachineStore { interface MachineStore {
machines: MachineStatus[]; machines: MachineStatus[];
addMachine: (productId: string, machine: MachineEventSchema) => void; addMachine: (productId: string, machine: MachineEventSchema) => void;
removeMachine: (modelUuid: string) => void; removeMachine: (modelUuid: string) => void;
updateMachine: ( updateMachine: (
modelUuid: string, modelUuid: string,
updates: Partial<Omit<MachineStatus, 'modelUuid' | 'productId'>> updates: Partial<Omit<MachineStatus, "modelUuid" | "productId">>
) => void; ) => void;
clearMachines: () => void; clearMachines: () => void;
addCurrentAction: (modelUuid: string, actionUuid: string, materialType: string, materialId: string) => void; addCurrentAction: (
removeCurrentAction: (modelUuid: string) => void; modelUuid: string,
actionUuid: string,
materialType: string,
materialId: string
) => void;
removeCurrentAction: (modelUuid: string) => void;
setMachineActive: (modelUuid: string, isActive: boolean) => void; setMachineActive: (modelUuid: string, isActive: boolean) => void;
setMachineState: (modelUuid: string, newState: MachineStatus['state']) => void; setMachineState: (
modelUuid: string,
newState: MachineStatus["state"]
) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
resetTime: (modelUuid: string) => void;
getMachineById: (modelUuid: string) => MachineStatus | undefined; getMachineById: (modelUuid: string) => MachineStatus | undefined;
getMachinesByProduct: (productId: string) => MachineStatus[]; getMachinesByProduct: (productId: string) => MachineStatus[];
getMachinesBystate: (state: string) => MachineStatus[]; getMachinesBystate: (state: string) => MachineStatus[];
getActiveMachines: () => MachineStatus[]; getActiveMachines: () => MachineStatus[];
getIdleMachines: () => MachineStatus[]; getIdleMachines: () => MachineStatus[];
} }
export const useMachineStore = create<MachineStore>()( export const useMachineStore = create<MachineStore>()(
immer((set, get) => ({ immer((set, get) => ({
machines: [], machines: [],
addMachine: (productId, machine) => { addMachine: (productId, machine) => {
set((state) => { set((state) => {
const exists = state.machines.some(m => m.modelUuid === machine.modelUuid); const exists = state.machines.some(
if (!exists) { (m) => m.modelUuid === machine.modelUuid
state.machines.push({ );
...machine, if (!exists) {
productId, state.machines.push({
isActive: false, ...machine,
idleTime: 0, productId,
activeTime: 0, isActive: false,
state: 'idle', idleTime: 0,
}); activeTime: 0,
} state: "idle",
}); });
}, }
});
},
removeMachine: (modelUuid) => { removeMachine: (modelUuid) => {
set((state) => { set((state) => {
state.machines = state.machines.filter(m => m.modelUuid !== modelUuid); state.machines = state.machines.filter(
}); (m) => m.modelUuid !== modelUuid
}, );
});
},
updateMachine: (modelUuid, updates) => { updateMachine: (modelUuid, updates) => {
set((state) => { set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid); const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) { if (machine) {
Object.assign(machine, updates); Object.assign(machine, updates);
} }
}); });
}, },
clearMachines: () => { clearMachines: () => {
set((state) => { set((state) => {
state.machines = []; state.machines = [];
}); });
}, },
addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => { addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => {
set((state) => { set((state) => {
const armBot = state.machines.find(a => a.modelUuid === modelUuid); const armBot = state.machines.find((a) => a.modelUuid === modelUuid);
if (armBot) { if (armBot) {
const action = armBot.point.action; const action = armBot.point.action;
if (action) { if (action) {
armBot.currentAction = { armBot.currentAction = {
actionUuid: actionUuid, actionUuid: actionUuid,
actionName: action.actionName, actionName: action.actionName,
materialType: materialType, materialType: materialType,
materialId: materialId materialId: materialId,
}; };
} }
} }
}); });
}, },
removeCurrentAction: (modelUuid) => { removeCurrentAction: (modelUuid) => {
set((state) => { set((state) => {
const armBot = state.machines.find(a => a.modelUuid === modelUuid); const armBot = state.machines.find((a) => a.modelUuid === modelUuid);
if (armBot) { if (armBot) {
armBot.currentAction = undefined; armBot.currentAction = undefined;
} }
}); });
}, },
setMachineActive: (modelUuid, isActive) => { setMachineActive: (modelUuid, isActive) => {
set((state) => { set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid); const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) { if (machine) {
machine.isActive = isActive; machine.isActive = isActive;
} }
}); });
}, },
setMachineState: (modelUuid, newState) => { setMachineState: (modelUuid, newState) => {
set((state) => { set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid); const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) { if (machine) {
machine.state = newState; machine.state = newState;
} }
}); });
}, },
incrementActiveTime: (modelUuid, incrementBy) => { incrementActiveTime: (modelUuid, incrementBy) => {
set((state) => { set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid); const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) { if (machine) {
machine.activeTime += incrementBy; machine.activeTime += incrementBy;
} }
}); });
}, },
incrementIdleTime: (modelUuid, incrementBy) => { incrementIdleTime: (modelUuid, incrementBy) => {
set((state) => { set((state) => {
const machine = state.machines.find(m => m.modelUuid === modelUuid); const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) { if (machine) {
machine.idleTime += incrementBy; machine.idleTime += incrementBy;
} }
}); });
}, },
resetTime: (modelUuid) => {
set((state) => {
const machine = state.machines.find((m) => m.modelUuid === modelUuid);
if (machine) {
machine.activeTime = 0;
machine.idleTime = 0;
}
});
},
getMachineById: (modelUuid) => { getMachineById: (modelUuid) => {
return get().machines.find(m => m.modelUuid === modelUuid); return get().machines.find((m) => m.modelUuid === modelUuid);
}, },
getMachinesByProduct: (productId) => { getMachinesByProduct: (productId) => {
return get().machines.filter(m => m.productId === productId); return get().machines.filter((m) => m.productId === productId);
}, },
getMachinesBystate: (state) => { getMachinesBystate: (state) => {
return get().machines.filter(m => m.state === state); return get().machines.filter((m) => m.state === state);
}, },
getActiveMachines: () => { getActiveMachines: () => {
return get().machines.filter(m => m.isActive); return get().machines.filter((m) => m.isActive);
}, },
getIdleMachines: () => { getIdleMachines: () => {
return get().machines.filter(m => !m.isActive && m.state === 'idle'); return get().machines.filter((m) => !m.isActive && m.state === "idle");
}, },
})) }))
); );

View File

@ -28,6 +28,7 @@ interface VehiclesStore {
clearCurrentMaterials: (modelUuid: string) => void; clearCurrentMaterials: (modelUuid: string) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
resetTime: (modelUuid: string) => void;
getVehicleById: (modelUuid: string) => VehicleStatus | undefined; getVehicleById: (modelUuid: string) => VehicleStatus | undefined;
getVehiclesByProduct: (productId: string) => VehicleStatus[]; getVehiclesByProduct: (productId: string) => VehicleStatus[];
@ -206,6 +207,16 @@ export const useVehicleStore = create<VehiclesStore>()(
}); });
}, },
resetTime: (modelUuid) => {
set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) {
vehicle.activeTime = 0;
vehicle.idleTime = 0;
}
});
},
getVehicleById: (modelUuid) => { getVehicleById: (modelUuid) => {
return get().vehicles.find((v) => v.modelUuid === modelUuid); return get().vehicles.find((v) => v.modelUuid === modelUuid);
}, },