import * as THREE from "three"; import { useEffect, useRef, useState } from "react"; import { useFrame } from "@react-three/fiber"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import camModel from "../../../assets/gltf-glb/camera face 2.gltf"; import getActiveUsersData from "../../../services/factoryBuilder/collab/getActiveUsers"; import { useActiveUsers, useSocketStore } from "../../../store/store"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { useNavigate } from "react-router-dom"; import { Html } from "@react-three/drei"; import CollabUserIcon from "../../../functions/collabUserIcon"; import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor"; import useModuleStore from "../../../store/useModuleStore"; const CamModelsGroup = () => { const navigate = useNavigate(); const groupRef = useRef(null); const email = localStorage.getItem("email"); const { setActiveUsers } = useActiveUsers(); const { socket } = useSocketStore(); const { activeModule } = useModuleStore(); const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); loader.setDRACOLoader(dracoLoader); const [cams, setCams] = useState([]); const [models, setModels] = useState>({}); const dedupeCams = (cams: any[]) => { const seen = new Set(); return cams.filter((cam) => { if (seen.has(cam.uuid)) return false; seen.add(cam.uuid); return true; }); }; const dedupeUsers = (users: any[]) => { const seen = new Set(); return users.filter((user) => { if (seen.has(user._id)) return false; seen.add(user._id); return true; }); }; useEffect(() => { if (!email) navigate("/"); if (!socket) return; const organization = email!.split("@")[1].split(".")[0]; socket.on("userConnectResponse", (data: any) => { if (!groupRef.current) return; if (data.data.userData.email === email) return; if (socket.id === data.socketId || organization !== data.organization) return; const model = groupRef.current.getObjectByProperty( "uuid", data.data.userData._id ); if (model) { groupRef.current.remove(model); } loader.load(camModel, (gltf) => { const newModel = gltf.scene.clone(); newModel.uuid = data.data.userData._id; newModel.position.set( data.data.position.x, data.data.position.y, data.data.position.z ); newModel.rotation.set( data.data.rotation.x, data.data.rotation.y, data.data.rotation.z ); newModel.userData = data.data.userData; setCams((prev) => dedupeCams([...prev, newModel])); setActiveUsers((prev: any) => dedupeUsers([...prev, data.data.userData]) ); }); }); socket.on("userDisConnectResponse", (data: any) => { if (!groupRef.current) return; if (socket.id === data.socketId || organization !== data.organization) return; setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id) ); setActiveUsers((prev: any) => prev.filter((user: any) => user._id !== data.data.userData._id) ); }); socket.on("cameraUpdateResponse", (data: any) => { if ( !groupRef.current || socket.id === data.socketId || organization !== data.organization ) return; setModels((prev) => ({ ...prev, [data.data.userId]: { targetPosition: new THREE.Vector3( data.data.position.x, data.data.position.y, data.data.position.z ), targetRotation: new THREE.Euler( data.data.rotation.x, data.data.rotation.y, data.data.rotation.z ), }, })); }); return () => { socket.off("userConnectResponse"); socket.off("userDisConnectResponse"); socket.off("cameraUpdateResponse"); }; }, [socket]); useFrame(() => { if (!groupRef.current) return; Object.keys(models).forEach((uuid) => { const model = groupRef.current!.getObjectByProperty("uuid", uuid); if (!model) return; const { targetPosition, targetRotation } = models[uuid]; model.position.lerp(targetPosition, 0.1); model.rotation.x = THREE.MathUtils.lerp( model.rotation.x, targetRotation.x, 0.1 ); model.rotation.y = THREE.MathUtils.lerp( model.rotation.y, targetRotation.y, 0.1 ); model.rotation.z = THREE.MathUtils.lerp( model.rotation.z, targetRotation.z, 0.1 ); }); }); useEffect(() => { if (!groupRef.current) return; const organization = email!.split("@")[1].split(".")[0]; getActiveUsersData(organization).then((data) => { const filteredData = data.cameraDatas.filter( (camera: any) => camera.userData.email !== email ); if (filteredData.length > 0) { loader.load(camModel, (gltf) => { const newCams = filteredData.map((cam: any) => { const newModel = gltf.scene.clone(); newModel.uuid = cam.userData._id; newModel.position.set( cam.position.x, cam.position.y, cam.position.z ); newModel.rotation.set( cam.rotation.x, cam.rotation.y, cam.rotation.z ); newModel.userData = cam.userData; return newModel; }); const users = filteredData.map((cam: any) => cam.userData); setActiveUsers((prev: any) => dedupeUsers([...prev, ...users])); setCams((prev) => dedupeCams([...prev, ...newCams])); }); } }); }, []); return ( {cams.map((cam, index) => ( ))} ); }; export default CamModelsGroup;