Files
Dwinzo_Demo/app/src/modules/builder/asset/assetsGroup.tsx

398 lines
24 KiB
TypeScript

import * as THREE from "three";
import { useEffect } from "react";
import { getFloorAssets } from "../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi";
import { useLoadingProgress, useRenameModeStore, useSelectedItem } from "../../../store/builder/store";
import { useSocketStore } from "../../../store/socket/useSocketStore";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { FloorItems, RefMesh } from "../../../types/world/worldTypes";
import Models from "./models/models";
import useModuleStore from "../../../store/ui/useModuleStore";
import { useThree } from "@react-three/fiber";
import { CameraControls } from "@react-three/drei";
import addAssetModel from "./functions/addAssetModel";
import { useParams } from "react-router-dom";
import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore";
import { getUserData } from "../../../functions/getUserData";
import { useSceneContext } from "../../scene/sceneContext";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
import useAssetResponseHandler from "./responseHandler/useAssetResponseHandler";
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
const { activeModule } = useModuleStore();
const { builderSocket } = useSocketStore();
const { controls, gl, pointer, camera, raycaster, scene } = useThree();
const { setLoadingProgress } = useLoadingProgress();
const { assetStore, eventStore, versionStore } = useSceneContext();
const { selectedVersion } = versionStore();
const { setAssets, clearAssets } = assetStore();
const { addEvent, clearEvents } = eventStore();
const { addAssetToScene } = useAssetResponseHandler();
const { setSelectedFloorAsset } = useBuilderStore();
const { selectedItem, setSelectedItem } = useSelectedItem();
const { projectId } = useParams();
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
const { userId } = getUserData();
const { setTop } = useTopData();
const { setLeft } = useLeftData();
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);
useEffect(() => {
if (!projectId || !selectedVersion) return;
clearEvents();
let totalAssets = 0;
let loadedAssets = 0;
const updateLoadingProgress = (progress: number) => {
if (progress < 100) {
setLoadingProgress(progress);
} else if (progress === 100) {
setTimeout(() => {
setLoadingProgress(100);
setTimeout(() => {
setLoadingProgress(0);
}, 1500);
}, 1000);
}
};
getFloorAssets(projectId, selectedVersion?.versionId || "")
.then((data) => {
if (data && data.length > 0) {
const uniqueItems = (data as FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.assetId === item.assetId));
totalAssets = uniqueItems.length;
if (totalAssets === 0) {
updateLoadingProgress(100);
return;
}
gltfLoaderWorker.postMessage({ floorItems: uniqueItems });
} else {
gltfLoaderWorker.postMessage({ floorItems: [] });
updateLoadingProgress(100);
clearAssets();
}
})
.catch((err) => {
console.error(err);
});
gltfLoaderWorker.onmessage = async (event) => {
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
const blobUrl = URL.createObjectURL(event.data.modelBlob);
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(event.data.modelID, gltf);
loadedAssets++;
const progress = Math.round((loadedAssets / totalAssets) * 100);
updateLoadingProgress(progress);
if (loadedAssets === totalAssets) {
const assets: Asset[] = [];
getFloorAssets(projectId, selectedVersion.versionId || "").then((data: FloorItems) => {
data.forEach((item) => {
if (item.eventData) {
assets.push({
modelUuid: item.modelUuid,
modelName: item.modelName,
assetId: item.assetId,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
isLocked: item.isLocked,
isCollidable: false,
isVisible: item.isVisible,
opacity: 1,
eventData: item.eventData,
});
if (item.eventData.type === "Vehicle") {
const vehicleEvent: VehicleEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "vehicle",
subType: (item.eventData.subType as VehicleEventSchema["subType"]) || "",
speed: 1,
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],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
loadCapacity: 1,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: [],
},
},
};
addEvent(vehicleEvent);
} else if (item.eventData.type === "Conveyor") {
const ConveyorEvent: ConveyorEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "transfer",
subType: item.eventData.subType || "",
speed: 1,
points:
item.eventData.points?.map((point: any, index: number) => ({
uuid: point.uuid || THREE.MathUtils.generateUUID(),
position: [point.position[0], point.position[1], point.position[2]],
rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: `Action 1`,
actionType: "default",
material: "Default material",
delay: 0,
spawnInterval: 5,
spawnCount: 1,
triggers: [],
},
})) || [],
};
addEvent(ConveyorEvent);
} else if (item.eventData.type === "StaticMachine") {
const machineEvent: MachineEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "machine",
subType: item.eventData.subType || "",
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],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "process",
processTime: 10,
swapMaterial: "Default Material",
triggers: [],
},
},
};
addEvent(machineEvent);
} else if (item.eventData.type === "ArmBot") {
const roboticArmEvent: RoboticArmEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "roboticArm",
subType: item.eventData.subType || "",
speed: 1,
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: "pickAndPlace",
process: {
startPoint: null,
endPoint: null,
},
triggers: [],
},
],
},
};
addEvent(roboticArmEvent);
} else if (item.eventData.type === "Storage") {
const storageEvent: StorageEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "storageUnit",
storageCapacity: 10,
storageCount: 10,
materialType: "Default material",
subType: item.eventData.subType || "",
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: "store",
triggers: [],
},
],
},
};
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",
subType: item.eventData.subType || "",
speed: 1,
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: "worker",
loadCount: 1,
assemblyCount: 1,
assemblyCondition: {
conditionType: "material",
materialType: "Default material",
},
manufactureCount: 1,
loadCapacity: 1,
processTime: 10,
triggers: [],
},
],
},
};
addEvent(humanEvent);
} else if (item.eventData.type === "Crane") {
const craneEvent: CraneEventSchema = {
modelUuid: item.modelUuid,
modelName: item.modelName,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
state: "idle",
type: "crane",
subType: (item.eventData.subType as CraneEventSchema["subType"]) || "pillarJib",
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: "pickAndDrop",
maxPickUpCount: 1,
triggers: [],
},
],
},
};
addEvent(craneEvent);
}
} else {
assets.push({
modelUuid: item.modelUuid,
modelName: item.modelName,
assetId: item.assetId,
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
isLocked: item.isLocked,
isCollidable: false,
isVisible: item.isVisible,
opacity: 1,
});
}
});
setAssets(assets);
});
updateLoadingProgress(100);
}
});
}
};
}, [selectedVersion?.versionId]);
useEffect(() => {
const canvasElement = gl.domElement;
const onDrop = (event: DragEvent) => {
if (!event.dataTransfer?.files[0]) return;
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== "Fenestration") {
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
addAssetModel(scene, raycaster, camera, pointer, builderSocket, selectedItem, setSelectedItem, addEvent, addAssetToScene, plane, loader, selectedVersion, projectId, userId);
}
};
const onDragOver = (event: any) => {
event.preventDefault();
};
const onMouseMove = (evt: any) => {
if (!canvasElement) return;
const canvasRect = canvasElement.getBoundingClientRect();
const relativeX = evt.clientX - canvasRect.left;
const relativeY = evt.clientY - canvasRect.top;
if (!isRenameMode) {
setTop(relativeY);
setLeft(relativeX);
}
};
const onMouseUp = (evt: any) => {
setIsRenameMode(false);
};
if (activeModule === "builder") {
canvasElement.addEventListener("drop", onDrop);
canvasElement.addEventListener("dragover", onDragOver);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener("mouseup", onMouseUp);
} else if (controls as CameraControls) {
const target = (controls as CameraControls).getTarget(new THREE.Vector3());
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
setSelectedFloorAsset(null);
}
return () => {
canvasElement.removeEventListener("drop", onDrop);
canvasElement.removeEventListener("dragover", onDragOver);
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("mouseup", onMouseUp);
};
}, [selectedItem, camera, activeModule, controls, isRenameMode]);
return <Models loader={loader} />;
}
export default AssetsGroup;