feat: Refactor human action handling to replace animatedTravel with worker actions and enhance animation management

This commit is contained in:
2025-07-03 14:23:57 +05:30
parent 98f4d48db2
commit eb5683eadc
11 changed files with 606 additions and 112 deletions

View File

@@ -0,0 +1,104 @@
import React, { useRef } from "react";
import { AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../../../icons/ExportCommonIcons";
import { handleResize } from "../../../../../../functions/handleResizePannel";
import { useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import RenameInput from "../../../../../ui/inputs/RenameInput";
interface AnimationListProps {
animationOptions: string[];
animationSequences: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null };
}[];
onAddAnimation: () => void;
onRemoveAnimation: (animationUuid: string) => void;
handleAnimationSelect: (animationUuid: string) => void;
handleRenameAnimation: (animationUuid: string, newName: string) => void;
selectedAnimation: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null };
} | undefined
}
const AnimationList: React.FC<AnimationListProps> = ({
animationSequences,
onAddAnimation,
onRemoveAnimation,
handleAnimationSelect,
handleRenameAnimation,
selectedAnimation
}) => {
const animationContainerRef = useRef<HTMLDivElement>(null);
const { selectedAction } = useSelectedAction();
return (
<div className="actions-list-container">
<div className="actions">
<div className="header">
<div className="header-value">Animation Sequences</div>
<button
id="add-action-button"
className="add-button"
onClick={onAddAnimation}
disabled={!selectedAction.actionId}
>
<AddIcon /> Add
</button>
</div>
<div
className="lists-main-container"
ref={animationContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{animationSequences.map((sequence) => (
<div
key={sequence.animationUuid}
className={`list-item ${selectedAnimation?.animationUuid === sequence.animationUuid ? "active" : ""}`}
>
<button
id="action-button"
className="value"
onClick={() =>
handleAnimationSelect(sequence.animationUuid)
}
>
<RenameInput
value={sequence.animationName}
onRename={(value) => handleRenameAnimation(sequence.animationUuid, value)}
/>
</button>
{animationSequences.length > 1 && (
<button
id="remove-action-button"
className="remove-button"
onClick={() => onRemoveAnimation(sequence.animationUuid)}
>
<RemoveIcon />
</button>
)}
</div>
))}
</div>
{animationSequences.length > 0 && (
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, animationContainerRef)}
>
<ResizeHeightIcon />
</button>
)}
</div>
</div>
</div>
);
};
export default AnimationList;

View File

