Seperate pending messages from artifact map (#3084)
* start of seperating pending message from artifact map * continue migration to sendCommandVersion2 * mostly massage types * process artifact after the fact * clean up
This commit is contained in:
@ -2022,13 +2022,17 @@ export async function getFaceDetails(
|
|||||||
entity_id: entityId,
|
entity_id: entityId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const faceInfo: Models['GetSketchModePlane_type'] = (
|
const resp = await engineCommandManager.sendSceneCommand({
|
||||||
await engineCommandManager.sendSceneCommand({
|
type: 'modeling_cmd_req',
|
||||||
type: 'modeling_cmd_req',
|
cmd_id: uuidv4(),
|
||||||
cmd_id: uuidv4(),
|
cmd: { type: 'get_sketch_mode_plane' },
|
||||||
cmd: { type: 'get_sketch_mode_plane' },
|
})
|
||||||
})
|
const faceInfo =
|
||||||
)?.data?.data
|
resp?.success &&
|
||||||
|
resp?.resp.type === 'modeling' &&
|
||||||
|
resp?.resp?.data?.modeling_response?.type === 'get_sketch_mode_plane'
|
||||||
|
? resp?.resp?.data?.modeling_response.data
|
||||||
|
: ({} as Models['GetSketchModePlane_type'])
|
||||||
await engineCommandManager.sendSceneCommand({
|
await engineCommandManager.sendSceneCommand({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd_id: uuidv4(),
|
cmd_id: uuidv4(),
|
||||||
|
@ -138,15 +138,23 @@ export const ModelingMachineProvider = ({
|
|||||||
|
|
||||||
sceneInfra.camControls.syncDirection = 'engineToClient'
|
sceneInfra.camControls.syncDirection = 'engineToClient'
|
||||||
|
|
||||||
const settings: Models['CameraSettings_type'] = (
|
const resp = await engineCommandManager.sendSceneCommand({
|
||||||
await engineCommandManager.sendSceneCommand({
|
type: 'modeling_cmd_req',
|
||||||
type: 'modeling_cmd_req',
|
cmd_id: uuidv4(),
|
||||||
cmd_id: uuidv4(),
|
cmd: {
|
||||||
cmd: {
|
type: 'default_camera_get_settings',
|
||||||
type: 'default_camera_get_settings',
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
)?.data?.data?.settings
|
const settings =
|
||||||
|
resp &&
|
||||||
|
resp.success &&
|
||||||
|
resp.resp.type === 'modeling' &&
|
||||||
|
resp.resp.data.modeling_response.type ===
|
||||||
|
'default_camera_get_settings'
|
||||||
|
? resp.resp.data.modeling_response.data.settings
|
||||||
|
: ({} as Models['DefaultCameraGetSettings_type']['settings'])
|
||||||
|
|
||||||
if (settings.up.z !== 1) {
|
if (settings.up.z !== 1) {
|
||||||
// workaround for gimbal lock situation
|
// workaround for gimbal lock situation
|
||||||
await engineCommandManager.sendSceneCommand({
|
await engineCommandManager.sendSceneCommand({
|
||||||
|
@ -7,8 +7,6 @@ import { getNodePathFromSourceRange } from 'lang/queryAst'
|
|||||||
import { Themes, getThemeColorForEngine, getOppositeTheme } from 'lib/theme'
|
import { Themes, getThemeColorForEngine, getOppositeTheme } from 'lib/theme'
|
||||||
import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes'
|
import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes'
|
||||||
|
|
||||||
let lastMessage = ''
|
|
||||||
|
|
||||||
// TODO(paultag): This ought to be tweakable.
|
// TODO(paultag): This ought to be tweakable.
|
||||||
const pingIntervalMs = 10000
|
const pingIntervalMs = 10000
|
||||||
|
|
||||||
@ -58,9 +56,6 @@ function isHighlightSetEntity_type(
|
|||||||
|
|
||||||
type WebSocketResponse = Models['WebSocketResponse_type']
|
type WebSocketResponse = Models['WebSocketResponse_type']
|
||||||
type OkWebSocketResponseData = Models['OkWebSocketResponseData_type']
|
type OkWebSocketResponseData = Models['OkWebSocketResponseData_type']
|
||||||
type BatchResponseMap = {
|
|
||||||
[key: string]: Models['BatchResponse_type']
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultCommand = CommandInfo & {
|
type ResultCommand = CommandInfo & {
|
||||||
type: 'result'
|
type: 'result'
|
||||||
@ -1169,6 +1164,15 @@ export enum EngineCommandManagerEvents {
|
|||||||
* It also maintains an {@link artifactMap} that keeps track of the state of each
|
* It also maintains an {@link artifactMap} that keeps track of the state of each
|
||||||
* command, and the artifacts that have been generated by those commands.
|
* command, and the artifacts that have been generated by those commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
interface PendingMessage {
|
||||||
|
command: EngineCommand
|
||||||
|
range: SourceRange
|
||||||
|
idToRangeMap: { [key: string]: SourceRange }
|
||||||
|
resolve: (data: [Models['WebSocketResponse_type']]) => void
|
||||||
|
reject: (reason: string) => void
|
||||||
|
promise: Promise<[Models['WebSocketResponse_type']]>
|
||||||
|
}
|
||||||
export class EngineCommandManager extends EventTarget {
|
export class EngineCommandManager extends EventTarget {
|
||||||
/**
|
/**
|
||||||
* The artifactMap is a client-side representation of the commands that have been sent
|
* The artifactMap is a client-side representation of the commands that have been sent
|
||||||
@ -1182,6 +1186,25 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
* of the KCL code that generated it.
|
* of the KCL code that generated it.
|
||||||
*/
|
*/
|
||||||
artifactMap: ArtifactMap = {}
|
artifactMap: ArtifactMap = {}
|
||||||
|
/**
|
||||||
|
* The pendingCommands object is a map of the commands that have been sent to the engine that are still waiting on a reply
|
||||||
|
*/
|
||||||
|
pendingCommands: {
|
||||||
|
[commandId: string]: PendingMessage
|
||||||
|
} = {}
|
||||||
|
/**
|
||||||
|
* The orderedCommands array of all the the commands sent to the engine, un-folded from batches, and made into one long
|
||||||
|
* list of the individual commands, this is used to process all the commands into the artifactMap
|
||||||
|
*/
|
||||||
|
orderedCommands: {
|
||||||
|
command: EngineCommand
|
||||||
|
range: SourceRange
|
||||||
|
}[] = []
|
||||||
|
/**
|
||||||
|
* A map of the responses to the @this.orderedCommands, when processing the commands into the artifactMap, this response map allow
|
||||||
|
* us to look up the response by command id
|
||||||
|
*/
|
||||||
|
responseMap: { [commandId: string]: OkWebSocketResponseData } = {}
|
||||||
/**
|
/**
|
||||||
* The client-side representation of the scene command artifacts that have been sent to the server;
|
* The client-side representation of the scene command artifacts that have been sent to the server;
|
||||||
* that is, the *non-modeling* commands and corresponding artifacts.
|
* that is, the *non-modeling* commands and corresponding artifacts.
|
||||||
@ -1206,7 +1229,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
defaultPlanes: DefaultPlanes | null = null
|
defaultPlanes: DefaultPlanes | null = null
|
||||||
commandLogs: CommandLog[] = []
|
commandLogs: CommandLog[] = []
|
||||||
pendingExport?: {
|
pendingExport?: {
|
||||||
resolve: (filename?: string) => void
|
resolve: (a: null) => void
|
||||||
reject: (reason: any) => void
|
reject: (reason: any) => void
|
||||||
}
|
}
|
||||||
_commandLogCallBack: (command: CommandLog[]) => void = () => {}
|
_commandLogCallBack: (command: CommandLog[]) => void = () => {}
|
||||||
@ -1435,31 +1458,92 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
// export we send a binary blob.
|
// export we send a binary blob.
|
||||||
// Pass this to our export function.
|
// Pass this to our export function.
|
||||||
exportSave(event.data).then(() => {
|
exportSave(event.data).then(() => {
|
||||||
this.pendingExport?.resolve()
|
this.pendingExport?.resolve(null)
|
||||||
}, this.pendingExport?.reject)
|
}, this.pendingExport?.reject)
|
||||||
} else {
|
return
|
||||||
const message: Models['WebSocketResponse_type'] = JSON.parse(
|
}
|
||||||
event.data
|
|
||||||
)
|
const message: Models['WebSocketResponse_type'] = JSON.parse(event.data)
|
||||||
if (
|
const pending = this.pendingCommands[message.request_id || '']
|
||||||
|
|
||||||
|
if (pending && !message.success) {
|
||||||
|
// handle bad case
|
||||||
|
pending.reject(`engine error: ${JSON.stringify(message.errors)}`)
|
||||||
|
delete this.pendingCommands[message.request_id || '']
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
pending &&
|
||||||
message.success &&
|
message.success &&
|
||||||
(message.resp.type === 'modeling' ||
|
(message.resp.type === 'modeling' ||
|
||||||
message.resp.type === 'modeling_batch') &&
|
message.resp.type === 'modeling_batch')
|
||||||
message.request_id
|
)
|
||||||
) {
|
)
|
||||||
this.handleModelingCommand(
|
return
|
||||||
message.resp,
|
|
||||||
message.request_id,
|
if (
|
||||||
message
|
message.resp.type === 'modeling' &&
|
||||||
)
|
pending.command.type === 'modeling_cmd_req' &&
|
||||||
} else if (
|
message.request_id
|
||||||
!message.success &&
|
) {
|
||||||
message.request_id &&
|
this.addCommandLog({
|
||||||
this.artifactMap[message.request_id]
|
type: 'receive-reliable',
|
||||||
) {
|
data: message.resp,
|
||||||
this.handleFailedModelingCommand(message.request_id, message)
|
id: message?.request_id || '',
|
||||||
}
|
cmd_type: pending?.command?.cmd?.type,
|
||||||
|
})
|
||||||
|
|
||||||
|
const modelingResponse = message.resp.data.modeling_response
|
||||||
|
|
||||||
|
Object.values(
|
||||||
|
this.subscriptions[modelingResponse.type] || {}
|
||||||
|
).forEach((callback) => callback(modelingResponse))
|
||||||
|
|
||||||
|
this.responseMap[message.request_id] = message.resp
|
||||||
|
} else if (
|
||||||
|
message.resp.type === 'modeling_batch' &&
|
||||||
|
pending.command.type === 'modeling_cmd_batch_req'
|
||||||
|
) {
|
||||||
|
let individualPendingResponses: {
|
||||||
|
[key: string]: Models['WebSocketRequest_type']
|
||||||
|
} = {}
|
||||||
|
pending.command.requests.forEach(({ cmd, cmd_id }) => {
|
||||||
|
individualPendingResponses[cmd_id] = {
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd,
|
||||||
|
cmd_id,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Object.entries(message.resp.data.responses).forEach(
|
||||||
|
([key, response]) => {
|
||||||
|
if (!('response' in response)) return
|
||||||
|
const command = individualPendingResponses[key]
|
||||||
|
if (!command) return
|
||||||
|
if (command.type === 'modeling_cmd_req')
|
||||||
|
this.addCommandLog({
|
||||||
|
type: 'receive-reliable',
|
||||||
|
data: {
|
||||||
|
type: 'modeling',
|
||||||
|
data: {
|
||||||
|
modeling_response: response.response,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: key,
|
||||||
|
cmd_type: command?.cmd?.type,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.responseMap[key] = {
|
||||||
|
type: 'modeling',
|
||||||
|
data: {
|
||||||
|
modeling_response: response.response,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pending.resolve([message])
|
||||||
|
delete this.pendingCommands[message.request_id || '']
|
||||||
}) as EventListener)
|
}) as EventListener)
|
||||||
|
|
||||||
this.onEngineConnectionNewTrack = ({
|
this.onEngineConnectionNewTrack = ({
|
||||||
@ -1485,6 +1569,106 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
this.onEngineConnectionStarted
|
this.onEngineConnectionStarted
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
handleIndividualResponse({
|
||||||
|
id,
|
||||||
|
pendingMsg,
|
||||||
|
response,
|
||||||
|
}: {
|
||||||
|
id: string
|
||||||
|
pendingMsg: {
|
||||||
|
command: EngineCommand
|
||||||
|
range: SourceRange
|
||||||
|
}
|
||||||
|
response: OkWebSocketResponseData
|
||||||
|
}) {
|
||||||
|
const command = pendingMsg
|
||||||
|
if (command?.command?.type !== 'modeling_cmd_req') return
|
||||||
|
if (response?.type !== 'modeling') return
|
||||||
|
const command2 = command.command.cmd
|
||||||
|
|
||||||
|
const range = command.range
|
||||||
|
const pathToNode = getNodePathFromSourceRange(this.getAst(), range)
|
||||||
|
const getParentId = (): string | undefined => {
|
||||||
|
if (command2.type === 'extend_path') return command2.path
|
||||||
|
if (command2.type === 'solid3d_get_extrusion_face_info') {
|
||||||
|
const edgeArtifact = this.artifactMap[command2.edge_id]
|
||||||
|
// edges's parent id is to the original "start_path" artifact
|
||||||
|
if (edgeArtifact && edgeArtifact.parentId) {
|
||||||
|
return edgeArtifact.parentId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (command2.type === 'close_path') return command2.path_id
|
||||||
|
if (command2.type === 'extrude') return command2.target
|
||||||
|
// handle other commands that have a parent here
|
||||||
|
}
|
||||||
|
const modelingResponse = response.data.modeling_response
|
||||||
|
|
||||||
|
if (command) {
|
||||||
|
const parentId = getParentId()
|
||||||
|
const artifact = {
|
||||||
|
type: 'result',
|
||||||
|
range: range,
|
||||||
|
pathToNode,
|
||||||
|
commandType: command.command.cmd.type,
|
||||||
|
parentId: parentId,
|
||||||
|
} as ArtifactMapCommand & { extrusions?: string[] }
|
||||||
|
this.artifactMap[id] = artifact
|
||||||
|
if (command2.type === 'extrude') {
|
||||||
|
;(artifact as any).target = command2.target
|
||||||
|
if (this.artifactMap[command2.target]?.commandType === 'start_path') {
|
||||||
|
if ((this.artifactMap[command2.target] as any)?.extrusions?.length) {
|
||||||
|
;(this.artifactMap[command2.target] as any).extrusions.push(id)
|
||||||
|
} else {
|
||||||
|
;(this.artifactMap[command2.target] as any).extrusions = [id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.artifactMap[id] = artifact
|
||||||
|
if (
|
||||||
|
(command2.type === 'entity_linear_pattern' &&
|
||||||
|
modelingResponse.type === 'entity_linear_pattern') ||
|
||||||
|
(command2.type === 'entity_circular_pattern' &&
|
||||||
|
modelingResponse.type === 'entity_circular_pattern')
|
||||||
|
) {
|
||||||
|
const entities = modelingResponse.data.entity_ids
|
||||||
|
entities?.forEach((entity: string) => {
|
||||||
|
this.artifactMap[entity] = artifact
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
command2.type === 'solid3d_get_extrusion_face_info' &&
|
||||||
|
modelingResponse.type === 'solid3d_get_extrusion_face_info'
|
||||||
|
) {
|
||||||
|
const parent = this.artifactMap[parentId || '']
|
||||||
|
modelingResponse.data.faces.forEach((face) => {
|
||||||
|
if (face.cap !== 'none' && face.face_id && parent) {
|
||||||
|
this.artifactMap[face.face_id] = {
|
||||||
|
...parent,
|
||||||
|
commandType: 'solid3d_get_extrusion_face_info',
|
||||||
|
additionalData: {
|
||||||
|
type: 'cap',
|
||||||
|
info: face.cap === 'bottom' ? 'start' : 'end',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const curveArtifact = this.artifactMap[face?.curve_id || '']
|
||||||
|
if (curveArtifact && face?.face_id) {
|
||||||
|
this.artifactMap[face.face_id] = {
|
||||||
|
...curveArtifact,
|
||||||
|
commandType: 'solid3d_get_extrusion_face_info',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (command) {
|
||||||
|
this.artifactMap[id] = {
|
||||||
|
type: 'result',
|
||||||
|
commandType: command2.type,
|
||||||
|
range,
|
||||||
|
pathToNode,
|
||||||
|
} as ArtifactMapCommand & { extrusions?: string[] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleResize({
|
handleResize({
|
||||||
streamWidth,
|
streamWidth,
|
||||||
@ -1509,233 +1693,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
}
|
}
|
||||||
this.engineConnection?.send(resizeCmd)
|
this.engineConnection?.send(resizeCmd)
|
||||||
}
|
}
|
||||||
handleModelingCommand(
|
|
||||||
message: OkWebSocketResponseData,
|
|
||||||
id: string,
|
|
||||||
raw: WebSocketResponse
|
|
||||||
) {
|
|
||||||
if (!(message.type === 'modeling' || message.type === 'modeling_batch')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const command = this.artifactMap[id]
|
|
||||||
let modelingResponse: Models['OkModelingCmdResponse_type'] = {
|
|
||||||
type: 'empty',
|
|
||||||
}
|
|
||||||
if ('modeling_response' in message.data) {
|
|
||||||
modelingResponse = message.data.modeling_response
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
command?.type === 'pending' &&
|
|
||||||
command.commandType === 'batch' &&
|
|
||||||
command?.additionalData?.type === 'batch-ids'
|
|
||||||
) {
|
|
||||||
if ('responses' in message.data) {
|
|
||||||
const batchResponse = message.data.responses as BatchResponseMap
|
|
||||||
// Iterate over the map of responses.
|
|
||||||
Object.entries(batchResponse).forEach(([key, response]) => {
|
|
||||||
// If the response is a success, we resolve the promise.
|
|
||||||
if ('response' in response && response.response) {
|
|
||||||
this.handleModelingCommand(
|
|
||||||
{
|
|
||||||
type: 'modeling',
|
|
||||||
data: {
|
|
||||||
modeling_response: response.response,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
request_id: key,
|
|
||||||
resp: {
|
|
||||||
type: 'modeling',
|
|
||||||
data: {
|
|
||||||
modeling_response: response.response,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
success: true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else if ('errors' in response) {
|
|
||||||
this.handleFailedModelingCommand(key, {
|
|
||||||
request_id: key,
|
|
||||||
success: false,
|
|
||||||
errors: response.errors,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
command.additionalData.ids.forEach((id) => {
|
|
||||||
this.handleModelingCommand(message, id, raw)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// batch artifact is just a container, we don't need to keep it
|
|
||||||
// once we process all the commands inside it
|
|
||||||
const resolve = command.resolve
|
|
||||||
delete this.artifactMap[id]
|
|
||||||
resolve({
|
|
||||||
id,
|
|
||||||
commandType: command.commandType,
|
|
||||||
range: command.range,
|
|
||||||
raw,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const sceneCommand = this.sceneCommandArtifacts[id]
|
|
||||||
this.addCommandLog({
|
|
||||||
type: 'receive-reliable',
|
|
||||||
data: message,
|
|
||||||
id,
|
|
||||||
cmd_type: command?.commandType || sceneCommand?.commandType,
|
|
||||||
})
|
|
||||||
Object.values(this.subscriptions[modelingResponse.type] || {}).forEach(
|
|
||||||
(callback) => callback(modelingResponse)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (command && command.type === 'pending') {
|
|
||||||
const resolve = command.resolve
|
|
||||||
const oldArtifact = this.artifactMap[id] as ArtifactMapCommand & {
|
|
||||||
extrusions?: string[]
|
|
||||||
}
|
|
||||||
const artifact = {
|
|
||||||
type: 'result',
|
|
||||||
range: command.range,
|
|
||||||
pathToNode: command.pathToNode,
|
|
||||||
commandType: command.commandType,
|
|
||||||
parentId: command.parentId ? command.parentId : undefined,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
} as ArtifactMapCommand & { extrusions?: string[] }
|
|
||||||
if (oldArtifact?.extrusions) {
|
|
||||||
artifact.extrusions = oldArtifact.extrusions
|
|
||||||
}
|
|
||||||
this.artifactMap[id] = artifact
|
|
||||||
if (
|
|
||||||
(command.commandType === 'entity_linear_pattern' &&
|
|
||||||
modelingResponse.type === 'entity_linear_pattern') ||
|
|
||||||
(command.commandType === 'entity_circular_pattern' &&
|
|
||||||
modelingResponse.type === 'entity_circular_pattern')
|
|
||||||
) {
|
|
||||||
const entities = modelingResponse.data.entity_ids
|
|
||||||
entities?.forEach((entity: string) => {
|
|
||||||
this.artifactMap[entity] = artifact
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
command?.commandType === 'solid3d_get_extrusion_face_info' &&
|
|
||||||
modelingResponse.type === 'solid3d_get_extrusion_face_info'
|
|
||||||
) {
|
|
||||||
const parent = this.artifactMap[command?.parentId || '']
|
|
||||||
modelingResponse.data.faces.forEach((face) => {
|
|
||||||
if (face.cap !== 'none' && face.face_id && parent) {
|
|
||||||
this.artifactMap[face.face_id] = {
|
|
||||||
...parent,
|
|
||||||
commandType: 'solid3d_get_extrusion_face_info',
|
|
||||||
additionalData: {
|
|
||||||
type: 'cap',
|
|
||||||
info: face.cap === 'bottom' ? 'start' : 'end',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const curveArtifact = this.artifactMap[face?.curve_id || '']
|
|
||||||
if (curveArtifact && face?.face_id) {
|
|
||||||
this.artifactMap[face.face_id] = {
|
|
||||||
...curveArtifact,
|
|
||||||
commandType: 'solid3d_get_extrusion_face_info',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
resolve({
|
|
||||||
id,
|
|
||||||
commandType: command.commandType,
|
|
||||||
range: command.range,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
})
|
|
||||||
} else if (sceneCommand && sceneCommand.type === 'pending') {
|
|
||||||
const resolve = sceneCommand.resolve
|
|
||||||
const artifact = {
|
|
||||||
type: 'result',
|
|
||||||
range: sceneCommand.range,
|
|
||||||
pathToNode: sceneCommand.pathToNode,
|
|
||||||
commandType: sceneCommand.commandType,
|
|
||||||
parentId: sceneCommand.parentId ? sceneCommand.parentId : undefined,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
} as const
|
|
||||||
this.sceneCommandArtifacts[id] = artifact
|
|
||||||
resolve({
|
|
||||||
id,
|
|
||||||
commandType: sceneCommand.commandType,
|
|
||||||
range: sceneCommand.range,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
})
|
|
||||||
} else if (command) {
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
type: 'result',
|
|
||||||
commandType: command?.commandType,
|
|
||||||
range: command?.range,
|
|
||||||
pathToNode: command?.pathToNode,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.sceneCommandArtifacts[id] = {
|
|
||||||
type: 'result',
|
|
||||||
commandType: sceneCommand?.commandType,
|
|
||||||
range: sceneCommand?.range,
|
|
||||||
pathToNode: sceneCommand?.pathToNode,
|
|
||||||
data: modelingResponse,
|
|
||||||
raw,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleFailedModelingCommand(id: string, raw: WebSocketResponse) {
|
|
||||||
const failed = raw as Models['FailureWebSocketResponse_type']
|
|
||||||
const errors = failed.errors
|
|
||||||
if (!id) return
|
|
||||||
const command = this.artifactMap[id]
|
|
||||||
if (command && command.type === 'pending') {
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
type: 'failed',
|
|
||||||
range: command.range,
|
|
||||||
pathToNode: command.pathToNode,
|
|
||||||
commandType: command.commandType,
|
|
||||||
parentId: command.parentId ? command.parentId : undefined,
|
|
||||||
errors,
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
command?.type === 'pending' &&
|
|
||||||
command.commandType === 'batch' &&
|
|
||||||
command?.additionalData?.type === 'batch-ids'
|
|
||||||
) {
|
|
||||||
command.additionalData.ids.forEach((id) => {
|
|
||||||
this.handleFailedModelingCommand(id, raw)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// batch artifact is just a container, we don't need to keep it
|
|
||||||
// once we process all the commands inside it
|
|
||||||
const resolve = command.resolve
|
|
||||||
delete this.artifactMap[id]
|
|
||||||
resolve({
|
|
||||||
id,
|
|
||||||
commandType: command.commandType,
|
|
||||||
range: command.range,
|
|
||||||
errors,
|
|
||||||
raw,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
type: 'failed',
|
|
||||||
range: command.range,
|
|
||||||
pathToNode: command.pathToNode,
|
|
||||||
commandType: command.commandType,
|
|
||||||
parentId: command.parentId ? command.parentId : undefined,
|
|
||||||
errors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tearDown(opts?: { idleMode: boolean }) {
|
tearDown(opts?: { idleMode: boolean }) {
|
||||||
if (this.engineConnection) {
|
if (this.engineConnection) {
|
||||||
this.engineConnection.removeEventListener(
|
this.engineConnection.removeEventListener(
|
||||||
@ -1768,6 +1726,8 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
}
|
}
|
||||||
async startNewSession() {
|
async startNewSession() {
|
||||||
this.artifactMap = {}
|
this.artifactMap = {}
|
||||||
|
this.orderedCommands = []
|
||||||
|
this.responseMap = {}
|
||||||
await this.initPlanes()
|
await this.initPlanes()
|
||||||
}
|
}
|
||||||
subscribeTo<T extends ModelTypes>({
|
subscribeTo<T extends ModelTypes>({
|
||||||
@ -1841,13 +1801,13 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
sendSceneCommand(
|
sendSceneCommand(
|
||||||
command: EngineCommand,
|
command: EngineCommand,
|
||||||
forceWebsocket = false
|
forceWebsocket = false
|
||||||
): Promise<any> {
|
): Promise<Models['WebSocketResponse_type'] | null> {
|
||||||
if (this.engineConnection === undefined) {
|
if (this.engineConnection === undefined) {
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.engineConnection?.isReady()) {
|
if (!this.engineConnection?.isReady()) {
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -1866,19 +1826,13 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
command.type === 'modeling_cmd_req' &&
|
|
||||||
command.cmd.type !== lastMessage
|
|
||||||
) {
|
|
||||||
lastMessage = command.cmd.type
|
|
||||||
}
|
|
||||||
if (command.type === 'modeling_cmd_batch_req') {
|
if (command.type === 'modeling_cmd_batch_req') {
|
||||||
this.engineConnection?.send(command)
|
this.engineConnection?.send(command)
|
||||||
// TODO - handlePendingCommands does not handle batch commands
|
// TODO - handlePendingCommands does not handle batch commands
|
||||||
// return this.handlePendingCommand(command.requests[0].cmd_id, command.cmd)
|
// return this.handlePendingCommand(command.requests[0].cmd_id, command.cmd)
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
}
|
}
|
||||||
if (command.type !== 'modeling_cmd_req') return Promise.resolve()
|
if (command.type !== 'modeling_cmd_req') return Promise.resolve(null)
|
||||||
const cmd = command.cmd
|
const cmd = command.cmd
|
||||||
if (
|
if (
|
||||||
(cmd.type === 'camera_drag_move' ||
|
(cmd.type === 'camera_drag_move' ||
|
||||||
@ -1891,7 +1845,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
;(cmd as any).sequence = this.outSequence
|
;(cmd as any).sequence = this.outSequence
|
||||||
this.outSequence++
|
this.outSequence++
|
||||||
this.engineConnection?.unreliableSend(command)
|
this.engineConnection?.unreliableSend(command)
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
} else if (
|
} else if (
|
||||||
cmd.type === 'highlight_set_entity' &&
|
cmd.type === 'highlight_set_entity' &&
|
||||||
this.engineConnection?.unreliableDataChannel
|
this.engineConnection?.unreliableDataChannel
|
||||||
@ -1899,7 +1853,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
cmd.sequence = this.outSequence
|
cmd.sequence = this.outSequence
|
||||||
this.outSequence++
|
this.outSequence++
|
||||||
this.engineConnection?.unreliableSend(command)
|
this.engineConnection?.unreliableSend(command)
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
} else if (
|
} else if (
|
||||||
cmd.type === 'mouse_move' &&
|
cmd.type === 'mouse_move' &&
|
||||||
this.engineConnection.unreliableDataChannel
|
this.engineConnection.unreliableDataChannel
|
||||||
@ -1907,9 +1861,9 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
cmd.sequence = this.outSequence
|
cmd.sequence = this.outSequence
|
||||||
this.outSequence++
|
this.outSequence++
|
||||||
this.engineConnection?.unreliableSend(command)
|
this.engineConnection?.unreliableSend(command)
|
||||||
return Promise.resolve()
|
return Promise.resolve(null)
|
||||||
} else if (cmd.type === 'export') {
|
} else if (cmd.type === 'export') {
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise<null>((resolve, reject) => {
|
||||||
this.pendingExport = { resolve, reject }
|
this.pendingExport = { resolve, reject }
|
||||||
})
|
})
|
||||||
this.engineConnection?.send(command)
|
this.engineConnection?.send(command)
|
||||||
@ -1922,194 +1876,15 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
;(cmd as any).sequence = this.outSequence++
|
;(cmd as any).sequence = this.outSequence++
|
||||||
}
|
}
|
||||||
// since it's not mouse drag or highlighting send over TCP and keep track of the command
|
// since it's not mouse drag or highlighting send over TCP and keep track of the command
|
||||||
this.engineConnection?.send(command)
|
return this.sendCommand(command.cmd_id, {
|
||||||
return this.handlePendingSceneCommand(command.cmd_id, command.cmd)
|
command,
|
||||||
}
|
idToRangeMap: {},
|
||||||
sendModelingCommand({
|
range: [0, 0],
|
||||||
id,
|
}).then(([a]) => a)
|
||||||
range,
|
|
||||||
command,
|
|
||||||
ast,
|
|
||||||
idToRangeMap,
|
|
||||||
}: {
|
|
||||||
id: string
|
|
||||||
range: SourceRange
|
|
||||||
command: EngineCommand
|
|
||||||
ast: Program
|
|
||||||
idToRangeMap?: { [key: string]: SourceRange }
|
|
||||||
}): Promise<ResolveCommand | void> {
|
|
||||||
if (this.engineConnection === undefined) {
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.engineConnection?.isReady()) {
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
if (typeof command !== 'string') {
|
|
||||||
this.addCommandLog({
|
|
||||||
type: 'send-modeling',
|
|
||||||
data: command,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.addCommandLog({
|
|
||||||
type: 'send-modeling',
|
|
||||||
data: JSON.parse(command),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.engineConnection?.send(command)
|
|
||||||
if (typeof command !== 'string' && command.type === 'modeling_cmd_req') {
|
|
||||||
return this.handlePendingCommand(id, command?.cmd, ast, range)
|
|
||||||
} else if (
|
|
||||||
typeof command !== 'string' &&
|
|
||||||
command.type === 'modeling_cmd_batch_req'
|
|
||||||
) {
|
|
||||||
return this.handlePendingBatchCommand(id, command.requests, idToRangeMap)
|
|
||||||
} else if (typeof command === 'string') {
|
|
||||||
const parseCommand: EngineCommand = JSON.parse(command)
|
|
||||||
if (parseCommand.type === 'modeling_cmd_req') {
|
|
||||||
return this.handlePendingCommand(id, parseCommand?.cmd, ast, range)
|
|
||||||
} else if (parseCommand.type === 'modeling_cmd_batch_req') {
|
|
||||||
return this.handlePendingBatchCommand(
|
|
||||||
id,
|
|
||||||
parseCommand.requests,
|
|
||||||
idToRangeMap
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Promise.reject(new Error('Expected unreachable reached'))
|
|
||||||
}
|
|
||||||
handlePendingSceneCommand(
|
|
||||||
id: string,
|
|
||||||
command: Models['ModelingCmd_type'],
|
|
||||||
ast?: Program,
|
|
||||||
range?: SourceRange
|
|
||||||
) {
|
|
||||||
let resolve: (val: any) => void = () => {}
|
|
||||||
const promise = new Promise((_resolve, reject) => {
|
|
||||||
resolve = _resolve
|
|
||||||
})
|
|
||||||
const pathToNode = ast
|
|
||||||
? getNodePathFromSourceRange(ast, range || [0, 0])
|
|
||||||
: []
|
|
||||||
this.sceneCommandArtifacts[id] = {
|
|
||||||
range: range || [0, 0],
|
|
||||||
pathToNode,
|
|
||||||
type: 'pending',
|
|
||||||
commandType: command.type,
|
|
||||||
promise,
|
|
||||||
resolve,
|
|
||||||
}
|
|
||||||
return promise
|
|
||||||
}
|
|
||||||
handlePendingCommand(
|
|
||||||
id: string,
|
|
||||||
command: Models['ModelingCmd_type'],
|
|
||||||
ast?: Program,
|
|
||||||
range?: SourceRange
|
|
||||||
): Promise<ResolveCommand | void> {
|
|
||||||
let resolve: (val: any) => void = () => {}
|
|
||||||
const promise: Promise<ResolveCommand | void> = new Promise(
|
|
||||||
(_resolve, reject) => {
|
|
||||||
resolve = _resolve
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const getParentId = (): string | undefined => {
|
|
||||||
if (command.type === 'extend_path') return command.path
|
|
||||||
if (command.type === 'solid3d_get_extrusion_face_info') {
|
|
||||||
const edgeArtifact = this.artifactMap[command.edge_id]
|
|
||||||
// edges's parent id is to the original "start_path" artifact
|
|
||||||
if (edgeArtifact && edgeArtifact.parentId) {
|
|
||||||
return edgeArtifact.parentId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (command.type === 'close_path') return command.path_id
|
|
||||||
if (command.type === 'extrude') return command.target
|
|
||||||
// handle other commands that have a parent here
|
|
||||||
}
|
|
||||||
const pathToNode = ast
|
|
||||||
? getNodePathFromSourceRange(ast, range || [0, 0])
|
|
||||||
: []
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
range: range || [0, 0],
|
|
||||||
pathToNode,
|
|
||||||
type: 'pending',
|
|
||||||
commandType: command.type,
|
|
||||||
parentId: getParentId(),
|
|
||||||
promise,
|
|
||||||
resolve,
|
|
||||||
}
|
|
||||||
if (command.type === 'extrude') {
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
range: range || [0, 0],
|
|
||||||
pathToNode,
|
|
||||||
type: 'pending',
|
|
||||||
commandType: 'extrude',
|
|
||||||
parentId: getParentId(),
|
|
||||||
promise,
|
|
||||||
target: command.target,
|
|
||||||
resolve,
|
|
||||||
}
|
|
||||||
const target = this.artifactMap[command.target]
|
|
||||||
if (target.commandType === 'start_path') {
|
|
||||||
// tsc cannot infer that target can have extrusions
|
|
||||||
// from the commandType (why?) so we need to cast it
|
|
||||||
const typedTarget = target as (
|
|
||||||
| PendingCommand
|
|
||||||
| ResultCommand
|
|
||||||
| FailedCommand
|
|
||||||
) & { extrusions?: string[] }
|
|
||||||
if (typedTarget?.extrusions?.length) {
|
|
||||||
typedTarget.extrusions.push(id)
|
|
||||||
} else {
|
|
||||||
typedTarget.extrusions = [id]
|
|
||||||
}
|
|
||||||
// Update in the map.
|
|
||||||
this.artifactMap[command.target] = typedTarget
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return promise
|
|
||||||
}
|
|
||||||
async handlePendingBatchCommand(
|
|
||||||
id: string,
|
|
||||||
commands: Models['ModelingCmdReq_type'][],
|
|
||||||
idToRangeMap?: { [key: string]: SourceRange },
|
|
||||||
ast?: Program,
|
|
||||||
range?: SourceRange
|
|
||||||
): Promise<ResolveCommand | void> {
|
|
||||||
let resolve: (val: any) => void = () => {}
|
|
||||||
const promise: Promise<ResolveCommand | void> = new Promise(
|
|
||||||
(_resolve, reject) => {
|
|
||||||
resolve = _resolve
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!idToRangeMap) {
|
|
||||||
return Promise.reject(
|
|
||||||
new Error('idToRangeMap is required for batch commands')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the overall batch command to the artifact map just so we can track all of the
|
|
||||||
// individual commands that are part of the batch.
|
|
||||||
// we'll delete this artifact once all of the individual commands have been processed.
|
|
||||||
this.artifactMap[id] = {
|
|
||||||
range: range || [0, 0],
|
|
||||||
pathToNode: [],
|
|
||||||
type: 'pending',
|
|
||||||
commandType: 'batch',
|
|
||||||
additionalData: { type: 'batch-ids', ids: commands.map((c) => c.cmd_id) },
|
|
||||||
parentId: undefined,
|
|
||||||
promise,
|
|
||||||
resolve,
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(
|
|
||||||
commands.map((c) =>
|
|
||||||
this.handlePendingCommand(c.cmd_id, c.cmd, ast, idToRangeMap[c.cmd_id])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return promise
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* A wrapper around the sendCommand where all inputs are JSON strings
|
||||||
|
*/
|
||||||
async sendModelingCommandFromWasm(
|
async sendModelingCommandFromWasm(
|
||||||
id: string,
|
id: string,
|
||||||
rangeStr: string,
|
rangeStr: string,
|
||||||
@ -2132,53 +1907,88 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
return Promise.reject(new Error('commandStr is undefined'))
|
return Promise.reject(new Error('commandStr is undefined'))
|
||||||
}
|
}
|
||||||
const range: SourceRange = JSON.parse(rangeStr)
|
const range: SourceRange = JSON.parse(rangeStr)
|
||||||
|
const command: EngineCommand = JSON.parse(commandStr)
|
||||||
const idToRangeMap: { [key: string]: SourceRange } =
|
const idToRangeMap: { [key: string]: SourceRange } =
|
||||||
JSON.parse(idToRangeStr)
|
JSON.parse(idToRangeStr)
|
||||||
|
|
||||||
const command: EngineCommand = JSON.parse(commandStr)
|
const resp = await this.sendCommand(id, {
|
||||||
|
|
||||||
// We only care about the modeling command response.
|
|
||||||
return this.sendModelingCommand({
|
|
||||||
id,
|
|
||||||
range,
|
|
||||||
command,
|
command,
|
||||||
ast: this.getAst(),
|
range,
|
||||||
idToRangeMap,
|
idToRangeMap,
|
||||||
}).then((resp) => {
|
|
||||||
if (!resp) {
|
|
||||||
return Promise.reject(
|
|
||||||
new Error(
|
|
||||||
'returning modeling cmd response to the rust side is undefined or null'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return JSON.stringify(resp.raw)
|
|
||||||
})
|
})
|
||||||
|
return JSON.stringify(resp[0])
|
||||||
}
|
}
|
||||||
async commandResult(id: string): Promise<any> {
|
/**
|
||||||
const command = this.artifactMap[id]
|
* Common send command function used for both modeling and scene commands
|
||||||
if (!command) {
|
* So that both have a common way to send pending commands with promises for the responses
|
||||||
return Promise.reject(new Error('No command found'))
|
*/
|
||||||
|
async sendCommand(
|
||||||
|
id: string,
|
||||||
|
message: {
|
||||||
|
command: PendingMessage['command']
|
||||||
|
range: PendingMessage['range']
|
||||||
|
idToRangeMap: PendingMessage['idToRangeMap']
|
||||||
}
|
}
|
||||||
if (command.type === 'result') {
|
): Promise<[Models['WebSocketResponse_type']]> {
|
||||||
return command.data
|
const { promise, resolve, reject } = promiseFactory<any>()
|
||||||
} else if (command.type === 'failed') {
|
this.pendingCommands[id] = {
|
||||||
return Promise.resolve(command.errors)
|
resolve,
|
||||||
|
reject,
|
||||||
|
promise,
|
||||||
|
command: message.command,
|
||||||
|
range: message.range,
|
||||||
|
idToRangeMap: message.idToRangeMap,
|
||||||
}
|
}
|
||||||
return command.promise
|
if (message.command.type === 'modeling_cmd_req') {
|
||||||
|
this.orderedCommands.push({
|
||||||
|
command: message.command,
|
||||||
|
range: message.range,
|
||||||
|
})
|
||||||
|
} else if (message.command.type === 'modeling_cmd_batch_req') {
|
||||||
|
message.command.requests.forEach((req) => {
|
||||||
|
const cmd: EngineCommand = {
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: req.cmd_id,
|
||||||
|
cmd: req.cmd,
|
||||||
|
}
|
||||||
|
this.orderedCommands.push({
|
||||||
|
command: cmd,
|
||||||
|
range: message.idToRangeMap[req.cmd_id || ''],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.engineConnection?.send(message.command)
|
||||||
|
return promise
|
||||||
}
|
}
|
||||||
async waitForAllCommands(): Promise<{
|
/**
|
||||||
artifactMap: ArtifactMap
|
* When an execution takes place we want to wait until we've got replies for all of the commands
|
||||||
}> {
|
* When this is done when we build the artifact map synchronously.
|
||||||
|
*/
|
||||||
|
async waitForAllCommands() {
|
||||||
const pendingCommands = Object.values(this.artifactMap).filter(
|
const pendingCommands = Object.values(this.artifactMap).filter(
|
||||||
({ type }) => type === 'pending'
|
({ type }) => type === 'pending'
|
||||||
) as PendingCommand[]
|
) as PendingCommand[]
|
||||||
const proms = pendingCommands.map(({ promise }) => promise)
|
const proms = pendingCommands.map(({ promise }) => promise)
|
||||||
await Promise.all(proms)
|
|
||||||
|
|
||||||
return {
|
const otherPending = Object.values(this.pendingCommands).map(
|
||||||
artifactMap: this.artifactMap,
|
(a) => a.promise
|
||||||
}
|
)
|
||||||
|
await Promise.all([...proms, otherPending])
|
||||||
|
this.orderedCommands.forEach(({ command, range }) => {
|
||||||
|
// expect all to be `modeling_cmd_req` as batch commands have
|
||||||
|
// already been expanded before being added to orderedCommands
|
||||||
|
if (command.type !== 'modeling_cmd_req') return
|
||||||
|
const id = command.cmd_id
|
||||||
|
const response = this.responseMap[id]
|
||||||
|
this.handleIndividualResponse({
|
||||||
|
id,
|
||||||
|
pendingMsg: {
|
||||||
|
command,
|
||||||
|
range,
|
||||||
|
},
|
||||||
|
response,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
private async initPlanes() {
|
private async initPlanes() {
|
||||||
if (this.planesInitialized()) return
|
if (this.planesInitialized()) return
|
||||||
@ -2209,7 +2019,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
this.onPlaneSelectCallback = callback
|
this.onPlaneSelectCallback = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
async setPlaneHidden(id: string, hidden: boolean): Promise<string> {
|
async setPlaneHidden(id: string, hidden: boolean) {
|
||||||
return await this.sendSceneCommand({
|
return await this.sendSceneCommand({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd_id: uuidv4(),
|
cmd_id: uuidv4(),
|
||||||
@ -2250,3 +2060,13 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function promiseFactory<T>() {
|
||||||
|
let resolve: (value: T | PromiseLike<T>) => void = () => {}
|
||||||
|
let reject: (value: T | PromiseLike<T>) => void = () => {}
|
||||||
|
const promise = new Promise<T>((_resolve, _reject) => {
|
||||||
|
resolve = _resolve
|
||||||
|
reject = _reject
|
||||||
|
})
|
||||||
|
return { promise, resolve, reject }
|
||||||
|
}
|
||||||
|
@ -87,16 +87,20 @@ export async function getEventForSelectWithPoint(
|
|||||||
// there's plans to get the faceId back from the solid2d creation
|
// there's plans to get the faceId back from the solid2d creation
|
||||||
// https://github.com/KittyCAD/engine/issues/2094
|
// https://github.com/KittyCAD/engine/issues/2094
|
||||||
// at which point we can add it to the artifact map and remove this logic
|
// at which point we can add it to the artifact map and remove this logic
|
||||||
const parentId = (
|
const resp = await engineCommandManager.sendSceneCommand({
|
||||||
await engineCommandManager.sendSceneCommand({
|
type: 'modeling_cmd_req',
|
||||||
type: 'modeling_cmd_req',
|
cmd: {
|
||||||
cmd: {
|
type: 'entity_get_parent_id',
|
||||||
type: 'entity_get_parent_id',
|
entity_id: data.entity_id,
|
||||||
entity_id: data.entity_id,
|
},
|
||||||
},
|
cmd_id: uuidv4(),
|
||||||
cmd_id: uuidv4(),
|
})
|
||||||
})
|
const parentId =
|
||||||
)?.data?.data?.entity_id
|
resp?.success &&
|
||||||
|
resp?.resp?.type === 'modeling' &&
|
||||||
|
resp?.resp?.data?.modeling_response?.type === 'entity_get_parent_id'
|
||||||
|
? resp?.resp?.data?.modeling_response?.data?.entity_id
|
||||||
|
: ''
|
||||||
const parentArtifact = engineCommandManager.artifactMap[parentId]
|
const parentArtifact = engineCommandManager.artifactMap[parentId]
|
||||||
if (parentArtifact) {
|
if (parentArtifact) {
|
||||||
_artifact = parentArtifact
|
_artifact = parentArtifact
|
||||||
@ -576,18 +580,22 @@ export async function sendSelectEventToEngine(
|
|||||||
el,
|
el,
|
||||||
...streamDimensions,
|
...streamDimensions,
|
||||||
})
|
})
|
||||||
const result: Models['SelectWithPoint_type'] = await engineCommandManager
|
const res = await engineCommandManager.sendSceneCommand({
|
||||||
.sendSceneCommand({
|
type: 'modeling_cmd_req',
|
||||||
type: 'modeling_cmd_req',
|
cmd: {
|
||||||
cmd: {
|
type: 'select_with_point',
|
||||||
type: 'select_with_point',
|
selected_at_window: { x, y },
|
||||||
selected_at_window: { x, y },
|
selection_type: 'add',
|
||||||
selection_type: 'add',
|
},
|
||||||
},
|
cmd_id: uuidv4(),
|
||||||
cmd_id: uuidv4(),
|
})
|
||||||
})
|
if (
|
||||||
.then((res) => res.data.data)
|
res?.success &&
|
||||||
return result
|
res?.resp?.type === 'modeling' &&
|
||||||
|
res?.resp?.data?.modeling_response.type === 'select_with_point'
|
||||||
|
)
|
||||||
|
return res?.resp?.data?.modeling_response?.data
|
||||||
|
return { entity_id: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateSelections(
|
export function updateSelections(
|
||||||
|
Reference in New Issue
Block a user