Add MQTT URL to environment variables and refactor simulation components

This commit is contained in:
Jerald-Golden-B 2025-03-28 19:10:49 +05:30
parent 813f620b4d
commit f46f29b88c
19 changed files with 1971 additions and 1164 deletions

View File

@ -9,3 +9,6 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
# Base URL for the server marketplace API. # Base URL for the server marketplace API.
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
# Base URL for the server mqtt.
REACT_APP_SERVER_MQTT_URL=185.100.212.76:23457

View File

@ -10,7 +10,7 @@ import {
SimulationIcon, SimulationIcon,
} from "../../icons/SimulationIcons"; } from "../../icons/SimulationIcons";
import useToggleStore from "../../../store/useUIToggleStore"; import useToggleStore from "../../../store/useUIToggleStore";
import MachineMechanics from "./mechanics/MachineMechanics"; import ConveyorMechanics from "./mechanics/ConveyorMechanics";
import Visualization from "./visualization/Visualization"; import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis"; import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations"; import Simulations from "./simulation/Simulations";
@ -18,6 +18,7 @@ import { useSelectedActionSphere } from "../../../store/store";
import GlobalProperties from "./properties/GlobalProperties"; import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties"; import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties"; import ZoneProperties from "./properties/ZoneProperties";
import VehicleMechanics from "./mechanics/VehicleMechanics";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
@ -98,17 +99,24 @@ const SideBarRight: React.FC = () => {
{toggleUI && activeModule === "simulation" && ( {toggleUI && activeModule === "simulation" && (
<> <>
{subModule === "mechanics" && selectedActionSphere && ( {subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Conveyor" && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<MachineMechanics /> <ConveyorMechanics />
</div>
</div>
)}
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <VehicleMechanics /> */}
</div> </div>
</div> </div>
)} )}
{subModule === "mechanics" && !selectedActionSphere && ( {subModule === "mechanics" && !selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
{/* <MachineMechanics /> */} <ConveyorMechanics />
</div> </div>
</div> </div>
)} )}

View File