@@ -1,27 +1,38 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { MathUtils } from "three";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput"; import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger"; import Trigger from "../trigger/Trigger";
import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import PickAndPlaceAction from "../actions/PickAndPlaceAction"; import PickAndPlaceAction from "../actions/PickAndPlaceAction";
import ActionsList from "../components/ActionsList";
import AnimationList from "../components/AnimationList";
import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext"; import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
import ActionsList from "../components/ActionsList"; import { useParams } from "react-router-dom";
function HumanMechanics() { function HumanMechanics() {
const [activeOption, setActiveOption] = useState<"animatedTravel">("animatedTravel"); const [activeOption, setActiveOption] = useState<"worker">("worker");
const [animationOptions, setAnimationOptions] = useState<string[]>([]);
const [speed, setSpeed] = useState("0.5"); const [speed, setSpeed] = useState("0.5");
const [currentAction, setCurrentAction] = useState<HumanAction | undefined>(); const [currentAction, setCurrentAction] = useState<HumanAction | undefined>();
const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>(); const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext(); const { productStore, assetStore } = useSceneContext();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore(); const { getAssetById } = assetStore();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = productStore();
const { selectedProductStore } = useProductContext(); const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore(); const { selectedProduct } = selectedProductStore();
const [selectedAnimation, setSelectedAnimation] = useState<{
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
}>();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
const { selectedVersionStore } = useVersionContext(); const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore(); const { selectedVersion } = selectedVersionStore();
@@ -35,10 +46,15 @@ function HumanMechanics() {
selectedEventData.selectedPoint selectedEventData.selectedPoint
) as HumanPointSchema | undefined; ) as HumanPointSchema | undefined;
if (point?.action) { if (point?.actions) {
setSelectedPointData(point); setSelectedPointData(point);
const action = point.action; if (point.actions.length > 0) {
setSelectedAction(action.actionUuid, action.actionName); setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
const asset = getAssetById(selectedEventData.data.modelUuid);
if (asset && asset.animations) {
setAnimationOptions(asset.animations)
}
}
} }
} else { } else {
clearSelectedAction(); clearSelectedAction();
@@ -62,11 +78,16 @@ function HumanMechanics() {
selectedEventData.selectedPoint selectedEventData.selectedPoint
) as HumanPointSchema | undefined; ) as HumanPointSchema | undefined;
if (point?.action) { if (point?.actions) {
setSelectedPointData(point); setSelectedPointData(point);
const action = point.action; const action = point.actions.find((a) => a.actionUuid === selectedAction.actionId);
setCurrentAction(action); if (action) {
setActiveOption(action.actionType as "animatedTravel"); setCurrentAction(action);
setActiveOption(action.actionType as "worker");
if (action.animationSequences.length > 0) {
setSelectedAnimation(action.animationSequences[0]);
}
}
} }
} else { } else {
clearSelectedAction(); clearSelectedAction();
@@ -91,80 +112,387 @@ function HumanMechanics() {
}; };
const handleSelectActionType = (actionType: string) => { const handleSelectActionType = (actionType: string) => {
if (!currentAction) return; if (!selectedAction.actionId || !currentAction || !selectedPointData) return;
setActiveOption(actionType as "animatedTravel");
const updatedAction = {
...currentAction,
actionType: actionType as "worker"
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction( const event = updateAction(
selectedProduct.productUuid, selectedProduct.productUuid,
currentAction.actionUuid, selectedAction.actionId,
{ actionType: actionType as "animatedTravel" } updatedAction
); );
if (event && selectedPointData) {
const updatedAction = { ...selectedPointData.action, actionType: actionType as "animatedTravel" };
setSelectedPointData({ ...selectedPointData, action: updatedAction });
}
if (event) { if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
} }
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
}; };
const handleRenameAction = (newName: string) => { const handleChooseAnimation = (animationOption: string) => {
if (!currentAction) return; if (!selectedAction.actionId || !currentAction || !selectedAnimation || !selectedPointData) return;
const updatedAnimation = {
...selectedAnimation,
animation: animationOption
};
const updatedAction = {
...currentAction,
animationSequences: currentAction.animationSequences.map(anim =>
anim.animationUuid === selectedAnimation.animationUuid ? updatedAnimation : anim
)
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction( const event = updateAction(
selectedProduct.productUuid, selectedProduct.productUuid,
currentAction.actionUuid, selectedAction.actionId,
{ actionName: newName } updatedAction
); );
if (event && selectedPointData) {
const updatedAction = { ...selectedPointData.action, actionName: newName };
setSelectedPointData({ ...selectedPointData, action: updatedAction });
}
if (event) { if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
} }
setCurrentAction(updatedAction);
setSelectedAnimation(updatedAnimation);
setSelectedPointData(updatedPoint);
}; };
const handleSpeedChange = (value: string) => { const handleSpeedChange = (value: string) => {
if (!selectedEventData) return; if (!selectedEventData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
const updatedEvent = {
...selectedEventData.data,
speed: numericValue
} as HumanEventSchema;
const event = updateEvent( const event = updateEvent(
selectedProduct.productUuid, selectedProduct.productUuid,
selectedEventData.data.modelUuid, selectedEventData.data.modelUuid,
{ speed: parseFloat(value) } updatedEvent
); );
if (event) { if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
} }
setSpeed(value);
}; };
const handleClearPoints = () => { const handleClearPoints = (animationUuid: string) => {
if (!currentAction) return; if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAnimation = currentAction.animationSequences.find(anim =>
anim.animationUuid === animationUuid
);
if (!updatedAnimation) return;
updatedAnimation.travelPoints = {
startPoint: null,
endPoint: null
};
const updatedAction = {
...currentAction,
animationSequences: currentAction.animationSequences.map(anim =>
anim.animationUuid === animationUuid ? updatedAnimation : anim
)
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction( const event = updateAction(
selectedProduct.productUuid, selectedProduct.productUuid,
currentAction.actionUuid, selectedAction.actionId,
{ updatedAction
travelPoints: {
startPoint: null,
endPoint: null,
},
}
); );
if (event) { if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
} }
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
if (selectedAnimation?.animationUuid === animationUuid) {
setSelectedAnimation(updatedAnimation);
}
};
const handleAddAction = () => {
if (!selectedEventData || !selectedPointData) return;
const newAction: HumanAction = {
actionUuid: MathUtils.generateUUID(),
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "worker",
animationSequences: [
{
animationUuid: MathUtils.generateUUID(),
animationName: 'Animation 1',
animationType: 'behaviour',
animation: null
}
],
loadCapacity: 1,
triggers: [],
};
const event = addAction(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint,
newAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
const updatedPoint = { ...selectedPointData, actions: [...selectedPointData.actions, newAction] };
setSelectedPointData(updatedPoint);
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
const event = removeAction(selectedProduct.productUuid, actionUuid);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
const index = selectedPointData.actions.findIndex((a) => a.actionUuid === actionUuid);
const newActions = selectedPointData.actions.filter((a) => a.actionUuid !== actionUuid);
const updatedPoint = { ...selectedPointData, actions: newActions };
setSelectedPointData(updatedPoint);
if (selectedAction.actionId === actionUuid) {
const nextAction = newActions[index] || newActions[index - 1];
if (nextAction) {
setSelectedAction(nextAction.actionUuid, nextAction.actionName);
} else {
clearSelectedAction();
}
}
};
const handleAddAnimation = () => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const newAnimation = {
animationUuid: MathUtils.generateUUID(),
animationName: `Animation ${currentAction.animationSequences.length + 1}`,
animationType: 'behaviour' as "behaviour",
animation: null
};
const updatedAction = {
...currentAction,
animationSequences: [...currentAction.animationSequences, newAnimation]
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
setSelectedAnimation(newAnimation);
};
const handleRemoveAnimation = (animationUuid: string) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = {
...currentAction,
animationSequences: currentAction.animationSequences.filter(
anim => anim.animationUuid !== animationUuid
)
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
if (selectedAnimation?.animationUuid === animationUuid) {
setSelectedAnimation(updatedAction.animationSequences[0] || undefined);
}
};
const handleAnimationTypeChange = (animationUuid: string, newType: "behaviour" | "animatedTravel") => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAnimationSequences = currentAction.animationSequences.map(anim => {
if (anim.animationUuid === animationUuid) {
const updatedAnim = {
...anim,
animationType: newType
};
if (newType === 'animatedTravel') {
updatedAnim.travelPoints = {
startPoint: null,
endPoint: null
};
} else {
delete updatedAnim.travelPoints;
}
return updatedAnim;
}
return anim;
});
const updatedAction = {
...currentAction,
animationSequences: updatedAnimationSequences
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
if (selectedAnimation?.animationUuid === animationUuid) {
const updatedAnimation = updatedAnimationSequences.find(anim =>
anim.animationUuid === animationUuid
);
if (updatedAnimation) {
setSelectedAnimation(updatedAnimation);
}
}
};
const handleAnimationSelect = (animationUuid: string) => {
if (!currentAction || !selectedAction.actionId) return;
const animation = currentAction.animationSequences.find(
anim => anim.animationUuid === animationUuid
);
if (animation) {
setSelectedAnimation(animation);
}
};
const handleRenameAnimation = (animationUuid: string, newName: string) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAnimation = currentAction.animationSequences.find(anim =>
anim.animationUuid === animationUuid
);
if (!updatedAnimation) return;
const renamedAnimation = { ...updatedAnimation, animationName: newName };
const updatedAction = {
...currentAction,
animationSequences: currentAction.animationSequences.map(anim =>
anim.animationUuid === animationUuid ? renamedAnimation : anim
)
};
const updatedPoint = {
...selectedPointData,
actions: selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId ? updatedAction : action
)
};
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
if (selectedAnimation?.animationUuid === animationUuid) {
setSelectedAnimation(renamedAnimation);
}
}; };
const availableActions = { const availableActions = {
defaultOption: "animatedTravel", defaultOption: "worker",
options: ["animatedTravel"], options: ["worker"],
}; };
return ( return (
@@ -186,21 +514,20 @@ function HumanMechanics() {
</div> </div>
</div> </div>
</div> </div>
<section>
<ActionsList
selectedPointData={selectedPointData}
multipleAction
handleAddAction={handleAddAction}
handleDeleteAction={handleDeleteAction}
/>
{currentAction && ( {selectedAction.actionId && currentAction && (
<section>
<ActionsList
selectedPointData={selectedPointData}
multipleAction={false}
handleAddAction={() => { }}
handleDeleteAction={() => { }}
/>
<div className="selected-actions-details"> <div className="selected-actions-details">
<div className="selected-actions-header"> <div className="selected-actions-header">
<RenameInput <RenameInput
value={currentAction.actionName || ""} value={selectedAction.actionName || ""}
onRename={handleRenameAction} canEdit={false}
/> />
</div> </div>
<div className="selected-actions-list"> <div className="selected-actions-list">
@@ -211,21 +538,63 @@ function HumanMechanics() {
onSelect={handleSelectActionType} onSelect={handleSelectActionType}
disabled={true} disabled={true}
/> />
{activeOption === 'animatedTravel' && (
<PickAndPlaceAction clearPoints={handleClearPoints} />
)}
</div> </div>
<AnimationList
animationOptions={animationOptions}
animationSequences={currentAction?.animationSequences || []}
onAddAnimation={handleAddAnimation}
onRemoveAnimation={handleRemoveAnimation}
handleAnimationSelect={handleAnimationSelect}
handleRenameAnimation={handleRenameAnimation}
selectedAnimation={selectedAnimation}
/>
{selectedAnimation && (
<>
<div className="selected-actions-header">
<RenameInput
value={selectedAnimation.animationName || ""}
canEdit={false}
/>
</div>
<div className="animation-controls">
<LabledDropdown
label="Animation Type"
defaultOption={selectedAnimation.animationType}
options={["behaviour", "animatedTravel"]}
onSelect={(type) =>
handleAnimationTypeChange(
selectedAnimation.animationUuid,
type as "behaviour" | "animatedTravel"
)
}
/>
<LabledDropdown
label="Animation"
defaultOption={selectedAnimation.animation || ''}
options={animationOptions}
onSelect={handleChooseAnimation}
disabled={true}
/>
{selectedAnimation.animationType === "animatedTravel" && (
<PickAndPlaceAction
clearPoints={() => handleClearPoints(selectedAnimation.animationUuid)}
/>
)}
</div>
</>
)}
<div className="tirgger"> <div className="tirgger">
<Trigger <Trigger
selectedPointData={selectedPointData as any} selectedPointData={selectedPointData as any}
type="Human" type={"Human"}
/> />
</div> </div>
</div> </div>
</section> )}
)} </section>
</> </>
); );
} }
export default HumanMechanics; export default HumanMechanics;

