299 lines
13 KiB
TypeScript
299 lines
13 KiB
TypeScript
import * as THREE from 'three';
|
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
import gsap from 'gsap';
|
|
import { toast } from 'react-toastify';
|
|
import TempLoader from './tempLoader';
|
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
|
import * as Types from "../../../../types/world/worldTypes";
|
|
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
|
import { Socket } from 'socket.io-client';
|
|
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
|
import { getAssetEventType } from '../../../../services/simulation/getAssetEventType';
|
|
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
|
|
|
async function addAssetModel(
|
|
raycaster: THREE.Raycaster,
|
|
camera: THREE.Camera,
|
|
pointer: THREE.Vector2,
|
|
floorGroup: Types.RefGroup,
|
|
setFloorItems: Types.setFloorItemSetState,
|
|
itemsGroup: Types.RefGroup,
|
|
isTempLoader: Types.RefBoolean,
|
|
tempLoader: Types.RefMesh,
|
|
socket: Socket<any>,
|
|
selectedItem: any,
|
|
setSelectedItem: any,
|
|
setSimulationPaths: any,
|
|
plane: Types.RefMesh,
|
|
): Promise<void> {
|
|
|
|
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
|
|
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
|
|
|
try {
|
|
isTempLoader.current = true;
|
|
const loader = new GLTFLoader();
|
|
const dracoLoader = new DRACOLoader();
|
|
|
|
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
|
loader.setDRACOLoader(dracoLoader);
|
|
|
|
raycaster.setFromCamera(pointer, camera);
|
|
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
|
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
|
|
|
|
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
|
const intersectedPlane = planeIntersections[0];
|
|
|
|
let intersectPoint: THREE.Vector3 | null = null;
|
|
|
|
if (intersectedFloor && intersectedPlane) {
|
|
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
|
|
} else if (intersectedFloor) {
|
|
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
|
|
} else if (intersectedPlane) {
|
|
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
|
}
|
|
|
|
if (intersectPoint) {
|
|
if (intersectPoint.y < 0) {
|
|
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
|
}
|
|
// console.log('selectedItem: ', selectedItem);
|
|
const cachedModel = THREE.Cache.get(selectedItem.id);
|
|
if (cachedModel) {
|
|
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
|
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
|
return;
|
|
} else {
|
|
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
|
|
|
if (cachedModelBlob) {
|
|
// console.log(`Added ${selectedItem.name} from indexDB`);
|
|
|
|
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
|
loader.load(blobUrl, (gltf) => {
|
|
URL.revokeObjectURL(blobUrl);
|
|
THREE.Cache.remove(blobUrl);
|
|
THREE.Cache.add(selectedItem.id, gltf);
|
|
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
|
},
|
|
() => {
|
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
|
});
|
|
} else {
|
|
// console.log(`Added ${selectedItem.name} from Backend`);
|
|
|
|
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
|
|
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
|
await storeGLTF(selectedItem.id, modelBlob);
|
|
THREE.Cache.add(selectedItem.id, gltf);
|
|
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
|
},
|
|
() => {
|
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching asset model:', error);
|
|
} finally {
|
|
setSelectedItem({});
|
|
}
|
|
}
|
|
|
|
async function handleModelLoad(
|
|
gltf: any,
|
|
intersectPoint: THREE.Vector3,
|
|
selectedItem: any,
|
|
itemsGroup: Types.RefGroup,
|
|
tempLoader: Types.RefMesh,
|
|
isTempLoader: Types.RefBoolean,
|
|
setFloorItems: Types.setFloorItemSetState,
|
|
setSimulationPaths: any,
|
|
socket: Socket<any>
|
|
) {
|
|
const model = gltf.scene.clone();
|
|
model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid };
|
|
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
|
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
|
|
|
model.traverse((child: any) => {
|
|
if (child) {
|
|
child.castShadow = true;
|
|
child.receiveShadow = true;
|
|
}
|
|
});
|
|
|
|
itemsGroup.current.add(model);
|
|
if (tempLoader.current) {
|
|
(<any>tempLoader.current.material).dispose();
|
|
(<any>tempLoader.current.geometry).dispose();
|
|
itemsGroup.current.remove(tempLoader.current);
|
|
tempLoader.current = undefined;
|
|
}
|
|
|
|
const newFloorItem: Types.EventData = {
|
|
modeluuid: model.uuid,
|
|
modelname: selectedItem.name,
|
|
modelfileID: selectedItem.id,
|
|
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true
|
|
};
|
|
|
|
const email = localStorage.getItem("email");
|
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
|
|
|
getAssetEventType(selectedItem.id, organization).then(async (res) => {
|
|
|
|
if (res.type === "Conveyor") {
|
|
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
|
|
|
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Conveyor' }> = {
|
|
type: 'Conveyor',
|
|
points: res.points.map((point: any, index: number) => ({
|
|
uuid: pointUUIDs[index],
|
|
position: point.position as [number, number, number],
|
|
rotation: point.rotation as [number, number, number],
|
|
actions: [{
|
|
uuid: THREE.MathUtils.generateUUID(),
|
|
name: 'Action 1',
|
|
type: 'Inherit',
|
|
material: 'Inherit',
|
|
delay: 'Inherit',
|
|
spawnInterval: 'Inherit',
|
|
isUsed: true
|
|
}],
|
|
triggers: [],
|
|
connections: {
|
|
source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] },
|
|
targets: []
|
|
}
|
|
})),
|
|
speed: 'Inherit'
|
|
};
|
|
|
|
// API
|
|
|
|
// await setFloorItemApi(
|
|
// organization,
|
|
// newFloorItem.modeluuid,
|
|
// newFloorItem.modelname,
|
|
// newFloorItem.modelfileID,
|
|
// newFloorItem.position,
|
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
// false,
|
|
// true,
|
|
// { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
|
|
// );
|
|
|
|
// SOCKET
|
|
|
|
const data = {
|
|
organization,
|
|
modeluuid: newFloorItem.modeluuid,
|
|
modelname: newFloorItem.modelname,
|
|
modelfileID: newFloorItem.modelfileID,
|
|
position: newFloorItem.position,
|
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true,
|
|
eventData: backendEventData,
|
|
socketId: socket.id
|
|
};
|
|
|
|
setFloorItems((prevItems) => {
|
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
return updatedItems;
|
|
});
|
|
|
|
const eventData: any = backendEventData;
|
|
eventData.modeluuid = newFloorItem.modeluuid;
|
|
eventData.modelName = newFloorItem.modelname;
|
|
eventData.position = newFloorItem.position;
|
|
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
|
|
|
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
|
...(prevEvents || []),
|
|
eventData as Types.ConveyorEventsSchema
|
|
]);
|
|
|
|
socket.emit("v2:model-asset:add", data);
|
|
|
|
} else if (res.type === "Vehicle") {
|
|
|
|
const pointUUID = THREE.MathUtils.generateUUID();
|
|
|
|
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Vehicle' }> = {
|
|
type: "Vehicle",
|
|
points: {
|
|
uuid: pointUUID,
|
|
position: res.points.position as [number, number, number],
|
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
|
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
|
speed: 2,
|
|
}
|
|
}
|
|
|
|
// API
|
|
|
|
// await setFloorItemApi(
|
|
// organization,
|
|
// newFloorItem.modeluuid,
|
|
// newFloorItem.modelname,
|
|
// newFloorItem.modelfileID,
|
|
// newFloorItem.position,
|
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
// false,
|
|
// true,
|
|
// { type: backendEventData.type, points: backendEventData.points }
|
|
// );
|
|
|
|
// SOCKET
|
|
|
|
const data = {
|
|
organization,
|
|
modeluuid: newFloorItem.modeluuid,
|
|
modelname: newFloorItem.modelname,
|
|
modelfileID: newFloorItem.modelfileID,
|
|
position: newFloorItem.position,
|
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
isLocked: false,
|
|
isVisible: true,
|
|
eventData: { type: backendEventData.type, points: backendEventData.points },
|
|
socketId: socket.id
|
|
};
|
|
|
|
const eventData: any = backendEventData;
|
|
eventData.modeluuid = newFloorItem.modeluuid;
|
|
eventData.modelName = newFloorItem.modelname;
|
|
eventData.position = newFloorItem.position;
|
|
|
|
setFloorItems((prevItems) => {
|
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
return updatedItems;
|
|
});
|
|
|
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
|
...(prevEvents || []),
|
|
eventData as Types.VehicleEventsSchema
|
|
]);
|
|
|
|
socket.emit("v2:model-asset:add", data);
|
|
|
|
}
|
|
|
|
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
|
});
|
|
}
|
|
|
|
export default addAssetModel;
|