@ -0,0 +1,586 @@
import React, { useRef, useState, useMemo, useEffect } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
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';
import InputToggle from "../../../ui/inputs/InputToggle";
const ConveyorMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = 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]);
const handleAddAction = () => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => {
if (path.type === "Conveyor") {
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] };
}
return point;
}),
};
}
return path;
});
setSimulationPaths(updatedPaths);
};
const handleDeleteAction = (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.filter(action => action.uuid !== uuid) }
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleActionSelect = (uuid: string, actionType: 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: 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: '',
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]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
<div className="machine-mechanics-content-container">
{!selectedPath &&
<>
<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">
{selectedPoint?.actions.map((action) => (
<div
key={action.uuid}
className={`list-item ${selectedItem?.type === "action" &&
selectedItem.item?.uuid === action.uuid
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "action", item: action })}
>
<RenameInput value={action.name} />
</div>
<div
className="remove-button"
onClick={() => handleDeleteAction(action.uuid)}
>
<RemoveIcon />
</div>
</div>
))}
</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="properties-header">{selectedItem.item.name}</div>
{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)}
/>
{/* 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)}
/>
)}
{/* 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
);
}}
/>
)}
{/* 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)}
/>
</>
)}
</>
)}
{selectedPath && !selectedItem && (
<div className="speed-control">
<InputWithDropDown
label="Conveyor 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.
</div>
</div>
</div>
);
};
export default ConveyorMechanics;

View File

@ -1,533 +0,0 @@
import React, { useRef, useState, useMemo, useEffect } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
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 InputToggle from "../../../ui/inputs/InputToggle";
const MachineMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null);
const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null;
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
}, [selectedActionSphere, simulationPaths]);
const handleAddAction = () => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...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] };
}
return point;
}),
}));
setSimulationPaths(updatedPaths);
};
const handleDeleteAction = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
: point
),
}));
setSimulationPaths(updatedPaths);
};
const handleActionSelect = (uuid: string, actionType: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
// Reset dependent fields when type changes
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
}
: action
),
}
: point
),
}));
setSimulationPaths(updatedPaths);
// Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
const updatedAction = updatedPaths
.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,
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
),
}));
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,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}));
setSimulationPaths(updatedPaths);
};
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action
),
}
: point
),
}));
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,
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: '',
isUsed: false
};
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}));
setSimulationPaths(updatedPaths);
};
const handleDeleteTrigger = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
: point
),
}));
setSimulationPaths(updatedPaths);
};
const handleTriggerSelect = (uuid: string, triggerType: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({
...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
),
}));
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,
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
),
}));
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,
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
),
}));
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]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name 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">
{selectedPoint?.actions.map((action) => (
<div
key={action.uuid}
className={`list-item ${selectedItem?.type === "action" &&
selectedItem.item?.uuid === action.uuid
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "action", item: action })}
>
<RenameInput value={action.name} />
</div>
<div
className="remove-button"
onClick={() => handleDeleteAction(action.uuid)}
>
<RemoveIcon />
</div>
</div>
))}
</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="properties-header">{selectedItem.item.name}</div>
{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)}
/>
{/* 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)}
/>
)}
{/* 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
);
}}
/>
)}
{/* 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)}
/>
</>
)}
</>
)}
{selectedPath && !selectedItem && (
<div className="speed-control">
<InputWithDropDown
label="Path 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.
</div>
</div>
</div>
);
};
export default MachineMechanics;

View File

@ -0,0 +1,561 @@
import React, { useRef, useState, useMemo, useEffect } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
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';
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 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]);
const handleAddAction = () => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => {
if (path.type === "Conveyor") {
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] };
}
return point;
}),
};
}
return path;
});
setSimulationPaths(updatedPaths);
};
const handleDeleteAction = (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.filter(action => action.uuid !== uuid) }
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleActionSelect = (uuid: string, actionType: 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: 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: '',
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]);
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name 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="properties-header">{selectedItem.item.name}</div>
{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)}
/>
{/* 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)}
/>
)}
{/* 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
);
}}
/>
)}
{/* 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)}
/>
</>
)}
</>
)}
{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.
</div>
</div>
</div>
);
};
export default VehicleMechanics;

View File

@ -34,15 +34,11 @@ export default function NavMeshDetails({
const [positions, indices] = getPositionsAndIndices(meshes); const [positions, indices] = getPositionsAndIndices(meshes);
const cs = 0.5; const cs = 0.25;
const ch = 0.5; const ch = 0.5;
const walkableRadius = 0.89; const walkableRadius = 0.5;
const { success, navMesh } = generateSoloNavMesh(positions, indices, { const { success, navMesh } = generateSoloNavMesh(positions, indices, { cs, ch, walkableRadius: Math.round(walkableRadius / ch), });
cs,
ch,
walkableRadius: Math.round(walkableRadius / ch),
});
if (!success || !navMesh) { if (!success || !navMesh) {
return; return;
@ -53,7 +49,7 @@ export default function NavMeshDetails({
const debugDrawer = new DebugDrawer(); const debugDrawer = new DebugDrawer();
debugDrawer.drawNavMesh(navMesh); debugDrawer.drawNavMesh(navMesh);
// scene.add(debugDrawer); // scene.add(debugDrawer);
} catch (error) {} } catch (error) { }
}; };
initializeNavigation(); initializeNavigation();

View File

@ -86,7 +86,7 @@ export default function PathNavigator({
return ( return (
<> <>
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />} {/* {path.length > 0 && <Line points={path} color="blue" lineWidth={3} />} */}
{path.length > 0 && ( {path.length > 0 && (
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}> <mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
<boxGeometry args={[1, 1, 1]} /> <boxGeometry args={[1, 1, 1]} />

View File

@ -43,66 +43,46 @@ export default function PolygonGenerator({
const lineFeatures = result?.map((line: any) => const lineFeatures = result?.map((line: any) =>
turf.lineString(line.map((p: any) => p?.position)) turf.lineString(line.map((p: any) => p?.position))
); );
const polygons = turf.polygonize(turf.featureCollection(lineFeatures)); const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
renderWallGeometry(wallPoints); renderWallGeometry(wallPoints);
let union: any = []; if (polygons.features.length > 1) {
polygons.features.forEach((feature) => {
if (feature.geometry.type === "Polygon") {
polygons.features.forEach((feature) => { const shape = new THREE.Shape();
union.push(feature); const coords = feature.geometry.coordinates[0];
});
if (union.length > 1) { shape.moveTo(coords[0][0], coords[0][1]);
const unionResult = turf.union(turf.featureCollection(union));
if (unionResult?.geometry.type === "MultiPolygon") { for (let i = 1; i < coords.length; i++) {
unionResult.geometry.coordinates.forEach((poly) => { shape.lineTo(coords[i][0], coords[i][1]);
const coordinates = poly[0].map(([x, z]) => {
return new THREE.Vector3(x, 0, z);
});
renderBoxGeometry(coordinates);
});
} else if (unionResult?.geometry.type === "Polygon") {
const coordinates = unionResult.geometry.coordinates[0].map(
([x, z]) => {
return new THREE.Vector3(x, 0, z);
} }
); shape.lineTo(coords[0][0], coords[0][1]);
renderBoxGeometry(coordinates);
} const extrudeSettings = {
} else if (union.length === 1) { depth: 5,
const coordinates = union[0].geometry.coordinates[0].map( bevelEnabled: false,
([x, z]: [number, number]) => { };
return new THREE.Vector3(x, 0, z);
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(Math.PI / 2);
mesh.name = "agv-collider";
mesh.position.y = 5;
mesh.receiveShadow = true;
groupRef.current?.add(mesh);
} }
); });
// setRooms((prevRooms) => [...prevRooms, coordinates]);
} }
}, [lines.current]); }, [lines.current]);
const renderBoxGeometry = (coordinates: THREE.Vector3[]) => {
const minX = Math.min(...coordinates.map((p) => p.x));
const maxX = Math.max(...coordinates.map((p) => p.x));
const minZ = Math.min(...coordinates.map((p) => p.z));
const maxZ = Math.max(...coordinates.map((p) => p.z));
const width = maxX - minX;
const depth = maxZ - minZ;
const height = 3;
const geometry = new THREE.BoxGeometry(width, height, depth);
const material = new THREE.MeshBasicMaterial({
color: "#ff66cc",
visible: false,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set((minX + maxX) / 2, height / 2, (minZ + maxZ) / 2);
groupRef.current?.add(mesh);
};
const renderWallGeometry = (walls: THREE.Vector3[][]) => { const renderWallGeometry = (walls: THREE.Vector3[][]) => {
walls.forEach((wall) => { walls.forEach((wall) => {
if (wall.length < 2) return; if (wall.length < 2) return;

View File

@ -78,7 +78,7 @@ const CamModelsGroup = () => {
socket.off('userDisConnectRespones'); socket.off('userDisConnectRespones');
socket.off('cameraUpdateResponse'); socket.off('cameraUpdateResponse');
}; };
}, [socket]); }, [socket, activeUsers]);
useFrame(() => { useFrame(() => {
if (!groupRef.current) return; if (!groupRef.current) return;

View File

@ -49,7 +49,6 @@ export default function Scene() {
<MeasurementTool /> <MeasurementTool />
<World /> <World />
<ZoneCentreTarget /> <ZoneCentreTarget />
{/* <Simulation /> */}
<Simulation /> <Simulation />
<PostProcessing /> <PostProcessing />
<Sun /> <Sun />
@ -58,9 +57,6 @@ export default function Scene() {
<MqttEvents /> <MqttEvents />
<Environment files={background} environmentIntensity={1.5} /> <Environment files={background} environmentIntensity={1.5} />
</Canvas> </Canvas>
</KeyboardControls> </KeyboardControls>
); );
} }

View File

@ -1,43 +1,29 @@
import { useFloorItems } from '../../../store/store'; import { useFloorItems, useSimulationPaths } from '../../../store/store';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes'; import * as Types from '../../../types/world/worldTypes';
import { useEffect } from 'react'; import { useEffect } from 'react';
interface Path { function Behaviour() {
modeluuid: string; const { setSimulationPaths } = useSimulationPaths();
modelName: string;
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
pathPosition: [number, number, number];
pathRotation: [number, number, number];
speed: number;
}
function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
const { floorItems } = useFloorItems(); const { floorItems } = useFloorItems();
useEffect(() => { useEffect(() => {
const newPaths: Path[] = []; const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
floorItems.forEach((item: Types.FloorItemType) => { floorItems.forEach((item: Types.FloorItemType) => {
if (item.modelfileID === "6633215057b31fe671145959") { if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
const point1Position = new THREE.Vector3(0, 1.25, 3.3); const point1Position = new THREE.Vector3(0, 0.85, 2.2);
const middlePointPosition = new THREE.Vector3(0, 1.25, 0); const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
const point2Position = new THREE.Vector3(0, 1.25, -3.3); const point2Position = new THREE.Vector3(0, 0.85, -2.2);
const point1UUID = THREE.MathUtils.generateUUID(); const point1UUID = THREE.MathUtils.generateUUID();
const middlePointUUID = THREE.MathUtils.generateUUID(); const middlePointUUID = THREE.MathUtils.generateUUID();
const point2UUID = THREE.MathUtils.generateUUID(); const point2UUID = THREE.MathUtils.generateUUID();
const newPath: Path = { const newPath: Types.ConveyorEventsSchema = {
modeluuid: item.modeluuid, modeluuid: item.modeluuid,
modelName: item.modelname, modelName: item.modelname,
type: 'Conveyor',
points: [ points: [
{ {
uuid: point1UUID, uuid: point1UUID,
@ -64,12 +50,32 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] }, connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
}, },
], ],
pathPosition: [...item.position], assetPosition: [...item.position],
pathRotation: [item.rotation.x, item.rotation.y, item.rotation.z], assetRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
speed: 1, speed: 1,
}; };
newPaths.push(newPath); newPaths.push(newPath);
} else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 1.3, 0);
const newVehiclePath: Types.VehicleEventsSchema = {
modeluuid: item.modeluuid,
modelName: item.modelname,
type: 'Vehicle',
point: {
uuid: pointUUID,
position: [pointPosition.x, pointPosition.y, pointPosition.z],
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: THREE.MathUtils.generateUUID(), hitCount: 1, end: THREE.MathUtils.generateUUID(), buffer: 0, isUsed: false }],
triggers: [],
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
},
assetPosition: [...item.position],
speed: 2,
};
newPaths.push(newVehiclePath);
} }
}); });

View File

@ -1,6 +1,7 @@
import { useFrame, useThree } from '@react-three/fiber'; import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes';
import { QuadraticBezierLine } from '@react-three/drei'; import { QuadraticBezierLine } from '@react-three/drei';
import { useIsConnecting, useSimulationPaths } from '../../../store/store'; import { useIsConnecting, useSimulationPaths } from '../../../store/store';
import useModuleStore from '../../../store/useModuleStore'; import useModuleStore from '../../../store/useModuleStore';
@ -27,61 +28,113 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
toPointUUID: string toPointUUID: string
) => { ) => {
const updatedPaths = simulationPaths.map(path => { const updatedPaths = simulationPaths.map(path => {
if (path.modeluuid === fromPathUUID) { if (path.type === 'Conveyor') {
return { if (path.modeluuid === fromPathUUID) {
...path, return {
points: path.points.map(point => { ...path,
if (point.uuid === fromPointUUID) { points: path.points.map(point => {
const newTarget = { if (point.uuid === fromPointUUID) {
pathUUID: toPathUUID, const newTarget = {
pointUUID: toPointUUID pathUUID: toPathUUID,
}; pointUUID: toPointUUID
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID &&
target.pointUUID === newTarget.pointUUID
)) {
return {
...point,
connections: {
...point.connections,
targets: [...existingTargets, newTarget]
}
}; };
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID &&
target.pointUUID === newTarget.pointUUID
)) {
return {
...point,
connections: {
...point.connections,
targets: [...existingTargets, newTarget]
}
};
}
} }
} return point;
return point; })
}) };
}; }
else if (path.modeluuid === toPathUUID) {
return {
...path,
points: path.points.map(point => {
if (point.uuid === toPointUUID) {
const reverseTarget = {
pathUUID: fromPathUUID,
pointUUID: fromPointUUID
};
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID
)) {
return {
...point,
connections: {
...point.connections,
targets: [...existingTargets, reverseTarget]
}
};
}
}
return point;
})
};
}
} }
else if (path.modeluuid === toPathUUID) { else if (path.type === 'Vehicle') {
return { // Handle outgoing connections from Vehicle
...path, if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
points: path.points.map(point => { const newTarget = {
if (point.uuid === toPointUUID) { pathUUID: toPathUUID,
const reverseTarget = { pointUUID: toPointUUID
pathUUID: fromPathUUID, };
pointUUID: fromPointUUID const existingTargets = path.point.connections.targets || [];
};
const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target => if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID && target.pathUUID === newTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID target.pointUUID === newTarget.pointUUID
)) { )) {
return { return {
...point, ...path,
connections: { point: {
...point.connections, ...path.point,
targets: [...existingTargets, reverseTarget] connections: {
} ...path.point.connections,
}; targets: [...existingTargets, newTarget]
}
} }
} };
return point; }
}) }
}; // Handle incoming connections to Vehicle
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) {
const reverseTarget = {
pathUUID: fromPathUUID,
pointUUID: fromPointUUID
};
const existingTargets = path.point.connections.targets || [];
if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID
)) {
return {
...path,
point: {
...path.point,
connections: {
...path.point.connections,
targets: [...existingTargets, reverseTarget]
}
}
};
}
}
} }
return path; return path;
}); });
@ -126,25 +179,43 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
if (intersects.length > 0) { if (intersects.length > 0) {
const intersected = intersects[0].object; const intersected = intersects[0].object;
if (intersected.name.includes("action-sphere")) { if (intersected.name.includes("events-sphere")) {
const pathUUID = intersected.userData.path.modeluuid; const pathUUID = intersected.userData.path.modeluuid;
const sphereUUID = intersected.uuid; const sphereUUID = intersected.uuid;
const worldPosition = new THREE.Vector3(); const worldPosition = new THREE.Vector3();
intersected.getWorldPosition(worldPosition); intersected.getWorldPosition(worldPosition);
const isStartOrEnd = intersected.userData.path.points.length > 0 && ( let isStartOrEnd = false;
sphereUUID === intersected.userData.path.points[0].uuid ||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid if (intersected.userData.path.points) {
); isStartOrEnd = intersected.userData.path.points.length > 0 && (
sphereUUID === intersected.userData.path.points[0].uuid ||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
);
} else if (intersected.userData.path.point) {
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid;
}
if (pathUUID) { if (pathUUID) {
// Check if sphere is already connected const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
const isAlreadyConnected = simulationPaths.some(path => const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
path.points.some(point =>
point.uuid === sphereUUID && if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
point.connections.targets.length > 0 console.log("Cannot connect two vehicle paths together");
) return;
); }
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
}
return false;
});
if (isAlreadyConnected) { if (isAlreadyConnected) {
console.log("Sphere is already connected. Ignoring."); console.log("Sphere is already connected. Ignoring.");
@ -211,6 +282,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
raycaster.setFromCamera(pointer, camera); raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) => const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) =>
!intersect.object.name.includes("Roof") && !intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject && !intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper") !(intersect.object.type === "GridHelper")
@ -229,7 +301,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) => const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
obj.object.name.includes("action-sphere") obj.object.name.includes("events-sphere")
); );
if (sphereIntersects.length > 0) { if (sphereIntersects.length > 0) {
@ -237,27 +309,45 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const sphereUUID = sphere.uuid; const sphereUUID = sphere.uuid;
const spherePosition = new THREE.Vector3(); const spherePosition = new THREE.Vector3();
sphere.getWorldPosition(spherePosition); sphere.getWorldPosition(spherePosition);
const pathUUID = sphere.userData.path.modeluuid; const pathData = sphere.userData.path;
const pathUUID = pathData.modeluuid;
const isStartOrEnd = sphere.userData.path.points.length > 0 && ( const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID);
sphereUUID === sphere.userData.path.points[0].uuid || const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
);
const isAlreadyConnected = simulationPaths.some(path => const isConnectable = (pathData.type === 'Vehicle' ||
path.points.some(point => (pathData.points.length > 0 && (
point.uuid === sphereUUID && sphereUUID === pathData.points[0].uuid ||
point.connections.targets.length > 0 sphereUUID === pathData.points[pathData.points.length - 1].uuid
) ))) && !isVehicleToVehicle;
);
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
}
return false;
});
if ( if (
!isAlreadyConnected && !isAlreadyConnected &&
!isVehicleToVehicle &&
firstSelected.sphereUUID !== sphereUUID && firstSelected.sphereUUID !== sphereUUID &&
firstSelected.pathUUID !== pathUUID && firstSelected.pathUUID !== pathUUID &&
(firstSelected.isCorner || isStartOrEnd) (firstSelected.isCorner || isConnectable)
) { ) {
snappedSphere = { sphereUUID, position: spherePosition, pathUUID, isCorner: isStartOrEnd }; snappedSphere = {
sphereUUID,
position: spherePosition,
pathUUID,
isCorner: isConnectable
};
} else { } else {
isInvalidConnection = true; isInvalidConnection = true;
} }
@ -281,8 +371,13 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
end: point, end: point,
mid: midPoint, mid: midPoint,
}); });
console.log({
start: firstSelected.position,
end: point,
mid: midPoint,
});
setIsConnecting(true); // setIsConnecting(true);
if (sphereIntersects.length > 0) { if (sphereIntersects.length > 0) {
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542'); setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');
@ -299,13 +394,53 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
}); });
// Render connections from simulationPaths
return ( return (
<> <>
{simulationPaths.flatMap(path => {simulationPaths.flatMap(path => {
path.points.flatMap(point => if (path.type === 'Conveyor') {
point.connections.targets.map((target, index) => { return path.points.flatMap(point =>
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid); point.connections.targets.map((target, index) => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
if (targetPath?.type === 'Vehicle') return null;
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
if (fromSphere && toSphere) {
const fromWorldPosition = new THREE.Vector3();
const toWorldPosition = new THREE.Vector3();
fromSphere.getWorldPosition(fromWorldPosition);
toSphere.getWorldPosition(toWorldPosition);
const distance = fromWorldPosition.distanceTo(toWorldPosition);
const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3(
(fromWorldPosition.x + toWorldPosition.x) / 2,
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
(fromWorldPosition.z + toWorldPosition.z) / 2
);
return (
<QuadraticBezierLine
key={`${point.uuid}-${target.pointUUID}-${index}`}
start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()}
mid={midPoint.toArray()}
color="white"
lineWidth={4}
dashed
dashSize={0.75}
dashScale={20}
/>
);
}
return null;
})
);
} else if (path.type === 'Vehicle') {
return path.point.connections.targets.map((target, index) => {
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID); const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
if (fromSphere && toSphere) { if (fromSphere && toSphere) {
@ -325,22 +460,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return ( return (
<QuadraticBezierLine <QuadraticBezierLine
key={`${point.uuid}-${target.pointUUID}-${index}`} key={`${path.point.uuid}-${target.pointUUID}-${index}`}
start={fromWorldPosition.toArray()} start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()} end={toWorldPosition.toArray()}
mid={midPoint.toArray()} mid={midPoint.toArray()}
color="white" color="orange"
lineWidth={4} lineWidth={4}
dashed dashed
dashSize={1} dashSize={0.75}
dashScale={20} dashScale={20}
/> />
); );
} }
return null; return null;
}) });
) }
)} return [];
})}
{currentLine && ( {currentLine && (
<QuadraticBezierLine <QuadraticBezierLine

View File

@ -4,10 +4,12 @@ import { Sphere, TransformControls } from '@react-three/drei';
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store'; import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
import { useFrame, useThree } from '@react-three/fiber'; import { useFrame, useThree } from '@react-three/fiber';
import { useSubModuleStore } from '../../../store/useModuleStore'; import { useSubModuleStore } from '../../../store/useModuleStore';
import { point } from '@turf/helpers';
interface Path { interface ConveyorEventsSchema {
modeluuid: string; modeluuid: string;
modelName: string; modelName: string;
type: 'Conveyor';
points: { points: {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
@ -16,8 +18,8 @@ interface Path {
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[]; }[];
pathPosition: [number, number, number]; assetPosition: [number, number, number];
pathRotation: [number, number, number]; assetRotation: [number, number, number];
speed: number; speed: number;
} }
@ -63,99 +65,154 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
const updateSimulationPaths = () => { const updateSimulationPaths = () => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths: Path[] = simulationPaths.map((path) => ({ const updatedPaths = simulationPaths.map((path) => {
...path, if (path.type === "Conveyor") {
points: path.points.map((point) => return {
point.uuid === selectedActionSphere.point.uuid ...path,
? { points: path.points.map((point) =>
...point, point.uuid === selectedActionSphere.point.uuid
position: [ ? {
selectedActionSphere.point.position.x, ...point,
selectedActionSphere.point.position.y, position: [
selectedActionSphere.point.position.z, selectedActionSphere.point.position.x,
], selectedActionSphere.point.position.y,
rotation: [ selectedActionSphere.point.position.z,
selectedActionSphere.point.rotation.x, ],
selectedActionSphere.point.rotation.y, rotation: [
selectedActionSphere.point.rotation.z, selectedActionSphere.point.rotation.x,
] selectedActionSphere.point.rotation.y,
} selectedActionSphere.point.rotation.z,
: point ]
), }
})); : point
),
};
}
return path;
}) as ConveyorEventsSchema[];
setSimulationPaths(updatedPaths); setSimulationPaths(updatedPaths);
}; };
return ( return (
<group name='simulation-simulationPaths-group' ref={pathsGroupRef} > <group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
{simulationPaths.map((path) => { {simulationPaths.map((path) => {
const points = path.points.map(point => new THREE.Vector3(...point.position)); if (path.type === 'Conveyor') {
const points = path.points.map(point => new THREE.Vector3(...point.position));
return ( return (
<group <group
name={`${path.modeluuid}-event-path`} name={`${path.modeluuid}-event-path`}
key={path.modeluuid} key={path.modeluuid}
ref={el => (groupRefs.current[path.modeluuid] = el!)} ref={el => (groupRefs.current[path.modeluuid] = el!)}
position={path.pathPosition} position={path.assetPosition}
rotation={path.pathRotation} rotation={path.assetRotation}
onClick={(e) => { onClick={(e) => {
if (isConnecting) return; if (isConnecting) return;
e.stopPropagation(); e.stopPropagation();
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
setSelectedActionSphere(null); setSelectedActionSphere(null);
setTransformMode(null); setTransformMode(null);
setSubModule('mechanics'); setSubModule('mechanics');
}} }}
onPointerMissed={() => { onPointerMissed={() => {
setSelectedPath(null); setSelectedPath(null);
setSubModule('properties'); setSubModule('properties');
}} }}
> >
{path.points.map((point, index) => ( {path.points.map((point, index) => (
<Sphere
key={point.uuid}
uuid={point.uuid}
position={point.position}
args={[0.15, 32, 32]}
name='events-sphere'
ref={el => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
if (isConnecting) return;
e.stopPropagation();
setSelectedActionSphere({
path,
point: sphereRefs.current[point.uuid]
});
setSubModule('mechanics');
setSelectedPath(null);
}}
userData={{ point, path }}
onPointerMissed={() => {
setSubModule('properties');
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
/>
</Sphere>
))}
{points.slice(0, -1).map((point, index) => {
const nextPoint = points[index + 1];
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
return (
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
<meshStandardMaterial transparent opacity={0.9} color="red" />
</mesh>
);
})}
</group>
);
} else if (path.type === 'Vehicle') {
return (
<group
name={`${path.modeluuid}-vehicle-path`}
key={path.modeluuid}
ref={el => (groupRefs.current[path.modeluuid] = el!)}
position={path.assetPosition}
onClick={(e) => {
if (isConnecting) return;
e.stopPropagation();
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
setSelectedActionSphere(null);
setTransformMode(null);
setSubModule('mechanics');
}}
onPointerMissed={() => {
setSelectedPath(null);
setSubModule('properties');
}}
>
<Sphere <Sphere
key={point.uuid} key={path.point.uuid}
uuid={point.uuid} uuid={path.point.uuid}
position={point.position} position={path.point.position}
args={[0.15, 32, 32]} args={[0.15, 32, 32]}
name='action-sphere' name='events-sphere'
ref={el => (sphereRefs.current[point.uuid] = el!)} ref={el => (sphereRefs.current[path.point.uuid] = el!)}
onClick={(e) => { onClick={(e) => {
if (isConnecting) return; if (isConnecting) return;
e.stopPropagation(); e.stopPropagation();
setSelectedActionSphere({ setSelectedActionSphere({
path, path,
point: sphereRefs.current[point.uuid] point: sphereRefs.current[path.point.uuid]
}); });
setSubModule('mechanics'); setSubModule('mechanics');
setSelectedPath(null); setSelectedPath(null);
}} }}
userData={{ point, path }} userData={{ point: path.point, path }}
onPointerMissed={() => { onPointerMissed={() => {
setSubModule('properties'); setSubModule('properties');
setSelectedActionSphere(null) setSelectedActionSphere(null);
}} }}
> >
<meshStandardMaterial <meshStandardMaterial color="purple" />
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
/>
</Sphere> </Sphere>
))} </group>
);
{points.slice(0, -1).map((point, index) => { }
const nextPoint = points[index + 1]; return null;
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
return (
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
<meshStandardMaterial transparent opacity={0.9} color="red" />
</mesh>
);
})}
</group>
);
})} })}
{selectedActionSphere && transformMode && ( {selectedActionSphere && transformMode && (
@ -163,7 +220,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
ref={transformRef} ref={transformRef}
object={selectedActionSphere.point} object={selectedActionSphere.point}
mode={transformMode} mode={transformMode}
onObjectChange={updateSimulationPaths} onMouseUp={updateSimulationPaths}
/> />
)} )}
</group> </group>

View File

@ -31,7 +31,7 @@ function Simulation() {
return ( return (
<> <>
<Behaviour setSimulationPaths={setSimulationPaths} /> <Behaviour/>
{activeModule === 'simulation' && ( {activeModule === 'simulation' && (
<> <>
<PathCreation pathsGroupRef={pathsGroupRef} /> <PathCreation pathsGroupRef={pathsGroupRef} />

View File

@ -1,409 +1,409 @@
import { useMemo, useState } from 'react'; // import { useMemo, useState } from 'react';
import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store'; // import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
import * as THREE from 'three'; // import * as THREE from 'three';
import useModuleStore from '../../store/useModuleStore'; // import useModuleStore from '../../store/useModuleStore';
function SimulationUI() { // function SimulationUI() {
const { ToggleView } = useToggleView(); // const { ToggleView } = useToggleView();
const { activeModule } = useModuleStore(); // const { activeModule } = useModuleStore();
const { startSimulation, setStartSimulation } = useStartSimulation(); // const { startSimulation, setStartSimulation } = useStartSimulation();
const { selectedActionSphere } = useSelectedActionSphere(); // const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath(); // const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); // const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath(); // const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
const [activeButton, setActiveButton] = useState<string | null>(null); // const [activeButton, setActiveButton] = useState<string | null>(null);
const handleAddAction = () => { // const handleAddAction = () => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => { // points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) { // if (point.uuid === selectedActionSphere.point.uuid) {
const actionIndex = point.actions.length; // const actionIndex = point.actions.length;
const newAction = { // const newAction = {
uuid: THREE.MathUtils.generateUUID(), // uuid: THREE.MathUtils.generateUUID(),
name: `Action ${actionIndex + 1}`, // Assign action name based on index // name: `Action ${actionIndex + 1}`, // Assign action name based on index
type: 'Inherit', // type: 'Inherit',
material: 'Inherit', // material: 'Inherit',
delay: 'Inherit', // delay: 'Inherit',
spawnInterval: 'Inherit', // spawnInterval: 'Inherit',
isUsed: false // isUsed: false
}; // };
return { ...point, actions: [...point.actions, newAction] }; // return { ...point, actions: [...point.actions, newAction] };
} // }
return point; // return point;
}), // }),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleDeleteAction = (uuid: string) => { // const handleDeleteAction = (uuid: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) } // ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleActionSelect = (uuid: string, actionType: string) => { // const handleActionSelect = (uuid: string, actionType: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
actions: point.actions.map((action) => // actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, type: actionType } : action // action.uuid === uuid ? { ...action, type: actionType } : action
), // ),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleMaterialSelect = (uuid: string, material: string) => { // const handleMaterialSelect = (uuid: string, material: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
actions: point.actions.map((action) => // actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, material } : action // action.uuid === uuid ? { ...action, material } : action
), // ),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleDelayChange = (uuid: string, delay: number | string) => { // const handleDelayChange = (uuid: string, delay: number | string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
actions: point.actions.map((action) => // actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action // action.uuid === uuid ? { ...action, delay } : action
), // ),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => { // const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
actions: point.actions.map((action) => // actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action // action.uuid === uuid ? { ...action, spawnInterval } : action
), // ),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleSpeedChange = (speed: number) => { // const handleSpeedChange = (speed: number) => {
if (!selectedPath) return; // if (!selectedPath) return;
const updatedPaths = simulationPaths.map((path) => // const updatedPaths = simulationPaths.map((path) =>
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path // path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
); // );
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); // setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
}; // };
const handleAddTrigger = () => { // const handleAddTrigger = () => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => { // points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) { // if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length; // const triggerIndex = point.triggers.length;
const newTrigger = { // const newTrigger = {
uuid: THREE.MathUtils.generateUUID(), // uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`, // Assign name based on index // name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
type: '', // type: '',
isUsed: false // isUsed: false
}; // };
return { ...point, triggers: [...point.triggers, newTrigger] }; // return { ...point, triggers: [...point.triggers, newTrigger] };
} // }
return point; // return point;
}), // }),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleDeleteTrigger = (uuid: string) => { // const handleDeleteTrigger = (uuid: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) } // ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleTriggerSelect = (uuid: string, triggerType: string) => { // const handleTriggerSelect = (uuid: string, triggerType: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
triggers: point.triggers.map((trigger) => // triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger // trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
), // ),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleResetPath = () => { // const handleResetPath = () => {
if (!selectedPath) return; // if (!selectedPath) return;
}; // };
const handleActionToggle = (uuid: string) => { // const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
actions: point.actions.map((action) => ({ // actions: point.actions.map((action) => ({
...action, // ...action,
isUsed: action.uuid === uuid ? !action.isUsed : false, // isUsed: action.uuid === uuid ? !action.isUsed : false,
})), // })),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const handleTriggerToggle = (uuid: string) => { // const handleTriggerToggle = (uuid: string) => {
if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationPaths.map((path) => ({
...path, // ...path,
points: path.points.map((point) => // points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.point.uuid
? { // ? {
...point, // ...point,
triggers: point.triggers.map((trigger) => ({ // triggers: point.triggers.map((trigger) => ({
...trigger, // ...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false, // isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})), // })),
} // }
: point // : point
), // ),
})); // }));
setSimulationPaths(updatedPaths); // setSimulationPaths(updatedPaths);
}; // };
const selectedPoint = useMemo(() => { // const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null; // if (!selectedActionSphere) return null;
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid); // return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
}, [selectedActionSphere, simulationPaths]); // }, [selectedActionSphere, simulationPaths]);
const createPath = () => { // const createPath = () => {
setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null); // setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
setDrawMaterialPath(!drawMaterialPath); // setDrawMaterialPath(!drawMaterialPath);
} // }
return ( // return (
<> // <>
{activeModule === "simulation" && ( // {activeModule === "simulation" && (
<div style={{ zIndex: 10, position: "fixed", width: '260px' }}> // <div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
{!ToggleView && ( // {!ToggleView && (
<> // <>
<button // <button
onClick={() => setStartSimulation(!startSimulation)} // onClick={() => setStartSimulation(!startSimulation)}
style={{ // style={{
marginTop: "10px", // marginTop: "10px",
background: startSimulation ? '#ff320e' : '', // background: startSimulation ? '#ff320e' : '',
padding: "10px", // padding: "10px",
borderRadius: "5px" // borderRadius: "5px"
}} // }}
> // >
{startSimulation ? 'Stop Simulation' : 'Start Simulation'} // {startSimulation ? 'Stop Simulation' : 'Start Simulation'}
</button> // </button>
<div style={{ zIndex: "10", position: "relative" }}> // <div style={{ zIndex: "10", position: "relative" }}>
{!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>} // {!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
</div> // </div>
{selectedPath && ( // {selectedPath && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<label>Path Speed:</label> // <label>Path Speed:</label>
<input // <input
style={{ width: '50px' }} // style={{ width: '50px' }}
type="number" // type="number"
value={selectedPath.path.speed} // value={selectedPath.path.speed}
min="0.1" // min="0.1"
step="0.1" // step="0.1"
onChange={(e) => handleSpeedChange(parseFloat(e.target.value))} // onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
/> // />
</div> // </div>
)} // )}
{selectedActionSphere && ( // {selectedActionSphere && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<button onClick={handleAddAction}>Add Action</button> // <button onClick={handleAddAction}>Add Action</button>
<button onClick={handleAddTrigger}>Add Trigger</button> // <button onClick={handleAddTrigger}>Add Trigger</button>
{selectedPoint?.actions.map((action) => ( // {selectedPoint?.actions.map((action) => (
<div key={action.uuid} style={{ marginTop: "10px" }}> // <div key={action.uuid} style={{ marginTop: "10px" }}>
<select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}> // <select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}>
<option value="Inherit">Inherit</option> // <option value="Inherit">Inherit</option>
<option value="Spawn">Spawn Point</option> // <option value="Spawn">Spawn Point</option>
<option value="Swap">Swap Material</option> // <option value="Swap">Swap Material</option>
<option value="Despawn">Despawn Point</option> // <option value="Despawn">Despawn Point</option>
<option value="Delay">Delay</option> // <option value="Delay">Delay</option>
</select> // </select>
<button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button> // <button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button>
<label> // <label>
<input // <input
type="checkbox" // type="checkbox"
checked={action.isUsed} // checked={action.isUsed}
onChange={() => handleActionToggle(action.uuid)} // onChange={() => handleActionToggle(action.uuid)}
/> // />
</label> // </label>
{(action.type === 'Spawn' || action.type === 'Swap') && ( // {(action.type === 'Spawn' || action.type === 'Swap') && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}> // <select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}>
<option value="Inherit">Inherit</option> // <option value="Inherit">Inherit</option>
<option value="Crate">Crate</option> // <option value="Crate">Crate</option>
<option value="Box">Box</option> // <option value="Box">Box</option>
</select> // </select>
</div> // </div>
)} // )}
{action.type === 'Delay' && ( // {action.type === 'Delay' && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<label>Delay Time:</label> // <label>Delay Time:</label>
<input // <input
style={{ width: '50px' }} // style={{ width: '50px' }}
type="text" // type="text"
value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay} // value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay}
min="1" // min="1"
onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')} // onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
/> // />
</div> // </div>
)} // )}
{action.type === 'Spawn' && ( // {action.type === 'Spawn' && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<label>Spawn Interval:</label> // <label>Spawn Interval:</label>
<input // <input
style={{ width: '50px' }} // style={{ width: '50px' }}
type="text" // type="text"
value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval} // value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval}
min="1" // min="1"
onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')} // onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
/> // />
</div> // </div>
)} // )}
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} /> // <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
</div> // </div>
))} // ))}
<hr style={{ margin: "10px 0", border: "1px solid black" }} /> // <hr style={{ margin: "10px 0", border: "1px solid black" }} />
{selectedPoint?.triggers.map((trigger) => ( // {selectedPoint?.triggers.map((trigger) => (
<div key={trigger.uuid} style={{ marginTop: "10px" }}> // <div key={trigger.uuid} style={{ marginTop: "10px" }}>
<select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}> // <select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}>
<option value="">Select Trigger Type</option> // <option value="">Select Trigger Type</option>
<option value="On-Hit">On Hit</option> // <option value="On-Hit">On Hit</option>
<option value="Buffer">Buffer</option> // <option value="Buffer">Buffer</option>
</select> // </select>
<button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button> // <button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button>
<label> // <label>
<input // <input
type="checkbox" // type="checkbox"
checked={trigger.isUsed} // checked={trigger.isUsed}
onChange={() => handleTriggerToggle(trigger.uuid)} // onChange={() => handleTriggerToggle(trigger.uuid)}
/> // />
</label> // </label>
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} /> // <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
</div> // </div>
))} // ))}
</div> // </div>
)} // )}
{selectedPath && ( // {selectedPath && (
<div style={{ marginTop: "10px" }}> // <div style={{ marginTop: "10px" }}>
<button // <button
onClick={handleResetPath} // onClick={handleResetPath}
style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }} // style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }}
> // >
Reset Path // Reset Path
</button> // </button>
</div> // </div>
)} // )}
</> // </>
)} // )}
</div> // </div>
)} // )}
</> // </>
); // );
} // }
export default SimulationUI; // export default SimulationUI;

View File

@ -64,7 +64,6 @@ const Project: React.FC = () => {
{activeModule === "market" && <MarketPlace />} {activeModule === "market" && <MarketPlace />}
<RealTimeVisulization /> <RealTimeVisulization />
{activeModule !== "market" && <Tools />} {activeModule !== "market" && <Tools />}
{/* <SimulationUI /> */}
{isPlaying && activeModule === "simulation" && <SimulationPlayer />} {isPlaying && activeModule === "simulation" && <SimulationPlayer />}
</div> </div>
); );