View File

@@ -9,9 +9,10 @@ interface RenameInputProps {
value: string; value: string;
onRename?: (newText: string) => void; onRename?: (newText: string) => void;
checkDuplicate?: (name: string) => boolean; checkDuplicate?: (name: string) => boolean;
canEdit?: boolean;
} }
const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplicate }) => { const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplicate, canEdit = true }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [text, setText] = useState(value); const [text, setText] = useState(value);
const [isDuplicate, setIsDuplicate] = useState(false); const [isDuplicate, setIsDuplicate] = useState(false);
@@ -28,13 +29,15 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplica
}, [text, checkDuplicate]); }, [text, checkDuplicate]);
const handleDoubleClick = () => { const handleDoubleClick = () => {
setIsEditing(true); if (canEdit) {
setTimeout(() => inputRef.current?.focus(), 0); setIsEditing(true);
setTimeout(() => inputRef.current?.focus(), 0);
}
}; };
const handleBlur = () => { const handleBlur = () => {
if(isDuplicate) return if (isDuplicate) return
setIsEditing(false); setIsEditing(false);
if (onRename && !isDuplicate) { if (onRename && !isDuplicate) {
onRename(text); onRename(text);

View File

@@ -256,18 +256,23 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), 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], 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], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: { actions: [
actionUuid: THREE.MathUtils.generateUUID(), {
actionName: "Action 1", actionUuid: THREE.MathUtils.generateUUID(),
actionType: "animatedTravel", actionName: "Action 1",
loadCapacity: 1, actionType: "worker",
travelPoints: { animationSequences: [
startPoint: null, {
endPoint: null, animationUuid: THREE.MathUtils.generateUUID(),
}, animationName: 'Animation 1',
triggers: [] animationType: 'behaviour',
} animation: null
}
],
loadCapacity: 1,
triggers: []
}
]
} }
} }
addEvent(humanEvent); addEvent(humanEvent);

