diff --git a/src/core/base/BaseRenderer.ts b/src/core/base/BaseRenderer.ts index 01a239f..cd8e9ba 100644 --- a/src/core/base/BaseRenderer.ts +++ b/src/core/base/BaseRenderer.ts @@ -108,7 +108,7 @@ export default abstract class BaseRenderer { } createPointForEntity(item: ItemJson, option?: RendererCudOption): Object3DLike { - const point = this.createPoint(item, option) + let point = this.createPoint(item, option) point.visible = ((typeof item.v !== 'undefined') ? item.v : true) if (item.dt.storeAt?.item) { @@ -118,7 +118,24 @@ export default abstract class BaseRenderer { setUserDataForItem(item, point) this.afterCreateOrUpdatePoint(item, option, point) this.tempViewport.entityManager.appendObject(item.id, point) - this.appendToScene(point) + if (typeof option.getParentObject3D === 'function') { + // 要求添加到指定 父对象 + const parent: THREE.Object3D = option.getParentObject3D(this.tempViewport, item) + if (point instanceof MeshWrap) { + const wrap = point as MeshWrap + const mesh = wrap.manager.wrapToObject3D(wrap) + this.tempViewport.entityManager.replaceObject(item.id, mesh) + parent.add(mesh) + point = mesh + + } else { + parent.add(point) + } + + } else { + // 默认添加到场景中 + this.appendToScene(point) + } return point } @@ -155,13 +172,14 @@ export default abstract class BaseRenderer { if (!rackRenderer) { console.error(`Cannot find renderer for rack type ${rack.t}`) } - const { position, rotation } = rackRenderer.getStorePlacement(rack, item.dt.storeAt.bay, item.dt.storeAt.level, item.dt.storeAt.cell) + const { position, rotation, getParentObject3D } = rackRenderer.getStorePlacement(rack, item.dt.storeAt.bay, item.dt.storeAt.level, item.dt.storeAt.cell) if (!position || !rotation) { console.error(`无法获取物品 ${item.id} 的存储位置`) } option.position = position option.rotation = rotation + option.getParentObject3D = getParentObject3D } if (_.isArray(option?.position) && _.isArray(option?.rotation)) { @@ -312,7 +330,10 @@ export default abstract class BaseRenderer { * 获取物品存储到地堆货位中,返回可存放的位置和角度一个 Position 和 Rotation */ getStorePlacement(storeItem: ItemJson, bay = 0, level = 0, cell = 0) - : { position: [number, number, number], rotation: [number, number, number] } { + : { + position: [number, number, number], rotation: [number, number, number], + getParentObject3D?: (viewport: Viewport, parent: ItemJson) => THREE.Object3D + } { throw new Error(' 不支持库存物品的添加. t=' + this.itemTypeName) } diff --git a/src/core/manager/EnvManager.ts b/src/core/manager/EnvManager.ts index 4a8b5f2..90acf2c 100644 --- a/src/core/manager/EnvManager.ts +++ b/src/core/manager/EnvManager.ts @@ -58,10 +58,6 @@ export default class EnvManager { const env = worldModel.state.runState.currentEnv try { worldModel.backendMessageReceiver.setProjectEnv(worldModel.state.project_uuid, worldModel.state.runState.currentEnvId) - await this.loadInvToModel() - this.stopSubscribe.push( - worldModel.backendMessageReceiver.subscribe('InvUpdate', this.onInvUpdateMessage.bind(this)) - ) this.client = mqtt.connect(env.envConfig.mqtt.websocket, { path: '/mqtt', @@ -75,6 +71,13 @@ export default class EnvManager { }) await this.loadExecutorToModel() + this.stopSubscribe.push( + worldModel.backendMessageReceiver.subscribe('InvUpdate', this.onInvUpdateMessage.bind(this)) + ) + this.stopSubscribe.push( + worldModel.backendMessageReceiver.subscribe('ServerState', this.onServerUpdateMessage.bind(this)) + ) + await this.loadInvToModel() this.client.on('connect', this.onMqttConnect) this.client.on('message', this.onMqttMessage) @@ -87,16 +90,30 @@ export default class EnvManager { } } + /** + * 监听在服务器停机之后,客户端连接也必须停机 + */ + onServerUpdateMessage(type: BackendTopicType, topic: string, data: ServerStatusVo) { + if (worldModel.state.runState.isRunning && worldModel.state.runState.currentEnvId === data.envId) { + // 处理服务器状态更新 + if (!data.isRunning) { + // 如果服务器停止了,则断开连接 + console.log(`Server stopped: ${data.envId}`) + system.msg(`Server is stopped, client disconnect!`, 'warning') + this.disconnectEnv().finally() + } + } + } + async onInvUpdateMessage(type: BackendTopicType, topic: string, body: InvUpdateVo) { + console.log(`InvUpdate: ${type} ${topic}`, body) + if (!window['Model']) { // 如果没有3D模型加载,则不处理库存更新 return } - const lpnItem = Model.find(body.lpn) - if (lpnItem) { - Model.deleteItem(lpnItem.id) - } + Model.deleteInv(body.lpn) if (body.after != null) { // 将托盘挪到目标位置 @@ -223,6 +240,6 @@ export default class EnvManager { * 卸载资源 */ dispose(): void { - this.disconnectEnv() + this.disconnectEnv().finally() } } diff --git a/src/core/script/ModelManager.ts b/src/core/script/ModelManager.ts index b9c06e9..120eb9e 100644 --- a/src/core/script/ModelManager.ts +++ b/src/core/script/ModelManager.ts @@ -85,8 +85,12 @@ export default class ModelManager implements IControls, Model { return position } + deleteInv(itemId) { + this.viewport.runtimeManager.removeEntity(itemId) + } + deleteItem(itemId) { - if(this.viewport.runtimeManager.has(itemId)){ + if (this.viewport.runtimeManager.has(itemId)) { // 临时执行器 this.viewport.runtimeManager.removeEntity(itemId) return diff --git a/src/editor/widgets/server/EnvSelectConnect.vue b/src/editor/widgets/server/EnvSelectConnect.vue index 52de079..5dfda8c 100644 --- a/src/editor/widgets/server/EnvSelectConnect.vue +++ b/src/editor/widgets/server/EnvSelectConnect.vue @@ -55,10 +55,10 @@ export default { methods: { renderIcon, connectEnv() { - worldModel.envManager.connectEnv() + worldModel.envManager.connectEnv().finally() }, disconnectEnv() { - worldModel.envManager.disconnectEnv() + worldModel.envManager.disconnectEnv().finally() }, createEnv() { EnvManager.createEnv(this.worldModelState.project_uuid).then(() => { diff --git a/src/modules/amr/ptr/cl2/Cl2Renderer.ts b/src/modules/amr/ptr/cl2/Cl2Renderer.ts index c1627ee..586ce1e 100644 --- a/src/modules/amr/ptr/cl2/Cl2Renderer.ts +++ b/src/modules/amr/ptr/cl2/Cl2Renderer.ts @@ -1,8 +1,9 @@ import * as THREE from 'three' import BaseRenderer from '@/core/base/BaseRenderer.ts' import Constract from '@/core/Constract.ts' -import Cl23dObject from "./Cl23dObject"; +import Cl23dObject from './Cl23dObject' import type { Object3DLike } from '@/types/ModelTypes.ts' +import type Viewport from '@/core/engine/Viewport.ts' /** * ptr侧叉渲染器 @@ -24,6 +25,39 @@ export default class PtrRenderer extends BaseRenderer { } /** + * 如果某物品要放到 Cl2 上 返回可存放的位置和角度一个 Position 和 Rotation + */ + getStorePlacement(storeItem: ItemJson, bay = 0, level = 0, cell = 0) + : { + position: [number, number, number], rotation: [number, number, number], + getParentObject3D?: (viewport: Viewport, parent: THREE.Object3D) => THREE.Object3D + } { + + return { + position: [0, 0.2, 0], + rotation: [0, 90, 0], + getParentObject3D: this.getArmObject.bind(this) + } + } + + getArmObject(viewport: Viewport, item: ItemJson): THREE.Object3D { + // 获取机械臂对象 + const object = viewport.entityManager.findObjectById(item.dt.storeAt?.item) + if (!object) { + console.warn('PtrRenderer: getArmObject failed, not found Cl2:', item.dt.storeAt?.item) + return + } + + const agv = object as THREE.Group + if (agv.children.length > 1) { + const pillar = agv.children[1] + if (pillar.children.length > 1) { + return pillar.children[1] + } + } + } + + /** * 所有的点,必须使用 storeWidth/storeDepth, 改TF无效 */ override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: THREE.Object3D) { @@ -39,7 +73,6 @@ export default class PtrRenderer extends BaseRenderer { ) } - createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D { throw new Error('not allow store line.') } @@ -51,11 +84,6 @@ export default class PtrRenderer extends BaseRenderer { createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D { // 创建平面几何体 - if (!item.dt.ptrWidth || !item.dt.ptrDepth) { - system.showErrorDialog('field ptrWidth / ptrDepth is null!') - return null - } - const group = new Cl23dObject(item, this.tempViewport, option) group.name = PtrRenderer.POINT_NAME @@ -64,7 +92,6 @@ export default class PtrRenderer extends BaseRenderer { return group } - updatePoint(item: ItemJson, object: Object3DLike, option?: RendererCudOption): Object3DLike { const group: THREE.Group = object as THREE.Group diff --git a/src/modules/rack/RackRenderer.ts b/src/modules/rack/RackRenderer.ts index 21c9f4f..93e0dc9 100644 --- a/src/modules/rack/RackRenderer.ts +++ b/src/modules/rack/RackRenderer.ts @@ -83,7 +83,7 @@ export default class RackRenderer extends BaseRenderer { localX += bays[bay].bayWidth / 2 // 居中 let localY = 0 - for (let i = 0; i < level; i++) { + for (let i = 0; i <= level; i++) { localY += levelHeights[i] } diff --git a/src/types/Model.d.ts b/src/types/Model.d.ts index 17eb8f7..a34e868 100644 --- a/src/types/Model.d.ts +++ b/src/types/Model.d.ts @@ -40,6 +40,11 @@ declare interface Model { */ createInv(boxType: ContainerT, lpn: string, rack: string, bay: number = 0, level: number = 0, cell: number = 0): void + /** + * 根据 ID 删除库存物品 + * @param itemId 物品ID + */ + deleteInv(itemId: string): void /** * 在指定位置创建一个流动的库存物品 diff --git a/src/types/Types.d.ts b/src/types/Types.d.ts index 80f812d..66bd45b 100644 --- a/src/types/Types.d.ts +++ b/src/types/Types.d.ts @@ -63,6 +63,7 @@ interface RendererCudOption { position?: any //THREE.Quaternion rotation?: any + getParentObject3D?: (viewport:any, item: ItemJson) => any } /**