Merge remote-tracking branch 'origin/main-dev' into main-demo

This commit is contained in:
2025-09-22 13:20:06 +05:30
4 changed files with 263 additions and 195 deletions

View File

@@ -39,7 +39,7 @@ const CopyPasteControls3D = () => {
rotatedObjects,
setRotatedObjects,
} = assetStore();
const { updateAssetInScene } = useAssetResponseHandler();
const { updateAssetInScene, removeAssetFromScene } = useAssetResponseHandler();
const { selectedVersion } = versionStore();
const { userId, organization } = getUserData();
@@ -502,56 +502,58 @@ const CopyPasteControls3D = () => {
projectId,
};
if (!builderSocket?.connected) {
// REST
removeAssetFromScene(data.modelUuid, () => {
if (!builderSocket?.connected) {
// REST
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, 0, position.z],
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
isLocked: false,
isVisible: true,
eventData: eventData,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
eventData: data.data.eventData,
};
updateAssetInScene(model, () => {
echo.log(`Pasted asset: ${model.modelName}`);
});
} else {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
}
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, 0, position.z],
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
isLocked: false,
isVisible: true,
eventData: eventData,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.catch(() => {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
eventData: data.data.eventData,
};
builderSocket.emit("v1:model-asset:copy", data);
}
updateAssetInScene(model, () => {
echo.log(`Pasted asset: ${model.modelName}`);
});
} else {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
}
})
.catch(() => {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
builderSocket.emit("v1:model-asset:copy", data);
}
});
} else {
const data = {
organization,
@@ -568,54 +570,56 @@ const CopyPasteControls3D = () => {
userId,
};
if (!builderSocket?.connected) {
// REST
removeAssetFromScene(data.modelUuid, () => {
if (!builderSocket?.connected) {
// REST
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, 0, position.z],
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
isLocked: false,
isVisible: true,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
};
updateAssetInScene(model, () => {
echo.log(`Pasted asset: ${model.modelUuid}`);
});
} else {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
}
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, 0, position.z],
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
isLocked: false,
isVisible: true,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.catch(() => {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
};
builderSocket.emit("v1:model-asset:copy", data);
}
updateAssetInScene(model, () => {
echo.log(`Pasted asset: ${model.modelUuid}`);
});
} else {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
}
})
.catch(() => {
echo.error(`Error pasting asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
builderSocket.emit("v1:model-asset:copy", data);
}
});
}
assetsToCopy.push({

View File

@@ -38,7 +38,7 @@ const DuplicationControls3D = () => {
rotatedObjects,
setRotatedObjects,
} = assetStore();
const { updateAssetInScene } = useAssetResponseHandler();
const { updateAssetInScene, removeAssetFromScene } = useAssetResponseHandler();
const { selectedVersion } = versionStore();
const { userId, organization } = getUserData();
@@ -93,9 +93,7 @@ const DuplicationControls3D = () => {
if (!isPointerMoving && duplicatedObjects.length > 0 && event.button === 2) {
event.preventDefault();
clearSelection();
duplicatedObjects.forEach((obj: THREE.Object3D) => {
removeAsset(obj.userData.modelUuid);
});
clearDuplication();
}
setKeyEvent("");
};
@@ -130,9 +128,7 @@ const DuplicationControls3D = () => {
if (keyCombination === "ESCAPE" && duplicatedObjects.length > 0) {
event.preventDefault();
clearSelection();
duplicatedObjects.forEach((obj: THREE.Object3D) => {
removeAsset(obj.userData.modelUuid);
});
clearDuplication();
}
};
@@ -233,6 +229,12 @@ const DuplicationControls3D = () => {
}
}, [axisConstraint, camera, duplicatedObjects]);
const clearDuplication = useCallback(() => {
duplicatedObjects.forEach((obj: THREE.Object3D) => {
removeAsset(obj.userData.modelUuid);
});
}, [duplicatedObjects, removeAsset]);
const duplicateSelection = useCallback(() => {
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
const positions: Record<string, THREE.Vector3> = {};
@@ -564,56 +566,58 @@ const DuplicationControls3D = () => {
projectId,
};
if (!builderSocket?.connected) {
// REST
removeAssetFromScene(data.modelUuid, () => {
if (!builderSocket?.connected) {
// REST
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, position.y, position.z],
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
isLocked: false,
isVisible: true,
eventData: eventData,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
eventData: data.data.eventData,
};
updateAssetInScene(model, () => {
echo.log(`Duplicated asset: ${model.modelName}`);
});
} else {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
}
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, position.y, position.z],
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
isLocked: false,
isVisible: true,
eventData: eventData,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.catch(() => {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
eventData: data.data.eventData,
};
builderSocket.emit("v1:model-asset:duplicate", data);
}
updateAssetInScene(model, () => {
echo.log(`Duplicated asset: ${model.modelName}`);
});
} else {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
}
})
.catch(() => {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
builderSocket.emit("v1:model-asset:duplicate", data);
}
});
} else {
const data = {
organization,
@@ -630,54 +634,56 @@ const DuplicationControls3D = () => {
userId,
};
if (!builderSocket?.connected) {
// REST
removeAssetFromScene(data.modelUuid, () => {
if (!builderSocket?.connected) {
// REST
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, position.y, position.z],
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
isLocked: false,
isVisible: true,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
};
updateAssetInScene(model, () => {
echo.log(`Duplicated asset: ${model.modelUuid}`);
});
} else {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
}
setAssetsApi({
modelUuid: newFloorItem.modelUuid,
modelName: newFloorItem.modelName,
assetId: newFloorItem.assetId,
position: [position.x, position.y, position.z],
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
isLocked: false,
isVisible: true,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
})
.catch(() => {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
return;
}
if (data.message === "Model created successfully" && data.data) {
const model: Asset = {
modelUuid: data.data.modelUuid,
modelName: data.data.modelName,
assetId: data.data.assetId,
position: data.data.position,
rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z],
isLocked: data.data.isLocked,
isCollidable: true,
isVisible: data.data.isVisible,
opacity: 1,
};
builderSocket.emit("v1:model-asset:duplicate", data);
}
updateAssetInScene(model, () => {
echo.log(`Duplicated asset: ${model.modelUuid}`);
});
} else {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
}
})
.catch(() => {
echo.error(`Error duplicating asset: ${newFloorItem.modelUuid}`);
clearSelection();
});
} else {
// SOCKET
builderSocket.emit("v1:model-asset:duplicate", data);
}
});
}
assetsToDuplicate.push({

View File

@@ -221,6 +221,36 @@ function MoveControls3D({ boundingBoxRef }: any) {
}, 50);
}, [movedObjects, initialStates, updateAsset]);
const resetToInitialPosition = useCallback(
(modelUuid: string, callBack?: () => void) => {
setTimeout(() => {
const movedObject = movedObjects.find((obj: THREE.Object3D) => obj.userData.modelUuid === modelUuid);
if (!movedObject) return;
const initialState = initialStates[movedObject.uuid];
if (!initialState) return;
const positionArray: [number, number, number] = [initialState.position.x, initialState.position.y, initialState.position.z];
updateAsset(modelUuid, {
position: positionArray,
rotation: [initialState.rotation?.x || 0, initialState.rotation?.y || 0, initialState.rotation?.z || 0],
});
movedObject.position.copy(initialState.position);
if (initialState.rotation) {
movedObject.rotation.copy(initialState.rotation);
}
setAxisConstraint(null);
if (callBack) callBack();
}, 50);
},
[movedObjects, initialStates, updateAsset]
);
useEffect(() => {
if (movedObjects.length > 0) {
const intersectionPoint = new THREE.Vector3();
@@ -413,7 +443,7 @@ function MoveControls3D({ boundingBoxRef }: any) {
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error moving asset: ${newFloorItem.modelUuid}`);
resetToInitialPositions();
resetToInitialPosition(newFloorItem.modelUuid);
clearSelection();
return;
}
@@ -437,13 +467,13 @@ function MoveControls3D({ boundingBoxRef }: any) {
});
} else {
echo.error(`Error moving asset: ${newFloorItem.modelUuid}`);
resetToInitialPositions();
resetToInitialPosition(newFloorItem.modelUuid);
clearSelection();
}
})
.catch(() => {
echo.error(`Error moving asset: ${newFloorItem.modelUuid}`);
resetToInitialPositions();
resetToInitialPosition(newFloorItem.modelUuid);
clearSelection();
});
} else {

View File

@@ -202,6 +202,34 @@ function RotateControls3D() {
}, 50);
}, [rotatedObjects, initialRotations, initialPositions, updateAsset]);
const resetToInitialRotation = useCallback(
(modelUuid: string) => {
setTimeout(() => {
const obj = rotatedObjects.find((o: THREE.Object3D) => o.userData.modelUuid === modelUuid);
if (!obj) return;
const uuid = obj.uuid;
const initialRotation = initialRotations[uuid];
const initialPosition = initialPositions[uuid];
if (initialRotation && initialPosition) {
const rotationArray: [number, number, number] = [initialRotation.x, initialRotation.y, initialRotation.z];
const positionArray: [number, number, number] = [initialPosition.x, initialPosition.y, initialPosition.z];
updateAsset(modelUuid, {
rotation: rotationArray,
position: positionArray,
});
obj.rotation.copy(initialRotation);
obj.position.copy(initialPosition);
}
}, 50);
},
[rotatedObjects, initialRotations, initialPositions, updateAsset]
);
useFrame(() => {
if (!isRotating || rotatedObjects.length === 0) return;