View File

@@ -374,17 +374,23 @@ async function handleModelLoad(
uuid: THREE.MathUtils.generateUUID(), uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z], position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0], rotation: [0, 0, 0],
action: { actions: [
actionUuid: THREE.MathUtils.generateUUID(), {
actionName: "Action 1", actionUuid: THREE.MathUtils.generateUUID(),
actionType: "animatedTravel", actionName: "Action 1",
loadCapacity: 1, actionType: "worker",
travelPoints: { animationSequences: [
startPoint: null, {
endPoint: null, animationUuid: THREE.MathUtils.generateUUID(),
}, animationName: 'Animation 1',
triggers: [] animationType: 'behaviour',
} animation: null
}
],
loadCapacity: 1,
triggers: []
}
]
} }
} }

View File

@@ -2,7 +2,7 @@ import { useCallback } from "react";
import { useSceneContext } from "../../../../scene/sceneContext"; import { useSceneContext } from "../../../../scene/sceneContext";
import { useProductContext } from "../../../products/productContext"; import { useProductContext } from "../../../products/productContext";
export function useAnimatedTravelHandler() { export function useWorkerHandler() {
const { materialStore, humanStore, productStore } = useSceneContext(); const { materialStore, humanStore, productStore } = useSceneContext();
const { getMaterialById } = materialStore(); const { getMaterialById } = materialStore();
const { } = humanStore(); const { } = humanStore();
@@ -10,12 +10,12 @@ export function useAnimatedTravelHandler() {
const { selectedProductStore } = useProductContext(); const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore(); const { selectedProduct } = selectedProductStore();
const animatedTravelLogStatus = (materialUuid: string, status: string) => { const workerLogStatus = (materialUuid: string, status: string) => {
echo.info(`${materialUuid}, ${status}`); echo.info(`${materialUuid}, ${status}`);
} }
const handleAnimatedTravel = useCallback((action: HumanAction, materialId?: string) => { const handleWorker = useCallback((action: HumanAction, materialId?: string) => {
if (!action || action.actionType !== 'animatedTravel' || !materialId) return; if (!action || action.actionType !== 'worker' || !materialId) return;
const material = getMaterialById(materialId); const material = getMaterialById(materialId);
if (!material) return; if (!material) return;
@@ -24,11 +24,11 @@ export function useAnimatedTravelHandler() {
if (!modelUuid) return; if (!modelUuid) return;
animatedTravelLogStatus(material.materialName, `performing animatedTravel`); workerLogStatus(material.materialName, `performing worker action`);
}, [getMaterialById]); }, [getMaterialById]);
return { return {
handleAnimatedTravel, handleWorker,
}; };
} }

View File

@@ -1,24 +1,24 @@
import { useEffect, useCallback } from 'react'; import { useEffect, useCallback } from 'react';
import { useAnimatedTravelHandler } from './actionHandler/useAnimatedTravelHandler'; import { useWorkerHandler } from './actionHandler/useWorkerHandler';
export function useHumanActions() { export function useHumanActions() {
const { handleAnimatedTravel } = useAnimatedTravelHandler(); const { handleWorker } = useWorkerHandler();
const handleAnimatedTravelAction = useCallback((action: HumanAction) => { const handleWorkerAction = useCallback((action: HumanAction) => {
handleAnimatedTravel(action); handleWorker(action);
}, [handleAnimatedTravel]); }, [handleWorker]);
const handleHumanAction = useCallback((action: HumanAction, materialId: string) => { const handleHumanAction = useCallback((action: HumanAction, materialId: string) => {
if (!action) return; if (!action) return;
switch (action.actionType) { switch (action.actionType) {
case 'animatedTravel': case 'worker':
handleAnimatedTravelAction(action); handleWorkerAction(action);
break; break;
default: default:
console.warn(`Unknown Human action type: ${action.actionType}`); console.warn(`Unknown Human action type: ${action.actionType}`);
} }
}, [handleAnimatedTravelAction]); }, [handleWorkerAction]);
const cleanup = useCallback(() => { const cleanup = useCallback(() => {
}, []); }, []);

View File

@@ -39,7 +39,7 @@ export function useActionHandler() {
case 'store': case 'retrieve': case 'store': case 'retrieve':
handleStorageAction(action as StorageAction, materialId as string); handleStorageAction(action as StorageAction, materialId as string);
break; break;
case 'animatedTravel': case 'worker':
handleHumanAction(action as HumanAction, materialId as string); handleHumanAction(action as HumanAction, materialId as string);
break; break;
default: default:

View File

@@ -155,8 +155,8 @@ function TriggerConnector() {
// Handle Human point // Handle Human point
else if (event.type === "human" && 'point' in event) { else if (event.type === "human" && 'point' in event) {
const point = event.point; const point = event.point;
if (point.action?.triggers) { point.actions?.forEach(action => {
point.action.triggers.forEach(trigger => { action.triggers?.forEach(trigger => {
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
newConnections.push({ newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
@@ -166,7 +166,7 @@ function TriggerConnector() {
}); });
} }
}); });
} });
} }
}); });