View File

@ -6,10 +6,7 @@ const MqttEvents = () => {
const { setTouch, setTemperature, setHumidity } = useDrieUIValue(); const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
useEffect(() => { useEffect(() => {
const client = mqtt.connect("ws://192.168.0.192:1884", { const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
username: "gabby",
password: "gabby"
});
client.subscribe("touch"); client.subscribe("touch");
client.subscribe("temperature"); client.subscribe("temperature");

View File

@ -2,7 +2,6 @@ import * as THREE from "three";
import * as Types from "../types/world/worldTypes"; import * as Types from "../types/world/worldTypes";
import { create } from "zustand"; import { create } from "zustand";
import { io } from "socket.io-client"; import { io } from "socket.io-client";
import { ComponentType, SVGProps } from "react";
export const useSocketStore = create<any>((set: any, get: any) => ({ export const useSocketStore = create<any>((set: any, get: any) => ({
socket: null, socket: null,
@ -31,8 +30,8 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
})); }));
export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void }>((set) => ({ export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void }>((set) => ({
loadingProgress: 1, loadingProgress: 1,
setLoadingProgress: (x: number) => set({ loadingProgress: x }), setLoadingProgress: (x: number) => set({ loadingProgress: x }),
})); }));
export const useOrganization = create<any>((set: any) => ({ export const useOrganization = create<any>((set: any) => ({
@ -311,30 +310,14 @@ export const useSelectedPath = create<any>((set: any) => ({
setSelectedPath: (x: any) => set({ selectedPath: x }), setSelectedPath: (x: any) => set({ selectedPath: x }),
})); }));
interface Path {
modeluuid: string;
modelName: string;
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
pathPosition: [number, number, number];
pathRotation: [number, number, number];
speed: number;
}
interface SimulationPathsStore { interface SimulationPathsStore {
simulationPaths: Path[]; simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
setSimulationPaths: (paths: Path[]) => void; setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void;
} }
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({ export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
simulationPaths: [], simulationPaths: [],
setSimulationPaths: (paths: Path[]) => set({ simulationPaths: paths }), setSimulationPaths: (paths) => set({ simulationPaths: paths }),
})); }));
export const useIsConnecting = create<any>((set: any) => ({ export const useIsConnecting = create<any>((set: any) => ({

View File

@ -284,4 +284,36 @@ interface ConnectionStore {
setConnections: (connections: PathConnection[]) => void; setConnections: (connections: PathConnection[]) => void;
addConnection: (newConnection: PathConnection) => void; addConnection: (newConnection: PathConnection) => void;
removeConnection: (fromUUID: string, toUUID: string) => void; removeConnection: (fromUUID: string, toUUID: string) => void;
}
interface ConveyorEventsSchema {
modeluuid: string;
modelName: string;
type: 'Conveyor';
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
assetPosition: [number, number, number];
assetRotation: [number, number, number];
speed: number;
}
interface VehicleEventsSchema {
modeluuid: string;
modelName: string;
type: 'Vehicle';
point: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
};
assetPosition: [number, number, number];
speed: number;
} }