added ui and integerated ui for the vehicle mechanics

This commit is contained in:
2025-03-29 12:58:54 +05:30
parent 1ce24a64f1
commit 13732a5679
12 changed files with 156 additions and 544 deletions

View File

@@ -109,7 +109,7 @@ const SideBarRight: React.FC = () => {
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <VehicleMechanics /> */}
<VehicleMechanics />
</div>
</div>
)}

View File

@@ -8,9 +8,7 @@ import {
import RenameInput from "../../../ui/inputs/RenameInput";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { handleResize } from "../../../../functions/handleResizePannel";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
@@ -428,9 +426,18 @@ const ConveyorMechanics: React.FC = () => {
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
{!selectedPath &&
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
}
{selectedPath &&
<div className="machine-mechanics-header">
{selectedPath.path.modelName || "path name not found"}
</div>
}
<div className="machine-mechanics-content-container">
{!selectedPath &&
@@ -632,10 +639,18 @@ const ConveyorMechanics: React.FC = () => {
</div>
)}
</div>
<div className="footer">
<InfoIcon />
By selecting points, you can create events and triggers.
</div>
{!selectedPath && (
<div className="footer">
<InfoIcon />
Configure the point's action and trigger properties.
</div>
)}
{selectedPath && (
<div className="footer">
<InfoIcon />
Configure the path properties.
</div>
)}
</div>
</div>
);

View File

@@ -1,562 +1,128 @@
import React, { useRef, useState, useMemo, useEffect } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { handleResize } from "../../../../functions/handleResizePannel";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
import * as THREE from 'three';
import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import InputToggle from "../../../ui/inputs/InputToggle";
const VehicleMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null);
const propertiesContainerRef = useRef<HTMLDivElement>(null);
const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null;
return simulationPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.flatMap((path) => path.points)
.find((point) => point.uuid === selectedActionSphere.point.uuid);
}, [selectedActionSphere, simulationPaths]);
if (!selectedActionSphere?.point?.uuid) return null;
const handleAddAction = () => {
if (!selectedActionSphere) return;
const vehiclePaths = simulationPaths.filter(
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
);
return vehiclePaths.find(
(path) => path.point.uuid === selectedActionSphere.point.uuid
)?.point;
}, [selectedActionSphere, simulationPaths, selectedActionSphere?.point?.uuid]);
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => {
if (!selectedActionSphere?.point?.uuid) return;
const updatedPaths = simulationPaths.map((path) => {
if (path.type === "Conveyor") {
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
return {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const actionIndex = point.actions.length;
const newAction = {
uuid: THREE.MathUtils.generateUUID(),
name: `Action ${actionIndex + 1}`,
type: 'Inherit',
material: 'Inherit',
delay: 'Inherit',
spawnInterval: 'Inherit',
isUsed: false
};
return { ...point, actions: [...point.actions, newAction] };
point: {
...path.point,
actions: {
...path.point.actions,
...updatedAction
}
return point;
}),
}
};
}
return path;
});
setSimulationPaths(updatedPaths);
};
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
const handleDeleteAction = (uuid: string) => {
if (!selectedActionSphere) return;
const handleStartPositionChange = React.useCallback((position: string) => {
handleActionUpdate({ start: position });
}, [handleActionUpdate]);
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
: point
),
}
: path
);
const handleEndPositionChange = React.useCallback((position: string) => {
handleActionUpdate({ end: position });
}, [handleActionUpdate]);
setSimulationPaths(updatedPaths);
};
const handleHitCountChange = React.useCallback((hitCount: number) => {
handleActionUpdate({ hitCount });
}, [handleActionUpdate]);
const handleActionSelect = (uuid: string, actionType: string) => {
if (!selectedActionSphere) return;
const handleBufferChange = React.useCallback((buffer: number) => {
handleActionUpdate({ buffer });
}, [handleActionUpdate]);
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
}
: action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
const updatedAction = updatedPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.flatMap(path => path.points)
.find(p => p.uuid === selectedActionSphere.point.uuid)
?.actions.find(a => a.uuid === uuid);
if (updatedAction) {
setSelectedItem({
type: "action",
item: updatedAction
});
}
}
};
// Modified handleMaterialSelect to ensure it only applies to relevant action types
const handleMaterialSelect = (uuid: string, material: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === 'Spawn' || action.type === 'Swap')
? { ...action, material }
: action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Update selected item if it's the current action
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
material
}
});
}
};
const handleDelayChange = (uuid: string, delay: number | string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleSpeedChange = (speed: number) => {
if (!selectedPath) return;
const updatedPaths = simulationPaths.map((path) =>
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
);
setSimulationPaths(updatedPaths);
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
};
const handleAddTrigger = () => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: '',
bufferTime: 0,
isUsed: false
};
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleDeleteTrigger = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleTriggerSelect = (uuid: string, triggerType: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
// Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
});
}
};
// Do the same for trigger toggle
const handleTriggerToggle = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
// Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
setSelectedItem({
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
});
}
};
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
useEffect(() => {
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
}, [selectedActionSphere]);
const handleSpeedChange = React.useCallback((speed: number) => {
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
{selectedActionSphere?.path?.modelName || "Vehicle point not found"}
</div>
<div className="machine-mechanics-content-container">
<div className="actions">
<div className="header">
<div className="header-value">Actions</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
<>
{console.log(selectedPoint)}
</>
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="triggers">
<div className="header">
<div className="header-value">Triggers</div>
<div className="add-button" onClick={handleAddTrigger}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={triggersContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{selectedPoint?.triggers.map((trigger) => (
<div
key={trigger.uuid}
className={`list-item ${selectedItem?.type === "trigger" &&
selectedItem.item?.uuid === trigger.uuid
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
>
<RenameInput value={trigger.name} />
</div>
<div
className="remove-button"
onClick={() => handleDeleteTrigger(trigger.uuid)}
>
<RemoveIcon />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="trigger-resize"
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="selected-properties-container">
{selectedItem && (
<div className="selected-properties-container" ref={propertiesContainerRef}>
<div className="properties-header">Vehicle Properties</div>
{selectedPoint && (
<>
<div className="properties-header">{selectedItem.item.name}</div>
<EyeDropInput
key={`start-${selectedPoint.uuid}`}
label="Start Position"
value={selectedPoint.actions.start}
onChange={handleStartPositionChange}
/>
{selectedItem.type === "action" && (
<>
<InputToggle
inputKey="enableTrigger"
label="Enable Trigger"
value={selectedItem.item.isUsed}
onClick={() => handleActionToggle(selectedItem.item.uuid)}
/>
<LabledDropdown
defaultOption={selectedItem.item.type}
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
/>
<EyeDropInput
key={`end-${selectedPoint.uuid}`}
label="End Position"
value={selectedPoint.actions.end}
onChange={handleEndPositionChange}
/>
{/* Only show material dropdown for Spawn/Swap actions */}
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
<LabledDropdown
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]}
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
/>
)}
<InputWithDropDown
key={`hitcount-${selectedPoint.uuid}`}
label="Hit Count"
value={selectedPoint.actions.hitCount.toString()}
onChange={(value) => handleHitCountChange(parseInt(value))}
/>
{/* Only show delay input for Delay actions */}
{selectedItem.item.type === 'Delay' && (
<InputWithDropDown
label="Delay Time"
value={selectedItem.item.delay === 'Inherit'
? undefined
: selectedItem.item.delay}
onChange={(value) => {
const numValue = parseInt(value);
handleDelayChange(
selectedItem.item.uuid,
!value ? 'Inherit' : numValue
);
}}
/>
)}
<InputWithDropDown
key={`buffer-${selectedPoint.uuid}`}
label="Buffer Time"
value={selectedPoint.actions.buffer.toString()}
onChange={(value) => handleBufferChange(parseInt(value))}
/>
{/* Only show spawn interval for Spawn actions */}
{selectedItem.item.type === 'Spawn' && (
<InputWithDropDown
label="Spawn Interval"
min={0}
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
onChange={(value) => {
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
}}
/>
)}
</>
)}
{selectedItem.type === "trigger" && (
<>
<InputToggle
inputKey="enableTrigger"
label="Enable Trigger"
value={selectedItem.item.isUsed}
onClick={() => handleTriggerToggle(selectedItem.item.uuid)}
/>
<LabledDropdown
defaultOption={selectedItem.item.type || "Select Trigger Type"}
options={["On-Hit", "Buffer"]}
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
/>
</>
)}
<InputWithDropDown
key={`speed-${selectedPoint.uuid}`}
label="Vehicle Speed"
value={selectedPoint.speed.toString()}
onChange={(value) => handleSpeedChange(parseFloat(value))}
/>
</>
)}
{selectedPath && !selectedItem && (
<div className="speed-control">
<InputWithDropDown
label="ConveyorEventsSchema Speed"
value={selectedPath.path.speed.toString()}
onChange={(value) => handleSpeedChange(parseFloat(value))}
/>
</div>
)}
</div>
<div className="footer">
<InfoIcon />
By selecting points, you can create events and triggers.
Configure vehicle's movement and interaction properties.
</div>
</div>
</div>
);
};
export default VehicleMechanics;
export default React.memo(VehicleMechanics);