dredless 1.0.1 → 1.1.0

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.
@@ -4068,7 +4068,6 @@
4068
4068
  firstRecord: () => firstRecord,
4069
4069
  isAquaShielderBotState: () => isAquaShielderBotState,
4070
4070
  isBlueRusherBotState: () => isBlueRusherBotState,
4071
- isBoulderBotExclusion: () => isBoulderBotExclusion,
4072
4071
  isCowardBossState: () => isCowardBossState,
4073
4072
  isLazerEnthusiastBotState: () => isLazerEnthusiastBotState,
4074
4073
  isNavigationDestination: () => isNavigationDestination,
@@ -4095,11 +4094,13 @@
4095
4094
  pushCapped: () => pushCapped,
4096
4095
  qKey: () => qKey,
4097
4096
  scaledSizeSummary: () => scaledSizeSummary,
4097
+ summarizeBall: () => summarizeBall,
4098
4098
  summarizeBlueprintPreview: () => summarizeBlueprintPreview,
4099
4099
  summarizeBot: () => summarizeBot,
4100
4100
  summarizeCannon: () => summarizeCannon,
4101
4101
  summarizeCargoEjector: () => summarizeCargoEjector,
4102
4102
  summarizeCargoHatch: () => summarizeCargoHatch,
4103
+ summarizeCombatBeams: () => summarizeCombatBeams,
4103
4104
  summarizeCommsStation: () => summarizeCommsStation,
4104
4105
  summarizeDockingSpring: () => summarizeDockingSpring,
4105
4106
  summarizeDoor: () => summarizeDoor,
@@ -4117,8 +4118,11 @@
4117
4118
  summarizeNavigationUnit: () => summarizeNavigationUnit,
4118
4119
  summarizePlayer: () => summarizePlayer,
4119
4120
  summarizePlayerPreview: () => summarizePlayerPreview,
4121
+ summarizeProjectile: () => summarizeProjectile,
4120
4122
  summarizePusher: () => summarizePusher,
4121
4123
  summarizePusherBeam: () => summarizePusherBeam,
4124
+ summarizeRcd: () => summarizeRcd,
4125
+ summarizeRecycler: () => summarizeRecycler,
4122
4126
  summarizeShieldGenerator: () => summarizeShieldGenerator,
4123
4127
  summarizeShieldProjector: () => summarizeShieldProjector,
4124
4128
  summarizeShipControl: () => summarizeShipControl,
@@ -4662,6 +4666,10 @@
4662
4666
  [11, { name: "numeric_sparse", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36 }) }],
4663
4667
  [12, { name: "numeric_sparse", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32 }) }],
4664
4668
  [14, { name: "size_state", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36, 32: 40, 64: 44 }) }],
4669
+ [15, {
4670
+ name: "combat_beams",
4671
+ fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36, 32: 40, 64: 44, 128: 48, 256: 52 })
4672
+ }],
4665
4673
  [16, {
4666
4674
  name: "label_numeric_state",
4667
4675
  read(reader, record, mask) {
@@ -4679,29 +4687,48 @@
4679
4687
  if (mask & 16) record.q36 = (record.q36 || 0) + reader.readFieldDelta();
4680
4688
  }
4681
4689
  }],
4682
- [17, { name: "numeric_sparse", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36 }) }],
4690
+ [17, {
4691
+ name: "ball",
4692
+ packedBeforeValues: true,
4693
+ packedBits: [{ bit: 1, offset: 21 }, { bit: 2, offset: 22 }]
4694
+ }],
4683
4695
  [18, {
4684
4696
  name: "mob_combat_state",
4697
+ // Official reader packs flags 64/2048 before numeric deltas. Raw offsets
4698
+ // follow that reader's layout, rather than treating flag bits as values.
4699
+ packedBeforeValues: true,
4700
+ packedBits: [{ bit: 64, offset: 77 }, { bit: 2048, offset: 78 }],
4701
+ defaults: {
4702
+ q20: -1,
4703
+ q24: 0,
4704
+ q28: 0,
4705
+ q32: 0,
4706
+ q36: 0,
4707
+ q40: -9417217,
4708
+ q44: 0,
4709
+ q48: -100,
4710
+ q52: 0,
4711
+ q56: 10,
4712
+ q60: 10,
4713
+ q64: 1,
4714
+ q68: 1,
4715
+ q72: 100
4716
+ },
4685
4717
  fields: numericFields({
4686
4718
  2: 20,
4687
4719
  4: 24,
4688
4720
  8: 28,
4689
4721
  16: 32,
4690
4722
  32: 36,
4691
- 64: 40,
4692
- 128: 44,
4693
- 256: 48,
4694
- 512: 52,
4695
- 1024: 56,
4696
- 2048: 60,
4697
- 4096: 64,
4698
- 8192: 68,
4699
- 16384: 72,
4700
- 32768: 76,
4701
- 65536: 80,
4702
- 131072: 84,
4703
- 524288: 88,
4704
- 4194304: 92
4723
+ 128: 40,
4724
+ 256: 44,
4725
+ 512: 48,
4726
+ 1024: 52,
4727
+ 4096: 56,
4728
+ 8192: 60,
4729
+ 16384: 64,
4730
+ 32768: 68,
4731
+ 65536: 72
4705
4732
  })
4706
4733
  }],
