@agent-play/sdk 3.2.2 → 3.3.2

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.
@@ -0,0 +1,649 @@
1
+ // src/lib/world-bounds.ts
2
+ var MINIMUM_PLAY_WORLD_BOUNDS = {
3
+ minX: 0,
4
+ minY: 0,
5
+ maxX: 19,
6
+ maxY: 19
7
+ };
8
+ function expandBoundsToMinimumPlayArea(bounds) {
9
+ return {
10
+ minX: Math.min(bounds.minX, MINIMUM_PLAY_WORLD_BOUNDS.minX),
11
+ minY: Math.min(bounds.minY, MINIMUM_PLAY_WORLD_BOUNDS.minY),
12
+ maxX: Math.max(bounds.maxX, MINIMUM_PLAY_WORLD_BOUNDS.maxX),
13
+ maxY: Math.max(bounds.maxY, MINIMUM_PLAY_WORLD_BOUNDS.maxY)
14
+ };
15
+ }
16
+ function clampWorldPosition(p, bounds) {
17
+ return {
18
+ x: Math.min(Math.max(p.x, bounds.minX), bounds.maxX),
19
+ y: Math.min(Math.max(p.y, bounds.minY), bounds.maxY)
20
+ };
21
+ }
22
+ function boundsContain(bounds, p) {
23
+ return p.x >= bounds.minX && p.x <= bounds.maxX && p.y >= bounds.minY && p.y <= bounds.maxY;
24
+ }
25
+
26
+ // src/lib/occupancy-grid-model.ts
27
+ var OCCUPANCY_POINT_MULTIPLIER = 5;
28
+ var CONTINUOUS_RENDER_OFFSET = 0.2;
29
+ var DEFAULT_AGENT_SPAWN_MIN_DISTANCE = 0.9;
30
+ var SPATIAL_ZONE_INDEX_AGENTS = 0;
31
+ var SPATIAL_ZONE_INDEX_SPACES = 2;
32
+ function spatialZoneBounds(quartileIndex) {
33
+ const { minX, maxX, minY, maxY } = MINIMUM_PLAY_WORLD_BOUNDS;
34
+ const spanX = maxX - minX + 1;
35
+ const spanY = maxY - minY + 1;
36
+ const halfX = spanX / 2;
37
+ const halfY = spanY / 2;
38
+ const midLeftMax = minX + halfX - 1;
39
+ const midRightMin = minX + halfX;
40
+ const midBottomMax = minY + halfY - 1;
41
+ const midTopMin = minY + halfY;
42
+ switch (quartileIndex) {
43
+ case 0:
44
+ return { minX, maxX: midLeftMax, minY, maxY: midBottomMax };
45
+ case 1:
46
+ return { minX: midRightMin, maxX, minY, maxY: midBottomMax };
47
+ case 2:
48
+ return { minX, maxX: midLeftMax, minY: midTopMin, maxY };
49
+ case 3:
50
+ return { minX: midRightMin, maxX, minY: midTopMin, maxY };
51
+ default:
52
+ throw new Error(
53
+ `spatialZoneBounds: invalid zone index ${String(quartileIndex)}`
54
+ );
55
+ }
56
+ }
57
+ function spatialZoneCenter(quartileIndex) {
58
+ const b = spatialZoneBounds(quartileIndex);
59
+ return {
60
+ x: (b.minX + b.maxX + 1) / 2,
61
+ y: (b.minY + b.maxY + 1) / 2
62
+ };
63
+ }
64
+ function enumerateIntegerCellsInBounds(bounds) {
65
+ const cells = [];
66
+ for (let x = bounds.minX; x <= bounds.maxX; x += 1) {
67
+ for (let y = bounds.minY; y <= bounds.maxY; y += 1) {
68
+ cells.push({ x, y });
69
+ }
70
+ }
71
+ return cells;
72
+ }
73
+ function pointCellInSpatialZone(wx, wy, zoneIndex) {
74
+ const bounds = spatialZoneBounds(zoneIndex);
75
+ const cx = Math.floor(wx);
76
+ const cy = Math.floor(wy);
77
+ return cx >= bounds.minX && cx <= bounds.maxX && cy >= bounds.minY && cy <= bounds.maxY;
78
+ }
79
+ function listOccupancyPointsForSpatialZone(zoneIndex) {
80
+ const bounds = spatialZoneBounds(zoneIndex);
81
+ return enumerateIntegerCellsInBounds(bounds).flatMap((cell) => {
82
+ const points = [];
83
+ for (let dx = 0; dx < OCCUPANCY_POINT_MULTIPLIER; dx += 1) {
84
+ for (let dy = 0; dy < OCCUPANCY_POINT_MULTIPLIER; dy += 1) {
85
+ points.push({
86
+ x: cell.x + CONTINUOUS_RENDER_OFFSET + (dx + 0.5) / OCCUPANCY_POINT_MULTIPLIER,
87
+ y: cell.y + CONTINUOUS_RENDER_OFFSET + (dy + 0.5) / OCCUPANCY_POINT_MULTIPLIER
88
+ });
89
+ }
90
+ }
91
+ return points;
92
+ });
93
+ }
94
+ function occupancyPointsGroupedBySpatialZone() {
95
+ return [
96
+ listOccupancyPointsForSpatialZone(0),
97
+ listOccupancyPointsForSpatialZone(1),
98
+ listOccupancyPointsForSpatialZone(2),
99
+ listOccupancyPointsForSpatialZone(3)
100
+ ];
101
+ }
102
+ function listAllowedOccupancyPoints() {
103
+ return listOccupancyPointsForSpatialZone(SPATIAL_ZONE_INDEX_AGENTS);
104
+ }
105
+ function quantizePosition(v) {
106
+ return Math.round(v * OCCUPANCY_POINT_MULTIPLIER) / OCCUPANCY_POINT_MULTIPLIER;
107
+ }
108
+ function occupancyKeyForPosition(x, y) {
109
+ return `${quantizePosition(x).toFixed(3)},${quantizePosition(y).toFixed(3)}`;
110
+ }
111
+ function buildRankedOccupancyPointsForSpatialZone(zoneIndex) {
112
+ const center = spatialZoneCenter(zoneIndex);
113
+ return [...listOccupancyPointsForSpatialZone(zoneIndex)].sort((left, right) => {
114
+ const dl = Math.hypot(left.x - center.x, left.y - center.y);
115
+ const dr = Math.hypot(right.x - center.x, right.y - center.y);
116
+ if (dl !== dr) {
117
+ return dl - dr;
118
+ }
119
+ if (left.x !== right.x) {
120
+ return left.x - right.x;
121
+ }
122
+ return left.y - right.y;
123
+ });
124
+ }
125
+ function buildRankedOccupancyPoints() {
126
+ return buildRankedOccupancyPointsForSpatialZone(SPATIAL_ZONE_INDEX_AGENTS);
127
+ }
128
+ function boundingWorldRectForOccupancyPoints(points) {
129
+ const head = points[0];
130
+ if (head === void 0) {
131
+ return null;
132
+ }
133
+ let minX = head.x;
134
+ let maxX = head.x;
135
+ let minY = head.y;
136
+ let maxY = head.y;
137
+ for (const p of points) {
138
+ if (p.x < minX) minX = p.x;
139
+ if (p.x > maxX) maxX = p.x;
140
+ if (p.y < minY) minY = p.y;
141
+ if (p.y > maxY) maxY = p.y;
142
+ }
143
+ return { minX, maxX, minY, maxY };
144
+ }
145
+ function isAgentSpawnOccupancyPointAvailable(input) {
146
+ const minDistance = input.minDistance ?? DEFAULT_AGENT_SPAWN_MIN_DISTANCE;
147
+ const key = occupancyKeyForPosition(input.point.x, input.point.y);
148
+ if (input.occupiedKeys.has(key)) {
149
+ return false;
150
+ }
151
+ if (!pointCellInSpatialZone(
152
+ input.point.x,
153
+ input.point.y,
154
+ SPATIAL_ZONE_INDEX_AGENTS
155
+ )) {
156
+ return false;
157
+ }
158
+ for (const existing of input.existingOccupants) {
159
+ const dist = Math.hypot(
160
+ input.point.x - existing.x,
161
+ input.point.y - existing.y
162
+ );
163
+ if (dist < minDistance) {
164
+ return false;
165
+ }
166
+ }
167
+ return true;
168
+ }
169
+ function isSpaceAnchorOccupancyPointAvailable(input) {
170
+ const key = occupancyKeyForPosition(input.point.x, input.point.y);
171
+ if (input.occupiedKeys.has(key)) {
172
+ return false;
173
+ }
174
+ if (!pointCellInSpatialZone(
175
+ input.point.x,
176
+ input.point.y,
177
+ SPATIAL_ZONE_INDEX_SPACES
178
+ )) {
179
+ return false;
180
+ }
181
+ for (const existing of input.existingOccupants) {
182
+ const dist = Math.hypot(
183
+ input.point.x - existing.x,
184
+ input.point.y - existing.y
185
+ );
186
+ if (dist < input.minDistance) {
187
+ return false;
188
+ }
189
+ }
190
+ for (const anchor of input.structureAnchors) {
191
+ const dist = Math.hypot(
192
+ input.point.x - anchor.x,
193
+ input.point.y - anchor.y
194
+ );
195
+ if (dist < input.structureMinDistance) {
196
+ return false;
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+
202
+ // src/lib/world-chain-keys.ts
203
+ var PLAYER_CHAIN_GENESIS_STABLE_KEY = "__genesis__";
204
+ var PLAYER_CHAIN_HEADER_STABLE_KEY = "__header__";
205
+
206
+ // src/lib/parse-occupant-row.ts
207
+ var SPACE_AMENITY_KINDS = [
208
+ "supermarket",
209
+ "shop",
210
+ "car_wash"
211
+ ];
212
+ function isSpaceAmenityKind(v) {
213
+ return SPACE_AMENITY_KINDS.includes(v);
214
+ }
215
+ function isRecord(v) {
216
+ return typeof v === "object" && v !== null;
217
+ }
218
+ function parseHumanOccupantRow(raw) {
219
+ if (typeof raw.id !== "string" || typeof raw.name !== "string") {
220
+ throw new Error("occupant: human needs id and name");
221
+ }
222
+ if (typeof raw.x !== "number" || typeof raw.y !== "number") {
223
+ throw new Error("occupant: human needs numeric x and y");
224
+ }
225
+ const base = {
226
+ kind: "human",
227
+ id: raw.id,
228
+ name: raw.name,
229
+ x: raw.x,
230
+ y: raw.y
231
+ };
232
+ if (typeof raw.interactive === "boolean") {
233
+ return { ...base, interactive: raw.interactive };
234
+ }
235
+ return base;
236
+ }
237
+ function parseAgentOccupantRow(raw) {
238
+ if (typeof raw.agentId !== "string" || typeof raw.name !== "string") {
239
+ throw new Error("occupant: agent needs agentId and name");
240
+ }
241
+ if (typeof raw.x !== "number" || typeof raw.y !== "number") {
242
+ throw new Error("occupant: agent needs numeric x and y");
243
+ }
244
+ const base = {
245
+ kind: "agent",
246
+ agentId: raw.agentId,
247
+ name: raw.name,
248
+ x: raw.x,
249
+ y: raw.y
250
+ };
251
+ if (typeof raw.nodeId === "string" && raw.nodeId.length > 0) {
252
+ base.nodeId = raw.nodeId;
253
+ }
254
+ let platform;
255
+ if (typeof raw.platform === "string") {
256
+ platform = raw.platform;
257
+ } else if (typeof raw.agentType === "string") {
258
+ platform = raw.agentType;
259
+ }
260
+ const enableP2a = raw.enableP2a === "on" || raw.enableP2a === "off" ? raw.enableP2a : void 0;
261
+ const realtimeInstructions = typeof raw.realtimeInstructions === "string" && raw.realtimeInstructions.trim().length > 0 ? raw.realtimeInstructions : void 0;
262
+ const realtimeRaw = raw.realtimeWebrtc;
263
+ const realtimeWebrtc = typeof realtimeRaw === "object" && realtimeRaw !== null && typeof realtimeRaw.clientSecret === "string" && realtimeRaw.clientSecret.length > 0 && typeof realtimeRaw.model === "string" && realtimeRaw.model.length > 0 ? (() => {
264
+ const record = realtimeRaw;
265
+ const parsed = {
266
+ clientSecret: record.clientSecret,
267
+ model: record.model
268
+ };
269
+ if (typeof record.expiresAt === "string" && record.expiresAt.length > 0) {
270
+ parsed.expiresAt = record.expiresAt;
271
+ }
272
+ if (typeof record.voice === "string" && record.voice.length > 0) {
273
+ parsed.voice = record.voice;
274
+ }
275
+ return parsed;
276
+ })() : void 0;
277
+ const out = { ...base };
278
+ if (platform !== void 0) {
279
+ out.platform = platform;
280
+ }
281
+ if (enableP2a !== void 0) {
282
+ out.enableP2a = enableP2a;
283
+ }
284
+ if (realtimeInstructions !== void 0) {
285
+ out.realtimeInstructions = realtimeInstructions;
286
+ }
287
+ if (realtimeWebrtc !== void 0) {
288
+ out.realtimeWebrtc = realtimeWebrtc;
289
+ }
290
+ return out;
291
+ }
292
+ function parseMcpOccupantRow(raw) {
293
+ if (typeof raw.id !== "string" || typeof raw.name !== "string") {
294
+ throw new Error("occupant: mcp needs id and name");
295
+ }
296
+ if (typeof raw.x !== "number" || typeof raw.y !== "number") {
297
+ throw new Error("occupant: mcp needs numeric x and y");
298
+ }
299
+ const base = {
300
+ kind: "mcp",
301
+ id: raw.id,
302
+ name: raw.name,
303
+ x: raw.x,
304
+ y: raw.y
305
+ };
306
+ if (typeof raw.url === "string") {
307
+ return { ...base, url: raw.url };
308
+ }
309
+ return base;
310
+ }
311
+ function parseSpaceCatalogEntry(raw) {
312
+ if (typeof raw.id !== "string" || typeof raw.name !== "string") {
313
+ throw new Error("space catalog: id and name required");
314
+ }
315
+ if (typeof raw.description !== "string") {
316
+ throw new Error("space catalog: description required");
317
+ }
318
+ if (typeof raw.designKey !== "string") {
319
+ throw new Error("space catalog: designKey required");
320
+ }
321
+ const ownerRaw = raw.owner;
322
+ if (!isRecord(ownerRaw) || typeof ownerRaw.displayName !== "string") {
323
+ throw new Error("space catalog: owner.displayName required");
324
+ }
325
+ const amenitiesRaw = raw.amenities;
326
+ if (!Array.isArray(amenitiesRaw) || amenitiesRaw.length === 0) {
327
+ throw new Error("space catalog: amenities must be a non-empty array");
328
+ }
329
+ const amenities = [];
330
+ for (const a of amenitiesRaw) {
331
+ if (typeof a !== "string" || !isSpaceAmenityKind(a)) {
332
+ throw new Error("space catalog: invalid amenity");
333
+ }
334
+ amenities.push(a);
335
+ }
336
+ const owner = {
337
+ displayName: ownerRaw.displayName
338
+ };
339
+ if (typeof ownerRaw.playerId === "string" && ownerRaw.playerId.length > 0) {
340
+ owner.playerId = ownerRaw.playerId;
341
+ }
342
+ if (typeof ownerRaw.nodeId === "string" && ownerRaw.nodeId.length > 0) {
343
+ owner.nodeId = ownerRaw.nodeId;
344
+ }
345
+ const entry = {
346
+ id: raw.id,
347
+ name: raw.name,
348
+ description: raw.description,
349
+ designKey: raw.designKey,
350
+ owner,
351
+ amenities
352
+ };
353
+ if (Array.isArray(raw.activityObjectIds)) {
354
+ const ids = [];
355
+ for (const x of raw.activityObjectIds) {
356
+ if (typeof x === "string") {
357
+ ids.push(x);
358
+ }
359
+ }
360
+ if (ids.length > 0) {
361
+ entry.activityObjectIds = ids;
362
+ }
363
+ }
364
+ return entry;
365
+ }
366
+ function parseStructureOccupantRow(raw) {
367
+ if (typeof raw.id !== "string" || typeof raw.name !== "string") {
368
+ throw new Error("occupant: structure needs id and name");
369
+ }
370
+ if (typeof raw.x !== "number" || typeof raw.y !== "number") {
371
+ throw new Error("occupant: structure needs numeric x and y");
372
+ }
373
+ if (typeof raw.worldId !== "string") {
374
+ throw new Error("occupant: structure needs worldId");
375
+ }
376
+ const spaceIdsRaw = raw.spaceIds;
377
+ if (!Array.isArray(spaceIdsRaw) || spaceIdsRaw.length === 0) {
378
+ throw new Error("occupant: structure needs non-empty spaceIds");
379
+ }
380
+ const spaceIds = [];
381
+ for (const s of spaceIdsRaw) {
382
+ if (typeof s !== "string") {
383
+ throw new Error("occupant: structure spaceIds must be strings");
384
+ }
385
+ spaceIds.push(s);
386
+ }
387
+ const base = {
388
+ kind: "structure",
389
+ id: raw.id,
390
+ name: raw.name,
391
+ x: raw.x,
392
+ y: raw.y,
393
+ worldId: raw.worldId,
394
+ spaceIds
395
+ };
396
+ if (raw.stationary === true) {
397
+ base.stationary = true;
398
+ }
399
+ const pa = raw.primaryAmenity;
400
+ if (typeof pa === "string" && isSpaceAmenityKind(pa)) {
401
+ base.primaryAmenity = pa;
402
+ }
403
+ const am = raw.amenities;
404
+ if (Array.isArray(am) && am.length > 0) {
405
+ const list = [];
406
+ for (const x of am) {
407
+ if (typeof x === "string" && isSpaceAmenityKind(x)) {
408
+ list.push(x);
409
+ }
410
+ }
411
+ if (list.length > 0) {
412
+ base.amenities = list;
413
+ }
414
+ }
415
+ return base;
416
+ }
417
+
418
+ // src/lib/player-chain-merge.ts
419
+ function isRecord2(v) {
420
+ return typeof v === "object" && v !== null;
421
+ }
422
+ function stableOccupantSortKey(occ) {
423
+ if (occ.kind === "human") {
424
+ return `human:${occ.id}`;
425
+ }
426
+ if (occ.kind === "agent") {
427
+ const nodeId = occ.nodeId;
428
+ if (typeof nodeId !== "string" || nodeId.length === 0) {
429
+ throw new Error("stableOccupantSortKey: invalid agent nodeId");
430
+ }
431
+ return `agent:${nodeId}:${occ.agentId}`;
432
+ }
433
+ if (occ.kind === "structure") {
434
+ return `structure:${occ.id}`;
435
+ }
436
+ return `mcp:${occ.id}`;
437
+ }
438
+ function sortNodeRefsForSerializedFetch(nodes) {
439
+ const removed = nodes.filter((n) => n.removed === true);
440
+ const rest = nodes.filter((n) => n.removed !== true);
441
+ removed.sort((a, b) => b.leafIndex - a.leafIndex);
442
+ rest.sort((a, b) => a.leafIndex - b.leafIndex);
443
+ return [...removed, ...rest];
444
+ }
445
+ function parsePlayerChainFanoutNotify(raw) {
446
+ if (!isRecord2(raw)) {
447
+ return void 0;
448
+ }
449
+ if (typeof raw.updatedAt !== "string" || raw.updatedAt.length === 0) {
450
+ return void 0;
451
+ }
452
+ if (!Array.isArray(raw.nodes)) {
453
+ return void 0;
454
+ }
455
+ const nodes = [];
456
+ for (const row of raw.nodes) {
457
+ if (!isRecord2(row)) {
458
+ return void 0;
459
+ }
460
+ if (typeof row.stableKey !== "string" || row.stableKey.length === 0) {
461
+ return void 0;
462
+ }
463
+ if (typeof row.leafIndex !== "number" || !Number.isFinite(row.leafIndex)) {
464
+ return void 0;
465
+ }
466
+ const ref = {
467
+ stableKey: row.stableKey,
468
+ leafIndex: row.leafIndex
469
+ };
470
+ if (row.removed === true) {
471
+ ref.removed = true;
472
+ }
473
+ if (typeof row.updatedAt === "string" && row.updatedAt.length > 0) {
474
+ ref.updatedAt = row.updatedAt;
475
+ }
476
+ nodes.push(ref);
477
+ }
478
+ return { updatedAt: raw.updatedAt, nodes };
479
+ }
480
+ function parsePlayerChainFanoutNotifyFromSsePayload(sseData) {
481
+ if (!isRecord2(sseData)) {
482
+ return void 0;
483
+ }
484
+ return parsePlayerChainFanoutNotify(sseData.playerChainNotify);
485
+ }
486
+ function parsePlayerChainNodeRpcBody(json) {
487
+ if (!isRecord2(json) || !isRecord2(json.node)) {
488
+ throw new Error("getPlayerChainNode: invalid response shape");
489
+ }
490
+ const n = json.node;
491
+ if (n.kind === "genesis") {
492
+ if (n.stableKey !== PLAYER_CHAIN_GENESIS_STABLE_KEY || typeof n.text !== "string") {
493
+ throw new Error("getPlayerChainNode: invalid genesis node");
494
+ }
495
+ return {
496
+ kind: "genesis",
497
+ stableKey: PLAYER_CHAIN_GENESIS_STABLE_KEY,
498
+ text: n.text
499
+ };
500
+ }
501
+ if (n.kind === "header") {
502
+ if (n.stableKey !== PLAYER_CHAIN_HEADER_STABLE_KEY || typeof n.sid !== "string") {
503
+ throw new Error("getPlayerChainNode: invalid header node");
504
+ }
505
+ const b = n.bounds;
506
+ if (!isRecord2(b)) {
507
+ throw new Error("getPlayerChainNode: invalid header bounds");
508
+ }
509
+ const { minX, minY, maxX, maxY } = b;
510
+ if (typeof minX !== "number" || typeof minY !== "number" || typeof maxX !== "number" || typeof maxY !== "number") {
511
+ throw new Error("getPlayerChainNode: invalid header bounds");
512
+ }
513
+ return {
514
+ kind: "header",
515
+ stableKey: PLAYER_CHAIN_HEADER_STABLE_KEY,
516
+ sid: n.sid,
517
+ bounds: { minX, minY, maxX, maxY }
518
+ };
519
+ }
520
+ if (n.kind === "space") {
521
+ if (typeof n.stableKey !== "string" || n.stableKey.length === 0) {
522
+ throw new Error("getPlayerChainNode: invalid space stableKey");
523
+ }
524
+ if (n.removed === true) {
525
+ return { kind: "space", stableKey: n.stableKey, removed: true };
526
+ }
527
+ const sp = n.space;
528
+ if (!isRecord2(sp)) {
529
+ throw new Error("getPlayerChainNode: invalid space payload");
530
+ }
531
+ return {
532
+ kind: "space",
533
+ stableKey: n.stableKey,
534
+ removed: false,
535
+ space: parseSpaceCatalogEntry(sp)
536
+ };
537
+ }
538
+ if (n.kind !== "occupant") {
539
+ throw new Error("getPlayerChainNode: unknown node kind");
540
+ }
541
+ if (typeof n.stableKey !== "string" || n.stableKey.length === 0) {
542
+ throw new Error("getPlayerChainNode: invalid occupant stableKey");
543
+ }
544
+ if (n.removed === true) {
545
+ return { kind: "occupant", stableKey: n.stableKey, removed: true };
546
+ }
547
+ const occ = n.occupant;
548
+ if (!isRecord2(occ) || occ.kind !== "human" && occ.kind !== "agent" && occ.kind !== "mcp" && occ.kind !== "structure") {
549
+ throw new Error("getPlayerChainNode: invalid occupant payload");
550
+ }
551
+ const occupant = occ.kind === "human" ? parseHumanOccupantRow(occ) : occ.kind === "agent" ? parseAgentOccupantRow(occ) : occ.kind === "mcp" ? parseMcpOccupantRow(occ) : parseStructureOccupantRow(occ);
552
+ return {
553
+ kind: "occupant",
554
+ stableKey: n.stableKey,
555
+ removed: false,
556
+ occupant
557
+ };
558
+ }
559
+ function mergeSnapshotWithPlayerChainNode(snapshot, node) {
560
+ if (node.kind === "genesis") {
561
+ return snapshot;
562
+ }
563
+ if (node.kind === "space") {
564
+ const spaceIdFromKey = node.stableKey.startsWith("space:") ? node.stableKey.slice("space:".length) : "";
565
+ if (node.removed === true) {
566
+ return {
567
+ ...snapshot,
568
+ spaces: (snapshot.spaces ?? []).filter((s) => s.id !== spaceIdFromKey)
569
+ };
570
+ }
571
+ const merged = (snapshot.spaces ?? []).filter((s) => s.id !== node.space.id);
572
+ merged.push(node.space);
573
+ merged.sort((a, b) => a.id.localeCompare(b.id));
574
+ return { ...snapshot, spaces: merged };
575
+ }
576
+ if (node.kind === "header") {
577
+ return {
578
+ ...snapshot,
579
+ sid: node.sid,
580
+ worldMap: {
581
+ ...snapshot.worldMap,
582
+ bounds: node.bounds
583
+ }
584
+ };
585
+ }
586
+ if (node.removed === true) {
587
+ return {
588
+ ...snapshot,
589
+ worldMap: {
590
+ ...snapshot.worldMap,
591
+ occupants: snapshot.worldMap.occupants.filter(
592
+ (o) => stableOccupantSortKey(o) !== node.stableKey
593
+ )
594
+ }
595
+ };
596
+ }
597
+ if (node.removed !== false) {
598
+ throw new Error("mergeSnapshotWithPlayerChainNode: invalid occupant node");
599
+ }
600
+ const occ = node.occupant;
601
+ const key = stableOccupantSortKey(occ);
602
+ const occupants = snapshot.worldMap.occupants.filter(
603
+ (o) => stableOccupantSortKey(o) !== key
604
+ );
605
+ return {
606
+ ...snapshot,
607
+ worldMap: {
608
+ ...snapshot.worldMap,
609
+ occupants: [...occupants, occ]
610
+ }
611
+ };
612
+ }
613
+
614
+ export {
615
+ MINIMUM_PLAY_WORLD_BOUNDS,
616
+ expandBoundsToMinimumPlayArea,
617
+ clampWorldPosition,
618
+ boundsContain,
619
+ OCCUPANCY_POINT_MULTIPLIER,
620
+ CONTINUOUS_RENDER_OFFSET,
621
+ DEFAULT_AGENT_SPAWN_MIN_DISTANCE,
622
+ SPATIAL_ZONE_INDEX_AGENTS,
623
+ SPATIAL_ZONE_INDEX_SPACES,
624
+ spatialZoneBounds,
625
+ spatialZoneCenter,
626
+ pointCellInSpatialZone,
627
+ listOccupancyPointsForSpatialZone,
628
+ occupancyPointsGroupedBySpatialZone,
629
+ listAllowedOccupancyPoints,
630
+ occupancyKeyForPosition,
631
+ buildRankedOccupancyPointsForSpatialZone,
632
+ buildRankedOccupancyPoints,
633
+ boundingWorldRectForOccupancyPoints,
634
+ isAgentSpawnOccupancyPointAvailable,
635
+ isSpaceAnchorOccupancyPointAvailable,
636
+ parseHumanOccupantRow,
637
+ parseAgentOccupantRow,
638
+ parseMcpOccupantRow,
639
+ parseSpaceCatalogEntry,
640
+ parseStructureOccupantRow,
641
+ PLAYER_CHAIN_GENESIS_STABLE_KEY,
642
+ PLAYER_CHAIN_HEADER_STABLE_KEY,
643
+ sortNodeRefsForSerializedFetch,
644
+ parsePlayerChainFanoutNotify,
645
+ parsePlayerChainFanoutNotifyFromSsePayload,
646
+ parsePlayerChainNodeRpcBody,
647
+ mergeSnapshotWithPlayerChainNode
648
+ };
649
+ //# sourceMappingURL=chunk-WWIEHWZZ.js.map