View File

@@ -32,13 +32,13 @@ type ProductsStore = {
productUuid: string, productUuid: string,
modelUuid: string, modelUuid: string,
pointUuid: string, pointUuid: string,
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action'] action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]
) => EventsSchema | undefined; ) => EventsSchema | undefined;
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined; removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
updateAction: ( updateAction: (
productUuid: string, productUuid: string,
actionUuid: string, actionUuid: string,
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']> updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]>
) => EventsSchema | undefined; ) => EventsSchema | undefined;
// Trigger-level actionss // Trigger-level actionss

View File

@@ -72,9 +72,15 @@ interface StorageAction {
interface HumanAction { interface HumanAction {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "animatedTravel"; actionType: "worker";
animationSequences: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
}[]
loadCapacity: number; loadCapacity: number;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; }
triggers: TriggerSchema[]; triggers: TriggerSchema[];
} }
@@ -120,7 +126,7 @@ interface HumanPointSchema {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
action: HumanAction; actions: HumanAction[];
} }
type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema; type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema;
@@ -229,6 +235,7 @@ interface HumanStatus extends HumanEventSchema {
currentAction?: { currentAction?: {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
animationUuid: string;
materialType?: string | null; materialType?: string | null;
materialId?: string | null; materialId?: string | null;
}; };