4707
4734
  [19, { name: "motion_state", packedBits: [{ bit: 4, offset: 29 }], ...TWO_FIELD_SPEC }],
@@ -4755,7 +4782,13 @@
4755
4782
  fields: numericFields({ 1: 20, 2: 24 }),
4756
4783
  blobs: [{ bit: 4, offset: 28 }, { bit: 8, offset: 40 }]
4757
4784
  }],
4758
- [24, { name: "projectile_state", packedBits: [{ bit: 8, offset: 33 }], fields: numericFields({ 1: 20, 2: 24, 4: 28 }) }],
4785
+ [24, {
4786
+ name: "projectile_state",
4787
+ defaults: { q20: 16777215, q24: 1, q28: 1 },
4788
+ packedBeforeValues: true,
4789
+ packedBits: [{ bit: 2, offset: 33 }],
4790
+ fields: numericFields({ 1: 20, 4: 24, 8: 28 })
4791
+ }],
4759
4792
  [25, {
4760
4793
  name: "zone_label",
4761
4794
  orderedValues: true,
@@ -4834,7 +4867,7 @@
4834
4867
  defaults: { q20: 0, q24: 0, q28: 0, q32: 0, q36: 0, q40: 0, q44: 0, q48: 0, q52: 0, q56: 0, q60: 0, q64: 0 },
4835
4868
  fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36, 32: 40, 64: 44, 128: 48, 256: 52, 512: 56, 1024: 60, 2048: 64 })
4836
4869
  }],
4837
- [59, { name: "numeric_sparse", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36 }) }],
4870
+ [59, { name: "rcd", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32 }) }],
4838
4871
  [60, { name: "fluid_tank", packedBits: [{ bit: 4, offset: 29 }], ...TWO_FIELD_SPEC }],
4839
4872
  [61, { name: "shield_charge", ...TWO_FIELD_SPEC }],
4840
4873
  [62, { name: "flag_state", packedBits: [{ bit: 1, offset: 21 }], fields: [] }],
@@ -4906,7 +4939,7 @@
4906
4939
  [48, 12],
4907
4940
  [49, 13],
4908
4941
  [50, 14],
4909
- [51, 51],
4942
+ [51, 15],
4910
4943
  [52, 16],
4911
4944
  [74, 17],
4912
4945
  [80, 17],
@@ -5327,38 +5360,113 @@
5327
5360
  combatRecord,
5328
5361
  motionRecord,
5329
5362
  table10Record,
5330
- table51Record,
5363
+ beamRecord,
5331
5364
  itemCrate,
5332
5365
  player,
5333
5366
  shipControl
