@vulfram/engine 0.17.1-alpha → 0.19.3-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +10 -5
- package/src/engine/api.ts +12 -25
- package/src/engine/bridge/dispatch.ts +3 -8
- package/src/engine/ecs/components.ts +340 -0
- package/src/engine/ecs/index.ts +3 -661
- package/src/engine/ecs/intents.ts +184 -0
- package/src/engine/ecs/systems.ts +26 -0
- package/src/engine/intents/store.ts +72 -0
- package/src/engine/state.ts +3 -3
- package/src/engine/systems/command-intent.ts +11 -16
- package/src/engine/systems/diagnostics.ts +3 -13
- package/src/engine/systems/input-mirror.ts +156 -18
- package/src/engine/systems/resource-upload.ts +12 -14
- package/src/engine/systems/response-decode.ts +17 -0
- package/src/engine/systems/scene-sync.ts +12 -13
- package/src/engine/systems/ui-bridge.ts +31 -10
- package/src/engine/systems/utils.ts +46 -3
- package/src/engine/systems/world-lifecycle.ts +9 -15
- package/src/engine/world/entities.ts +201 -37
- package/src/engine/world/mount.ts +27 -6
- package/src/engine/world/world-ui.ts +77 -30
- package/src/engine/world/world3d.ts +282 -33
- package/src/helpers/collision.ts +487 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/raycast.ts +442 -0
- package/src/types/cmds/geometry.ts +2 -2
- package/src/types/cmds/index.ts +42 -0
- package/src/types/cmds/input.ts +39 -0
- package/src/types/cmds/material.ts +10 -10
- package/src/types/cmds/realm.ts +0 -2
- package/src/types/cmds/system.ts +10 -0
- package/src/types/cmds/target.ts +14 -0
- package/src/types/events/keyboard.ts +2 -2
- package/src/types/events/pointer.ts +43 -0
- package/src/types/events/system.ts +44 -0
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
CmdEnvironmentDisposeArgs,
|
|
5
5
|
} from '../../types/cmds/environment';
|
|
6
6
|
import type {
|
|
7
|
+
CmdTargetMeasurementArgs,
|
|
7
8
|
CmdTargetDisposeArgs,
|
|
8
9
|
CmdTargetLayerDisposeArgs,
|
|
9
10
|
CmdTargetLayerUpsertArgs,
|
|
@@ -29,6 +30,11 @@ import type {
|
|
|
29
30
|
CmdSystemDiagnosticsSetArgs,
|
|
30
31
|
CmdUploadBufferDiscardAllArgs,
|
|
31
32
|
} from '../../types/cmds/system';
|
|
33
|
+
import type {
|
|
34
|
+
CmdInputTargetListenerDisposeArgs,
|
|
35
|
+
CmdInputTargetListenerListArgs,
|
|
36
|
+
CmdInputTargetListenerUpsertArgs,
|
|
37
|
+
} from '../../types/cmds/input';
|
|
32
38
|
import type { CmdTextureBindTargetArgs } from '../../types/cmds/texture';
|
|
33
39
|
import type {
|
|
34
40
|
CmdUiAccessKitActionRequestArgs,
|
|
@@ -69,6 +75,7 @@ import type {
|
|
|
69
75
|
ModelProps,
|
|
70
76
|
TagProps,
|
|
71
77
|
TextureProps,
|
|
78
|
+
TransformComponent,
|
|
72
79
|
TransformProps,
|
|
73
80
|
UiFocusCycleMode,
|
|
74
81
|
WindowStateComponent,
|
|
@@ -107,7 +114,7 @@ function recalculateWorldWindowBindings(world: ReturnType<typeof getWorldOrThrow
|
|
|
107
114
|
export function emitIntent(worldId: number, intent: Intent): void {
|
|
108
115
|
requireInitialized();
|
|
109
116
|
const world = getWorldOrThrow(worldId);
|
|
110
|
-
world.
|
|
117
|
+
world.intentStore.enqueue(intent);
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
/**
|
|
@@ -157,6 +164,46 @@ export function upsertTarget(worldId: number, args: CmdTargetUpsertArgs): number
|
|
|
157
164
|
return id;
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Requests size measurements for a target.
|
|
169
|
+
*/
|
|
170
|
+
export function measureTarget(
|
|
171
|
+
worldId: number,
|
|
172
|
+
args: CmdTargetMeasurementArgs,
|
|
173
|
+
): number {
|
|
174
|
+
return enqueueCommand(worldId, 'cmd-target-measurement', args);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Creates or updates an input listener bound to a routed target.
|
|
179
|
+
*/
|
|
180
|
+
export function upsertInputTargetListener(
|
|
181
|
+
worldId: number,
|
|
182
|
+
args: CmdInputTargetListenerUpsertArgs,
|
|
183
|
+
): number {
|
|
184
|
+
return enqueueCommand(worldId, 'cmd-input-target-listener-upsert', args);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Disposes an input listener bound to routed targets.
|
|
189
|
+
*/
|
|
190
|
+
export function disposeInputTargetListener(
|
|
191
|
+
worldId: number,
|
|
192
|
+
args: CmdInputTargetListenerDisposeArgs,
|
|
193
|
+
): number {
|
|
194
|
+
return enqueueCommand(worldId, 'cmd-input-target-listener-dispose', args);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Lists input listeners (optionally filtered by target id).
|
|
199
|
+
*/
|
|
200
|
+
export function listInputTargetListeners(
|
|
201
|
+
worldId: number,
|
|
202
|
+
args: CmdInputTargetListenerListArgs = {},
|
|
203
|
+
): number {
|
|
204
|
+
return enqueueCommand(worldId, 'cmd-input-target-listener-list', args);
|
|
205
|
+
}
|
|
206
|
+
|
|
160
207
|
/**
|
|
161
208
|
* Disposes a target.
|
|
162
209
|
*/
|
|
@@ -178,19 +225,8 @@ export function bindWorldToTarget(
|
|
|
178
225
|
args: Omit<CmdTargetLayerUpsertArgs, 'realmId'>,
|
|
179
226
|
): number {
|
|
180
227
|
const world = getWorldOrThrow(worldId);
|
|
181
|
-
const realmId = getWorldRealmId(worldId);
|
|
182
|
-
if (realmId === null) {
|
|
183
|
-
throw new EngineError(
|
|
184
|
-
'WorldNotReady',
|
|
185
|
-
`World ${worldId} realm is not ready. Call tick() and wait for realm-create response.`,
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
228
|
|
|
189
229
|
const resolvedCameraId = args.cameraId ?? findPreferredCameraId(worldId);
|
|
190
|
-
const resolvedArgs: Omit<CmdTargetLayerUpsertArgs, 'realmId'> = {
|
|
191
|
-
...args,
|
|
192
|
-
cameraId: resolvedCameraId,
|
|
193
|
-
};
|
|
194
230
|
|
|
195
231
|
world.targetLayerBindings.set(args.targetId, {
|
|
196
232
|
targetId: args.targetId,
|
|
@@ -200,9 +236,16 @@ export function bindWorldToTarget(
|
|
|
200
236
|
});
|
|
201
237
|
markRoutingIndexDirty();
|
|
202
238
|
|
|
239
|
+
const realmId = getWorldRealmId(worldId);
|
|
240
|
+
if (realmId === null) {
|
|
241
|
+
// Realm not ready yet: keep binding cached and let response-decode flush later.
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
203
245
|
return enqueueCommand(worldId, 'cmd-target-layer-upsert', {
|
|
204
246
|
realmId,
|
|
205
|
-
...
|
|
247
|
+
...args,
|
|
248
|
+
cameraId: resolvedCameraId,
|
|
206
249
|
});
|
|
207
250
|
}
|
|
208
251
|
|
|
@@ -214,18 +257,18 @@ export function unbindWorldFromTarget(
|
|
|
214
257
|
args: Omit<CmdTargetLayerDisposeArgs, 'realmId'>,
|
|
215
258
|
): number {
|
|
216
259
|
const world = getWorldOrThrow(worldId);
|
|
217
|
-
const realmId = getWorldRealmId(worldId);
|
|
218
|
-
if (realmId === null) {
|
|
219
|
-
throw new EngineError(
|
|
220
|
-
'WorldNotReady',
|
|
221
|
-
`World ${worldId} realm is not ready. Call tick() and wait for realm-create response.`,
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
260
|
world.targetLayerBindings.delete(args.targetId);
|
|
225
261
|
if (world.targetWindowBindings.delete(args.targetId)) {
|
|
226
262
|
recalculateWorldWindowBindings(world);
|
|
227
263
|
}
|
|
228
264
|
markRoutingIndexDirty();
|
|
265
|
+
|
|
266
|
+
const realmId = getWorldRealmId(worldId);
|
|
267
|
+
if (realmId === null) {
|
|
268
|
+
// Realm not ready yet: nothing to dispose in core.
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
229
272
|
return enqueueCommand(worldId, 'cmd-target-layer-dispose', {
|
|
230
273
|
realmId,
|
|
231
274
|
...args,
|
|
@@ -317,7 +360,7 @@ export function disposeWorld(
|
|
|
317
360
|
}
|
|
318
361
|
const hasRetainedTargets = world.targetLayerBindings.size > 0;
|
|
319
362
|
const hasPendingWork =
|
|
320
|
-
world.
|
|
363
|
+
world.intentStore.size() > 0 || world.pendingCommands.length > 0;
|
|
321
364
|
|
|
322
365
|
if (
|
|
323
366
|
(!disposeRealm && (retainedCoreObjectCount > 0 || hasPendingWork)) ||
|
|
@@ -328,7 +371,7 @@ export function disposeWorld(
|
|
|
328
371
|
`retainRealm=${!disposeRealm} retainTargets=${!disposeTargets} ` +
|
|
329
372
|
`trackedCoreObjects=${retainedCoreObjectCount} ` +
|
|
330
373
|
`targetBindings=${world.targetLayerBindings.size} ` +
|
|
331
|
-
`pendingIntents=${world.
|
|
374
|
+
`pendingIntents=${world.intentStore.size()} ` +
|
|
332
375
|
`pendingCommands=${world.pendingCommands.length}`;
|
|
333
376
|
if (strictResourceLifecycle) {
|
|
334
377
|
throw new EngineError('WorldDisposeLifecycleRisk', message);
|
|
@@ -589,9 +632,6 @@ function resolveWorldWindowId(worldId: number): number {
|
|
|
589
632
|
for (const windowId of world.targetWindowBindings.values()) {
|
|
590
633
|
return windowId;
|
|
591
634
|
}
|
|
592
|
-
if (world.realmCreateArgs.hostWindowId !== undefined) {
|
|
593
|
-
return world.realmCreateArgs.hostWindowId;
|
|
594
|
-
}
|
|
595
635
|
throw new EngineError(
|
|
596
636
|
'WindowNotFound',
|
|
597
637
|
`World ${worldId} has no window binding available for this command.`,
|
|
@@ -1054,6 +1094,44 @@ export function updateTransform(
|
|
|
1054
1094
|
entityId: number,
|
|
1055
1095
|
props: TransformProps,
|
|
1056
1096
|
): void {
|
|
1097
|
+
// Apply immediately to local ECS snapshot so same-frame queries
|
|
1098
|
+
// (for example gizmo/collision helpers) observe latest transform.
|
|
1099
|
+
// Intent is still emitted to keep the standard system pipeline authoritative.
|
|
1100
|
+
const world = getWorldOrThrow(worldId);
|
|
1101
|
+
const store = world.components.get(entityId);
|
|
1102
|
+
const transform = store?.get('Transform') as TransformComponent | undefined;
|
|
1103
|
+
if (transform) {
|
|
1104
|
+
if (props.position) {
|
|
1105
|
+
transform.position = [
|
|
1106
|
+
props.position[0] ?? transform.position[0],
|
|
1107
|
+
props.position[1] ?? transform.position[1],
|
|
1108
|
+
props.position[2] ?? transform.position[2],
|
|
1109
|
+
];
|
|
1110
|
+
}
|
|
1111
|
+
if (props.rotation) {
|
|
1112
|
+
transform.rotation = [
|
|
1113
|
+
props.rotation[0] ?? transform.rotation[0],
|
|
1114
|
+
props.rotation[1] ?? transform.rotation[1],
|
|
1115
|
+
props.rotation[2] ?? transform.rotation[2],
|
|
1116
|
+
props.rotation[3] ?? transform.rotation[3],
|
|
1117
|
+
];
|
|
1118
|
+
}
|
|
1119
|
+
if (props.scale) {
|
|
1120
|
+
transform.scale = [
|
|
1121
|
+
props.scale[0] ?? transform.scale[0],
|
|
1122
|
+
props.scale[1] ?? transform.scale[1],
|
|
1123
|
+
props.scale[2] ?? transform.scale[2],
|
|
1124
|
+
];
|
|
1125
|
+
}
|
|
1126
|
+
if (props.layerMask !== undefined) {
|
|
1127
|
+
transform.layerMask = props.layerMask;
|
|
1128
|
+
}
|
|
1129
|
+
if (props.visible !== undefined) {
|
|
1130
|
+
transform.visible = props.visible;
|
|
1131
|
+
}
|
|
1132
|
+
world.constraintDirtyEntities.add(entityId);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1057
1135
|
emitIntent(worldId, {
|
|
1058
1136
|
type: 'update-transform',
|
|
1059
1137
|
entityId,
|
|
@@ -1205,38 +1283,92 @@ export function isKeyJustReleased(worldId: number, keyCode: number): boolean {
|
|
|
1205
1283
|
}
|
|
1206
1284
|
|
|
1207
1285
|
/**
|
|
1208
|
-
* Gets the current
|
|
1286
|
+
* Gets the current pointer position in window space.
|
|
1287
|
+
*/
|
|
1288
|
+
export function getPointerPosition(worldId: number): [number, number] {
|
|
1289
|
+
const state = getInputState(worldId);
|
|
1290
|
+
return state?.pointerPosition ?? [0, 0];
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Gets the real drawn window area associated with the latest pointer event.
|
|
1209
1295
|
*/
|
|
1210
|
-
export function
|
|
1296
|
+
export function getPointerWindowSize(
|
|
1297
|
+
worldId: number,
|
|
1298
|
+
): [number, number] | null {
|
|
1211
1299
|
const state = getInputState(worldId);
|
|
1212
|
-
return state?.
|
|
1300
|
+
return state?.pointerWindowSize ?? null;
|
|
1213
1301
|
}
|
|
1214
1302
|
|
|
1215
1303
|
/**
|
|
1216
|
-
* Gets the
|
|
1304
|
+
* Gets the pointer movement delta for this frame in window space.
|
|
1217
1305
|
*/
|
|
1218
|
-
export function
|
|
1306
|
+
export function getPointerDelta(worldId: number): [number, number] {
|
|
1219
1307
|
const state = getInputState(worldId);
|
|
1220
|
-
return state?.
|
|
1308
|
+
return state?.pointerDelta ?? [0, 0];
|
|
1221
1309
|
}
|
|
1222
1310
|
|
|
1223
1311
|
/**
|
|
1224
|
-
*
|
|
1312
|
+
* Gets the pointer position relative to the current routed target.
|
|
1225
1313
|
*/
|
|
1226
|
-
export function
|
|
1314
|
+
export function getPointerTargetPosition(
|
|
1315
|
+
worldId: number,
|
|
1316
|
+
): [number, number] | null {
|
|
1227
1317
|
const state = getInputState(worldId);
|
|
1228
|
-
return state?.
|
|
1318
|
+
return state?.pointerPositionTarget ?? null;
|
|
1229
1319
|
}
|
|
1230
1320
|
|
|
1231
1321
|
/**
|
|
1232
|
-
*
|
|
1322
|
+
* Gets the real drawn target area associated with the latest pointer event.
|
|
1233
1323
|
*/
|
|
1234
|
-
export function
|
|
1324
|
+
export function getPointerTargetSize(
|
|
1325
|
+
worldId: number,
|
|
1326
|
+
): [number, number] | null {
|
|
1327
|
+
const state = getInputState(worldId);
|
|
1328
|
+
return state?.pointerTargetSize ?? null;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Gets the pointer movement delta relative to the current routed target.
|
|
1333
|
+
*/
|
|
1334
|
+
export function getPointerTargetDelta(worldId: number): [number, number] | null {
|
|
1335
|
+
const state = getInputState(worldId);
|
|
1336
|
+
return state?.pointerTargetDelta ?? null;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Gets the routed target under pointer, when available.
|
|
1341
|
+
*/
|
|
1342
|
+
export function getPointerTargetId(worldId: number): number | null {
|
|
1343
|
+
const state = getInputState(worldId);
|
|
1344
|
+
return state?.pointerTargetId ?? null;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Gets pointer UV (0..1) in routed target space, when available.
|
|
1349
|
+
*/
|
|
1350
|
+
export function getPointerTargetUv(worldId: number): [number, number] | null {
|
|
1351
|
+
const state = getInputState(worldId);
|
|
1352
|
+
return state?.pointerTargetUv ?? null;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/**
|
|
1356
|
+
* Checks if a pointer button is currently pressed.
|
|
1357
|
+
*/
|
|
1358
|
+
export function isPointerButtonPressed(worldId: number, button: number): boolean {
|
|
1359
|
+
const state = getInputState(worldId);
|
|
1360
|
+
return state?.pointerButtons.has(button) ?? false;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* Checks if a pointer button was just pressed this frame.
|
|
1365
|
+
*/
|
|
1366
|
+
export function isPointerButtonJustPressed(
|
|
1235
1367
|
worldId: number,
|
|
1236
1368
|
button: number,
|
|
1237
1369
|
): boolean {
|
|
1238
1370
|
const state = getInputState(worldId);
|
|
1239
|
-
return state?.
|
|
1371
|
+
return state?.pointerJustPressed.has(button) ?? false;
|
|
1240
1372
|
}
|
|
1241
1373
|
|
|
1242
1374
|
/**
|
|
@@ -1247,6 +1379,38 @@ export function getScrollDelta(worldId: number): [number, number] {
|
|
|
1247
1379
|
return state?.scrollDelta ?? [0, 0];
|
|
1248
1380
|
}
|
|
1249
1381
|
|
|
1382
|
+
/**
|
|
1383
|
+
* Returns true while IME composition is active for this world.
|
|
1384
|
+
*/
|
|
1385
|
+
export function isImeEnabled(worldId: number): boolean {
|
|
1386
|
+
const state = getInputState(worldId);
|
|
1387
|
+
return state?.imeEnabled ?? false;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Returns current IME preedit text, if any.
|
|
1392
|
+
*/
|
|
1393
|
+
export function getImePreeditText(worldId: number): string | null {
|
|
1394
|
+
const state = getInputState(worldId);
|
|
1395
|
+
return state?.imePreeditText ?? null;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/**
|
|
1399
|
+
* Returns current IME cursor range inside preedit text, if available.
|
|
1400
|
+
*/
|
|
1401
|
+
export function getImeCursorRange(worldId: number): [number, number] | null {
|
|
1402
|
+
const state = getInputState(worldId);
|
|
1403
|
+
return state?.imeCursorRange ?? null;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Returns last IME committed text for the current frame, if any.
|
|
1408
|
+
*/
|
|
1409
|
+
export function getImeCommitText(worldId: number): string | null {
|
|
1410
|
+
const state = getInputState(worldId);
|
|
1411
|
+
return state?.imeCommitText ?? null;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1250
1414
|
/**
|
|
1251
1415
|
* Gets the current window size.
|
|
1252
1416
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
CmdTargetMeasurementArgs,
|
|
2
3
|
CmdTargetLayerDisposeArgs,
|
|
3
4
|
CmdTargetLayerUpsertArgs,
|
|
4
5
|
CmdTargetUpsertArgs,
|
|
@@ -8,6 +9,7 @@ import { engineState } from '../state';
|
|
|
8
9
|
import {
|
|
9
10
|
bindWorldToTarget,
|
|
10
11
|
isWorldReady,
|
|
12
|
+
measureTarget,
|
|
11
13
|
unbindWorldFromTarget,
|
|
12
14
|
upsertTarget,
|
|
13
15
|
} from './entities';
|
|
@@ -31,6 +33,7 @@ export type MountWorldArgs = {
|
|
|
31
33
|
export type WaitWorldReadyOptions = {
|
|
32
34
|
timeoutMs?: number;
|
|
33
35
|
pollIntervalMs?: number;
|
|
36
|
+
onPoll?: (() => void | Promise<void>) | undefined;
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
/**
|
|
@@ -54,15 +57,22 @@ export async function waitWorldReady(
|
|
|
54
57
|
): Promise<boolean> {
|
|
55
58
|
const timeoutMs = options.timeoutMs ?? 5_000;
|
|
56
59
|
const pollIntervalMs = options.pollIntervalMs ?? 16;
|
|
57
|
-
const
|
|
60
|
+
const deadline = Date.now() + timeoutMs;
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
if (isWorldMountReady(worldId))
|
|
61
|
-
|
|
62
|
+
const poll = async (): Promise<boolean> => {
|
|
63
|
+
if (isWorldMountReady(worldId)) return true;
|
|
64
|
+
if (Date.now() >= deadline) return isWorldMountReady(worldId);
|
|
65
|
+
|
|
66
|
+
if (options.onPoll) {
|
|
67
|
+
await options.onPoll();
|
|
68
|
+
if (isWorldMountReady(worldId)) return true;
|
|
62
69
|
}
|
|
70
|
+
|
|
63
71
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
return poll();
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return poll();
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
function allocateTargetId(): TargetId {
|
|
@@ -172,3 +182,14 @@ export function remountWorld(
|
|
|
172
182
|
const commandId = bindWorldToTarget(asWorldNumber(worldId), args);
|
|
173
183
|
return asCommandId(commandId);
|
|
174
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Requests measurement for a mounted target.
|
|
188
|
+
*/
|
|
189
|
+
export function measureMountedTarget(
|
|
190
|
+
worldId: WorldId,
|
|
191
|
+
args: CmdTargetMeasurementArgs,
|
|
192
|
+
): CommandId {
|
|
193
|
+
const commandId = measureTarget(asWorldNumber(worldId), args);
|
|
194
|
+
return asCommandId(commandId);
|
|
195
|
+
}
|
|
@@ -55,7 +55,6 @@ import type { WorldUIId } from './types';
|
|
|
55
55
|
import { asWorldNumber, asWorldUIId } from './types';
|
|
56
56
|
|
|
57
57
|
type CreateUIWorldOptions = {
|
|
58
|
-
outputSurfaceId?: number;
|
|
59
58
|
importance?: number;
|
|
60
59
|
cachePolicy?: number;
|
|
61
60
|
flags?: number;
|
|
@@ -74,15 +73,12 @@ type UIFocusNextArgs = {
|
|
|
74
73
|
formId?: string;
|
|
75
74
|
};
|
|
76
75
|
|
|
77
|
-
function resolveWorldUIContext(worldId: number): {
|
|
76
|
+
function resolveWorldUIContext(worldId: number): {
|
|
77
|
+
windowId: number;
|
|
78
|
+
realmId: number;
|
|
79
|
+
} {
|
|
78
80
|
const world = getWorldOrThrow(worldId);
|
|
79
|
-
const realmId = world.coreRealmId;
|
|
80
|
-
if (realmId === undefined) {
|
|
81
|
-
throw new EngineError(
|
|
82
|
-
'WorldNotReady',
|
|
83
|
-
`World ${worldId} has no core realm available yet.`,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
81
|
+
const realmId = world.coreRealmId ?? world.worldId;
|
|
86
82
|
|
|
87
83
|
if (world.primaryWindowId !== undefined) {
|
|
88
84
|
return { windowId: world.primaryWindowId, realmId };
|
|
@@ -90,9 +86,6 @@ function resolveWorldUIContext(worldId: number): { windowId: number; realmId: nu
|
|
|
90
86
|
for (const windowId of world.targetWindowBindings.values()) {
|
|
91
87
|
return { windowId, realmId };
|
|
92
88
|
}
|
|
93
|
-
if (world.realmCreateArgs.hostWindowId !== undefined) {
|
|
94
|
-
return { windowId: world.realmCreateArgs.hostWindowId, realmId };
|
|
95
|
-
}
|
|
96
89
|
throw new EngineError(
|
|
97
90
|
'WindowNotFound',
|
|
98
91
|
`World ${worldId} has no window binding available for UI operation.`,
|
|
@@ -110,32 +103,50 @@ export function createUIWorld(options?: CreateUIWorldOptions): WorldUIId {
|
|
|
110
103
|
}
|
|
111
104
|
|
|
112
105
|
/** Defines a theme in a UI world. */
|
|
113
|
-
export function defineUITheme(
|
|
106
|
+
export function defineUITheme(
|
|
107
|
+
worldId: WorldUIId,
|
|
108
|
+
args: CmdUiThemeDefineArgs,
|
|
109
|
+
): void {
|
|
114
110
|
uiDefineThemeRaw(asWorldNumber(worldId), args);
|
|
115
111
|
}
|
|
116
112
|
|
|
117
113
|
/** Disposes a theme in a UI world. */
|
|
118
|
-
export function disposeUITheme(
|
|
114
|
+
export function disposeUITheme(
|
|
115
|
+
worldId: WorldUIId,
|
|
116
|
+
args: CmdUiThemeDisposeArgs,
|
|
117
|
+
): void {
|
|
119
118
|
uiDisposeThemeRaw(asWorldNumber(worldId), args);
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
/** Creates a document in a UI world. */
|
|
123
|
-
export function createUIDocument(
|
|
122
|
+
export function createUIDocument(
|
|
123
|
+
worldId: WorldUIId,
|
|
124
|
+
args: CmdUiDocumentCreateArgs,
|
|
125
|
+
): void {
|
|
124
126
|
uiCreateDocumentRaw(asWorldNumber(worldId), args);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
/** Disposes a document in a UI world. */
|
|
128
|
-
export function disposeUIDocument(
|
|
130
|
+
export function disposeUIDocument(
|
|
131
|
+
worldId: WorldUIId,
|
|
132
|
+
args: CmdUiDocumentDisposeArgs,
|
|
133
|
+
): void {
|
|
129
134
|
uiDisposeDocumentRaw(asWorldNumber(worldId), args);
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/** Sets document rect in a UI world. */
|
|
133
|
-
export function setUIDocumentRect(
|
|
138
|
+
export function setUIDocumentRect(
|
|
139
|
+
worldId: WorldUIId,
|
|
140
|
+
args: CmdUiDocumentSetRectArgs,
|
|
141
|
+
): void {
|
|
134
142
|
uiSetDocumentRectRaw(asWorldNumber(worldId), args);
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
/** Sets document theme in a UI world. */
|
|
138
|
-
export function setUIDocumentTheme(
|
|
146
|
+
export function setUIDocumentTheme(
|
|
147
|
+
worldId: WorldUIId,
|
|
148
|
+
args: CmdUiDocumentSetThemeArgs,
|
|
149
|
+
): void {
|
|
139
150
|
uiSetDocumentThemeRaw(asWorldNumber(worldId), args);
|
|
140
151
|
}
|
|
141
152
|
|
|
@@ -145,12 +156,18 @@ export function applyUIOps(worldId: WorldUIId, args: CmdUiApplyOpsArgs): void {
|
|
|
145
156
|
}
|
|
146
157
|
|
|
147
158
|
/** Requests UI document tree. */
|
|
148
|
-
export function getUIDocumentTree(
|
|
159
|
+
export function getUIDocumentTree(
|
|
160
|
+
worldId: WorldUIId,
|
|
161
|
+
args: CmdUiDocumentGetTreeArgs,
|
|
162
|
+
): void {
|
|
149
163
|
uiGetDocumentTreeRaw(asWorldNumber(worldId), args);
|
|
150
164
|
}
|
|
151
165
|
|
|
152
166
|
/** Requests UI layout rects. */
|
|
153
|
-
export function getUILayoutRects(
|
|
167
|
+
export function getUILayoutRects(
|
|
168
|
+
worldId: WorldUIId,
|
|
169
|
+
args: CmdUiDocumentGetLayoutRectsArgs,
|
|
170
|
+
): void {
|
|
154
171
|
uiGetLayoutRectsRaw(asWorldNumber(worldId), args);
|
|
155
172
|
}
|
|
156
173
|
|
|
@@ -165,37 +182,58 @@ export function setUIFocus(worldId: WorldUIId, args: CmdUiFocusSetArgs): void {
|
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
/** Requests focus state in a UI world. */
|
|
168
|
-
export function getUIFocus(
|
|
185
|
+
export function getUIFocus(
|
|
186
|
+
worldId: WorldUIId,
|
|
187
|
+
args: CmdUiFocusGetArgs = {},
|
|
188
|
+
): void {
|
|
169
189
|
uiGetFocusRaw(asWorldNumber(worldId), args);
|
|
170
190
|
}
|
|
171
191
|
|
|
172
192
|
/** Configures UI event trace in a UI world. */
|
|
173
|
-
export function setUIEventTrace(
|
|
193
|
+
export function setUIEventTrace(
|
|
194
|
+
worldId: WorldUIId,
|
|
195
|
+
args: CmdUiEventTraceSetArgs,
|
|
196
|
+
): void {
|
|
174
197
|
uiSetEventTraceRaw(asWorldNumber(worldId), args);
|
|
175
198
|
}
|
|
176
199
|
|
|
177
200
|
/** Creates UI image from a previously uploaded buffer. */
|
|
178
|
-
export function createUIImageFromBuffer(
|
|
201
|
+
export function createUIImageFromBuffer(
|
|
202
|
+
worldId: WorldUIId,
|
|
203
|
+
args: CmdUiImageCreateFromBufferArgs,
|
|
204
|
+
): void {
|
|
179
205
|
uiCreateImageFromBufferRaw(asWorldNumber(worldId), args);
|
|
180
206
|
}
|
|
181
207
|
|
|
182
208
|
/** Disposes UI image resource. */
|
|
183
|
-
export function disposeUIImage(
|
|
209
|
+
export function disposeUIImage(
|
|
210
|
+
worldId: WorldUIId,
|
|
211
|
+
args: CmdUiImageDisposeArgs,
|
|
212
|
+
): void {
|
|
184
213
|
uiDisposeImageRaw(asWorldNumber(worldId), args);
|
|
185
214
|
}
|
|
186
215
|
|
|
187
216
|
/** Sends clipboard paste payload to UI world. */
|
|
188
|
-
export function pasteUIClipboard(
|
|
217
|
+
export function pasteUIClipboard(
|
|
218
|
+
worldId: WorldUIId,
|
|
219
|
+
args: CmdUiClipboardPasteArgs,
|
|
220
|
+
): void {
|
|
189
221
|
uiClipboardPasteRaw(asWorldNumber(worldId), args);
|
|
190
222
|
}
|
|
191
223
|
|
|
192
224
|
/** Replies to UI screenshot request. */
|
|
193
|
-
export function replyUIScreenshot(
|
|
225
|
+
export function replyUIScreenshot(
|
|
226
|
+
worldId: WorldUIId,
|
|
227
|
+
args: CmdUiScreenshotReplyArgs,
|
|
228
|
+
): void {
|
|
194
229
|
uiScreenshotReplyRaw(asWorldNumber(worldId), args);
|
|
195
230
|
}
|
|
196
231
|
|
|
197
232
|
/** Sends AccessKit action request. */
|
|
198
|
-
export function requestUIAccessKitAction(
|
|
233
|
+
export function requestUIAccessKitAction(
|
|
234
|
+
worldId: WorldUIId,
|
|
235
|
+
args: CmdUiAccessKitActionRequestArgs,
|
|
236
|
+
): void {
|
|
199
237
|
uiAccessKitActionRequestRaw(asWorldNumber(worldId), args);
|
|
200
238
|
}
|
|
201
239
|
|
|
@@ -220,17 +258,26 @@ export function disposeUIForm(worldId: WorldUIId, formId: string): void {
|
|
|
220
258
|
}
|
|
221
259
|
|
|
222
260
|
/** Upserts UI fieldset metadata. */
|
|
223
|
-
export function upsertUIFieldset(
|
|
261
|
+
export function upsertUIFieldset(
|
|
262
|
+
worldId: WorldUIId,
|
|
263
|
+
args: Parameters<typeof uiFieldsetUpsertRaw>[1],
|
|
264
|
+
): void {
|
|
224
265
|
uiFieldsetUpsertRaw(asWorldNumber(worldId), args);
|
|
225
266
|
}
|
|
226
267
|
|
|
227
268
|
/** Disposes UI fieldset metadata. */
|
|
228
|
-
export function disposeUIFieldset(
|
|
269
|
+
export function disposeUIFieldset(
|
|
270
|
+
worldId: WorldUIId,
|
|
271
|
+
args: { formId: string; fieldsetId: string },
|
|
272
|
+
): void {
|
|
229
273
|
uiFieldsetDisposeRaw(asWorldNumber(worldId), args.formId, args.fieldsetId);
|
|
230
274
|
}
|
|
231
275
|
|
|
232
276
|
/** Upserts focusable metadata. */
|
|
233
|
-
export function upsertUIFocusable(
|
|
277
|
+
export function upsertUIFocusable(
|
|
278
|
+
worldId: WorldUIId,
|
|
279
|
+
args: Parameters<typeof uiFocusableUpsertRaw>[1],
|
|
280
|
+
): void {
|
|
234
281
|
uiFocusableUpsertRaw(asWorldNumber(worldId), args);
|
|
235
282
|
}
|
|
236
283
|
|