5334
5367
  }) {
5335
- if (!health || itemCrate || player || shipControl || isBoulderBotExclusion(health, table2Record, combatRecord)) return null;
5368
+ if (!health || itemCrate || player || shipControl) return null;
5336
5369
  const className = botClassFromState({
5337
5370
  health,
5338
5371
  table2Record,
5339
5372
  smallRecord,
5340
5373
  combatRecord,
5341
5374
  table10Record,
5342
- table51Record
5375
+ beamRecord
5343
5376
  });
5377
+ if (className === "bot") return null;
5344
5378
  return {
5345
5379
  entity,
5346
5380
  className,
5381
+ classificationSource: "heuristic",
5382
+ health,
5383
+ beams: summarizeCombatBeams(entity, beamRecord),
5384
+ combat: combatRecord ? {
5385
+ bodyColorRgba: (combatRecord.q20 ?? -1) >>> 0,
5386
+ weaponColorRgba: (combatRecord.q40 ?? -9417217) >>> 0,
5387
+ aimAngle: combatRecord.q44 === -70 ? null : numberOrNull(combatRecord.q44, 10),
5388
+ thrusterMask: combatRecord.q60 ?? 10,
5389
+ alternateSprite: Boolean(combatRecord.q77),
5390
+ beamEffectEnabled: Boolean(combatRecord.q78),
5391
+ state: cloneRecord(combatRecord)
5392
+ } : null,
5347
5393
  identifier: botIdentifierFromState({ combatRecord, motionRecord, smallRecord }),
5348
5394
  typeA: health.state?.q28 ?? null,
5349
5395
  typeB: health.state?.q32 ?? null
5350
5396
  };
5351
5397
  }
5352
- function isBoulderBotExclusion(health, table2Record, combatRecord) {
5353
- return Boolean(
5354
- health?.maxHp === 2e3 && health?.state?.q28 === 30 && health?.state?.q32 != null && table2Record?.q20 != null && table2Record?.q24 == null && !combatRecord
5355
- );
5398
+ function summarizeProjectile(entity, record) {
5399
+ if (!record) return null;
5400
+ const color = record.q20 ?? 16777215;
5401
+ const itemId = record.q28 ?? 1;
5402
+ return {
5403
+ entity,
5404
+ color,
5405
+ colorCss: colorToCss(color),
5406
+ botStyle: Boolean(record.q33),
5407
+ indicatorCount: record.q24 ?? 1,
5408
+ spriteItemId: itemId === 0 ? null : itemId,
5409
+ spriteItemName: itemId === 0 ? null : entityNameFromType(itemId),
5410
+ state: cloneRecord(record)
5411
+ };
5412
+ }
5413
+ function summarizeCombatBeams(entity, record) {
5414
+ if (!record) return null;
5415
+ return {
5416
+ entity,
5417
+ beams: [0, 1, 2].map((index) => {
5418
+ const length = (record[qKey(32 + index * 4)] ?? 0) / 10;
5419
+ return {
5420
+ angle: (record[qKey(20 + index * 4)] ?? 0) / 1e3,
5421
+ length,
5422
+ active: length > 0,
5423
+ colorRgba: (record[qKey(44 + index * 4)] ?? 0) >>> 0
5424
+ };
5425
+ }),
5426
+ state: cloneRecord(record)
5427
+ };
5428
+ }
5429
+ function summarizeBall(entity, record, health = null, sizeRecord = null) {
5430
+ if (!record) return null;
5431
+ return {
5432
+ entity,
5433
+ health,
5434
+ radius: numberOrNull(sizeRecord?.q20, 20),
5435
+ rubber: Boolean(record.q21),
5436
+ isEgg: Boolean(record.q22),
5437
+ state: cloneRecord(record)
5438
+ };
5439
+ }
5440
+ function summarizeRcd(entity, record, itemHolderRecord) {
5441
+ if (!record) return null;
5442
+ const variant = (record.q20 ?? 0) === 0 ? "sandbox" : "flux";
5443
+ const item = itemSummary(itemHolderRecord?.q20, itemHolderRecord?.q24);
5444
+ return {
5445
+ entity,
5446
+ variant,
5447
+ variantCode: record.q20 ?? 0,
5448
+ itemId: variant === "sandbox" ? 121 : 122,
5449
+ storedItemId: item.itemId,
5450
+ storedItemName: item.itemName,
5451
+ storedItemCount: item.count,
5452
+ beam: {
5453
+ offsetX: (record.q28 ?? 0) / 5,
5454
+ offsetY: (record.q32 ?? 0) / 5,
5455
+ active: Boolean(record.q28 || record.q32)
5456
+ },
5457
+ state: cloneRecord(record)
5458
+ };
5459
+ }
5460
+ function summarizeRecycler(entity, marker, itemHolderRecord) {
5461
+ if (!marker) return null;
5462
+ const item = itemSummary(itemHolderRecord?.q20, itemHolderRecord?.q24);
5463
+ return { entity, storedItemId: item.itemId, storedItemName: item.itemName, storedItemCount: item.count };
5356
5464
  }
5357
- function botClassFromState({ health, table2Record, smallRecord, combatRecord, table10Record, table51Record }) {
5465
+ function botClassFromState({ health, table2Record, smallRecord, combatRecord, table10Record, beamRecord }) {
5358
5466
  if (isYellowMineGuardBotState({ health, smallRecord, combatRecord, table2Record })) return "yellow-mine-guard";
5359
5467
  if (isShieldHelperBotState({ health, table2Record })) return "shield-helper";
5360
5468
  if (isShieldMasterBotState({ health, table2Record })) return "shield-master";
5361
- if (isLazerEnthusiastBotState({ health, table2Record, table10Record, table51Record })) return "lazer-enthusiast";
5469
+ if (isLazerEnthusiastBotState({ health, table2Record, table10Record, beamRecord })) return "lazer-enthusiast";
5362
5470
  if (isCowardBossState({ health })) return "the-coward";
5363
5471
  if (isOrangeFoolBotState({ combatRecord })) return "orange-fool";
5364
5472
  if (isZombieBossBotState({ health, table2Record, combatRecord })) return "zombie-boss";
@@ -5372,6 +5480,7 @@
5372
5480
  if (isAquaShielderBotState({ health, table2Record, combatRecord })) return "aqua-shielder";
5373
5481
  if (table2Record) return "table2-bot";
5374
5482
  if (combatRecord) return "combat-bot";
5483
+ if (beamRecord) return "beam-bot";
5375
5484
  return "bot";
5376
5485
  }
5377
5486
  function isCowardBossState({ health }) {
@@ -5398,8 +5507,8 @@
5398
5507
  function isAquaShielderBotState({ health, table2Record, combatRecord }) {
5399
5508
  return combatRecord?.q20 === 13697024 && combatRecord?.q24 === 1 || health?.state?.q28 === 50 && health?.state?.q32 === 122 && table2Record?.q20 === 240 && table2Record?.q24 === -900;
5400
5509
  }
5401
- function isLazerEnthusiastBotState({ health, table2Record, table10Record, table51Record }) {
5402
- return health?.state?.q28 === 140 && health?.state?.q32 === 155 && table2Record?.q20 === 300 && table2Record?.q24 === -900 && Boolean(table10Record) && Boolean(table51Record);
5510
+ function isLazerEnthusiastBotState({ health, table2Record, table10Record, beamRecord }) {
5511
+ return health?.state?.q28 === 140 && health?.state?.q32 === 155 && table2Record?.q20 === 300 && table2Record?.q24 === -900 && Boolean(table10Record) && Boolean(beamRecord);
5403
5512
  }
5404
5513
  function isYellowMineGuardBotState({ health, smallRecord, combatRecord, table2Record }) {
5405
5514
  return health?.state?.q28 === 30 && health?.state?.q32 === 33 && smallRecord?.q20 === 78 && smallRecord?.q24 === 78 && combatRecord?.q24 === -995542016 && !table2Record;
@@ -5952,6 +6061,10 @@
5952
6061
  return { width: 1, height: 1, source: "default" };
5953
6062
  }
5954
6063
  function entityLabel(entity) {
6064
+ if (entity?.projectile) return "Projectile";
6065
+ if (entity?.ball) return entity.ball.isEgg ? "Egg" : "Ball";
6066
+ if (entity?.rcd) return entity.rcd.variant === "sandbox" ? "Sandbox RCD" : "Flux RCD";
6067
+ if (entity?.recycler) return "Recycler";
5955
6068
  if (entity?.category === "metadata" && entity?.typeName) return `Metadata ${entity.typeName}`;
5956
6069
  if (entity?.blueprintPreview) return `Blueprint Preview (${entity.blueprintPreview.itemName ?? entity.blueprintPreview.itemId ?? "item"})`;
5957
6070
  if (entity?.category === "loose_item" && entity?.itemHolder?.itemName) return `Loose ${entity.itemHolder.itemName}`;
@@ -5982,6 +6095,10 @@
5982
6095
  return entity?.typeId != null ? `Entity ${entity.typeId}` : "Entity";
5983
6096
  }
5984
6097
  function entityCategory(entity) {
6098
+ if (entity?.projectile) return "projectile";
6099
+ if (entity?.ball) return "ball";
6100
+ if (entity?.rcd) return "rcd";
6101
+ if (entity?.recycler) return "placed_entity";
5985
6102
  if (entity?.player) return "player";
5986
6103
  if (entity?.blueprintPreview) return "blueprint_preview";
5987
6104
  if (entity?.shipControl) return "ship_control";
@@ -6084,7 +6201,11 @@
6084
6201
  summarizeCommsStation: summarizeCommsStation2,
6085
6202
  summarizeHealth: summarizeHealth2,
6086
6203
  summarizeBot: summarizeBot2,
6087
- isBoulderBotExclusion: isBoulderBotExclusion2,
6204
+ summarizeProjectile: summarizeProjectile2,
6205
+ summarizeCombatBeams: summarizeCombatBeams2,
6206
+ summarizeBall: summarizeBall2,
6207
+ summarizeRcd: summarizeRcd2,
6208
+ summarizeRecycler: summarizeRecycler2,
6088
6209
  botClassFromState: botClassFromState2,
6089
6210
  isCowardBossState: isCowardBossState2,
6090
6211
  isOrangeFoolBotState: isOrangeFoolBotState2,
@@ -6265,6 +6386,11 @@
6265
6386
  blocks: includeBlocks ? this.#derivedBlocks().slice() : void 0,
6266
6387
  transforms: derived.transforms.slice(),
6267
6388
  players: derived.players.slice(),
6389
+ projectiles: derived.specialEntities.projectiles.slice(),
6390
+ bots: derived.specialEntities.bots.slice(),
6391
+ rcds: derived.specialEntities.rcds.slice(),
6392
+ balls: derived.specialEntities.balls.slice(),
6393
+ recyclers: derived.specialEntities.recyclers.slice(),
6268
6394
  shipControls: derived.shipControls.slice(),
6269
6395
  machines: this.#machinesSnapshot(derived.machines),
6270
6396
  tables: includeTables ? this.tablesSnapshot() : derived.tableSummaries.slice()
@@ -6289,6 +6415,21 @@
6289
6415
  players() {
6290
6416
  return this.#derivedState().players.slice();
6291
6417
  }
6418
+ projectiles() {
6419
+ return this.#derivedState().specialEntities.projectiles.slice();
6420
+ }
6421
+ bots() {
6422
+ return this.#derivedState().specialEntities.bots.slice();
6423
+ }
6424
+ rcds() {
6425
+ return this.#derivedState().specialEntities.rcds.slice();
6426
+ }
6427
+ balls() {
6428
+ return this.#derivedState().specialEntities.balls.slice();
6429
+ }
6430
+ recyclers() {
6431
+ return this.#derivedState().specialEntities.recyclers.slice();
6432
+ }
6292
6433
  shipControls() {
6293
6434
  return this.#derivedState().shipControls.slice();
6294
6435
  }
@@ -6633,6 +6774,7 @@
6633
6774
  doors: [],
6634
6775
  expandoBoxes: []
6635
6776
  };
6777
+ const specialEntities = { projectiles: [], bots: [], rcds: [], balls: [], recyclers: [] };
6636
6778
  const players = [];
6637
6779
  const shipControls = [];
6638
6780
  const transforms = [];
@@ -6661,12 +6803,18 @@
6661
6803
  if (contents.spawnPoint) machines.spawnPoints.push(contents.spawnPoint);
6662
6804
  if (contents.door) machines.doors.push(contents.door);
6663
6805
  if (contents.expandoBox) machines.expandoBoxes.push(contents.expandoBox);
6806
+ if (contents.projectile) specialEntities.projectiles.push(contents.projectile);
6807
+ if (contents.bot) specialEntities.bots.push(contents.bot);
6808
+ if (contents.rcd) specialEntities.rcds.push(contents.rcd);
6809
+ if (contents.ball) specialEntities.balls.push(contents.ball);
6810
+ if (contents.recycler) specialEntities.recyclers.push(contents.recycler);
6664
6811
  if (contents.player) players.push(contents.player);
6665
6812
  if (contents.shipControl) shipControls.push(contents.shipControl);
6666
6813
  }
6667
6814
  derived.entities = entities;
6668
6815
  derived.transforms = transforms;
6669
6816
  derived.players = players;
6817
+ derived.specialEntities = specialEntities;
6670
6818
  derived.shipControls = shipControls;
6671
6819
  derived.machines = machines;
6672
6820
  derived.summariesDirty = false;
@@ -6743,6 +6891,11 @@
6743
6891
  const itemHolder = summarizeItemHolder2(entityId, itemHolderRecord);
6744
6892
  const isExpandoBox = typeId === EXPANDO_BOX_TYPE_ID2 || markerTypeId === EXPANDO_BOX_TYPE_ID2;
6745
6893
  const health = summarizeHealth2(entityId, healthRecord);
6894
+ const projectile = summarizeProjectile2(entityId, rec(24));
6895
+ const combatBeams = summarizeCombatBeams2(entityId, rec(15));
6896
+ const ball = summarizeBall2(entityId, rec(17), health, rec(2));
6897
+ const rcd = summarizeRcd2(entityId, rec(59), itemHolderRecord);
6898
+ const recycler = this.isOverworld === false ? summarizeRecycler2(entityId, rec(23), itemHolderRecord) : null;
6746
6899
  const fabricator = summarizeFabricator2(entityId, fabricatorRecord, itemHolderRecord, typeRecord);
6747
6900
  const cargoEjector = summarizeCargoEjector2(entityId, typeId, cargoEjectorRecord);
6748
6901
  const cannon = summarizeCannon2(entityId, cannonRecord, typeId, transformRecord);
@@ -6774,15 +6927,15 @@
6774
6927
  const mapMarker = this.isOverworld ? summarizeMapMarker2(entityId, labelRecord, zoneLabelRecord, crateSizeRecord) : null;
6775
6928
  const dockingSpring = this.isOverworld ? summarizeDockingSpring2(entityId, dockingSpringRecord, bodyStateRecord, crateSizeRecord) : null;
6776
6929
  const hugeThruster = this.isOverworld ? summarizeHugeThruster2(entityId, hugeThrusterRecord, crateSizeRecord) : null;
6777
- const itemCrate = this.isOverworld && !rec(2) && !rec(18) && health && crateSizeRecord ? summarizeItemCrate2(entityId, crateSizeRecord, crateItemRecord, healthRecord) : null;
6778
- const bot = this.isOverworld ? summarizeBot2(entityId, {
6930
+ const itemCrate = this.isOverworld && !rec(2) && !rec(18) && !combatBeams && !projectile && !ball && !rcd && health && crateSizeRecord ? summarizeItemCrate2(entityId, crateSizeRecord, crateItemRecord, healthRecord) : null;
6931
+ const bot = (this.isOverworld || rec(18) || combatBeams) && !projectile && !ball && !rcd ? summarizeBot2(entityId, {
6779
6932
  health,
6780
6933
  table2Record: rec(2),
6781
6934
  smallRecord: crateSizeRecord,
6782
6935
  combatRecord: rec(18),
6783
6936
  motionRecord: crateItemRecord,
6784
6937
  table10Record: rec(10),
6785
- table51Record: rec(51),
6938
+ beamRecord: rec(15),
6786
6939
  itemCrate,
6787
6940
  player,
6788
6941
  shipControl
@@ -6795,6 +6948,11 @@
6795
6948
  flags: [transformRecord.q33, transformRecord.q34, transformRecord.q35].filter((value) => value != null)
6796
6949
  } : null;
6797
6950
  const contents = mergeContents2({
6951
+ projectile,
6952
+ combatBeams,
6953
+ ball,
6954
+ rcd,
6955
+ recycler,
6798
6956
  itemHolder,
6799
6957
  expandoBox,
6800
6958
  hoverOutline,
@@ -6855,6 +7013,10 @@
6855
7013
  });
6856
7014
  const typeName = entityNameFromType2(typeId);
6857
7015
  const category = entityCategory2({
7016
+ projectile,
7017
+ ball,
7018
+ rcd,
7019
+ recycler,
6858
7020
  typeId,
6859
7021
  markerTypeId,
6860
7022
  looseItemMarker,
@@ -6890,6 +7052,10 @@
6890
7052
  markerTypeId,
6891
7053
  markerTypeName,
6892
7054
  label: entityLabel2({
7055
+ projectile,
7056
+ ball,
7057
+ rcd,
7058
+ recycler,
6893
7059
  category,
6894
7060
  typeId,
6895
7061
  typeName,
@@ -6923,6 +7089,11 @@
6923
7089
  isOverworld: this.isOverworld
6924
7090
  }),
6925
7091
  kind: [
7092
+ projectile ? "projectile" : null,
7093
+ combatBeams ? "combat_beams" : null,
7094
+ ball ? "ball" : null,
7095
+ rcd ? "rcd" : null,
7096
+ recycler ? "recycler" : null,
6926
7097
  transform ? "transform" : null,
6927
7098
  dynamicBody ? "dynamic_body" : null,
6928
7099
  itemHolder ? "item_holder" : null,
@@ -7529,6 +7700,11 @@
7529
7700
  transforms: model.transforms,
7530
7701
  machines: model.machines,
7531
7702
  players: model.players,
7703
+ projectiles: model.projectiles,
7704
+ bots: model.bots,
7705
+ rcds: model.rcds,
7706
+ balls: model.balls,
7707
+ recyclers: model.recyclers,
7532
7708
  shipControls: model.shipControls,
7533
7709
  commsBubbles: this.commsBubbles.slice(),
7534
7710
  tiles: includeTiles ? [...this.tiles.values()] : void 0
@@ -8941,6 +9117,11 @@
8941
9117
  this.entities = new EntityCollection(client, scope);
8942
9118
  this.machines = new MachineCollection(client, scope);
8943
9119
  this.players = new PlayerCollection(client, scope);
9120
+ this.projectiles = new EntitySummaryCollection(client, scope, "projectiles");
9121
+ this.bots = new EntitySummaryCollection(client, scope, "bots");
9122
+ this.rcds = new EntitySummaryCollection(client, scope, "rcds");
9123
+ this.balls = new EntitySummaryCollection(client, scope, "balls");
9124
+ this.recyclers = new EntitySummaryCollection(client, scope, "recyclers");
8944
9125
  this.blocks = new BlockCollection(client, scope);
8945
9126
  this.materials = new MaterialCollection(client, scope);
8946
9127
  }
@@ -9058,6 +9239,21 @@
9058
9239
  return currentPlayerSummary(this.client, this.scope);
9059
9240
  }
9060
9241
  };
9242
+ var EntitySummaryCollection = class {
9243
+ constructor(client, scope, method) {
9244
+ this.client = client;
9245
+ this.scope = scope;
9246
+ this.method = method;
9247
+ this.component = { projectiles: "projectile", bots: "bot", rcds: "rcd", balls: "ball", recyclers: "recycler" }[method];
9248
+ }
9249
+ all() {
9250
+ return worldStateFor(this.client, this.scope)?.model[this.method]() || [];
9251
+ }
9252
+ get(entity) {
9253
+ const id = entityIdOf(entity);
9254
+ return worldStateFor(this.client, this.scope)?.model.entity(id)?.contents?.[this.component] || null;
9255
+ }
9256
+ };
9061
9257
  var BlockCollection = class {
9062
9258
  constructor(client, scope) {
9063
9259
  this.client = client;
@@ -9709,6 +9905,7 @@
9709
9905
  }
9710
9906
  };
9711
9907
  var ENTITY_COMPONENT_ALIASES = /* @__PURE__ */ new Map([
9908
+ ["combatbeams", "combatBeams"],
9712
9909
  ["hoveroutline", "hoverOutline"],
9713
9910
  ["outline", "hoverOutline"],
9714
9911
  ["itemholder", "itemHolder"],
@@ -9759,6 +9956,12 @@
9759
9956
  "expandoBox"
9760
9957
  ];
9761
9958
  var ENTITY_FEATURES = [
9959
+ "combatBeams",
9960
+ "projectile",
9961
+ "bot",
9962
+ "rcd",
9963
+ "ball",
9964
+ "recycler",
9762
9965
  "health",
9763
9966
  "position",
9764
9967
  "outline",
@@ -9817,6 +10020,10 @@
9817
10020
  return null;
9818
10021
  }
9819
10022
  function entityPublicType(summary, contents) {
10023
+ if (contents?.projectile) return "projectile";
10024
+ if (contents?.rcd) return "rcd";
10025
+ if (contents?.ball) return contents.ball.isEgg ? "egg" : "ball";
10026
+ if (contents?.recycler) return "recycler";
9820
10027
  const machine = entityMachineType(contents);
9821
10028
  if (machine) return machine;
9822
10029
  if (contents?.player || summary?.category === "player") return "player";