@shipload/sdk 1.0.0-next.5 → 1.0.0-next.50

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.
Files changed (144) hide show
  1. package/lib/scan.d.ts +52 -0
  2. package/lib/scan.js +162 -0
  3. package/lib/scan.js.map +1 -0
  4. package/lib/scan.m.js +152 -0
  5. package/lib/scan.m.js.map +1 -0
  6. package/lib/shipload.d.ts +2881 -1149
  7. package/lib/shipload.js +13031 -5511
  8. package/lib/shipload.js.map +1 -1
  9. package/lib/shipload.m.js +12807 -5460
  10. package/lib/shipload.m.js.map +1 -1
  11. package/lib/testing.d.ts +1028 -0
  12. package/lib/testing.js +4336 -0
  13. package/lib/testing.js.map +1 -0
  14. package/lib/testing.m.js +4330 -0
  15. package/lib/testing.m.js.map +1 -0
  16. package/package.json +20 -2
  17. package/src/capabilities/craftable.ts +51 -0
  18. package/src/capabilities/crafting.test.ts +7 -0
  19. package/src/capabilities/crafting.ts +6 -7
  20. package/src/capabilities/gathering.test.ts +29 -0
  21. package/src/capabilities/gathering.ts +37 -19
  22. package/src/capabilities/index.ts +0 -1
  23. package/src/capabilities/modules.ts +22 -0
  24. package/src/capabilities/storage.ts +16 -1
  25. package/src/contracts/platform.ts +231 -3
  26. package/src/contracts/server.ts +1160 -520
  27. package/src/coordinates/address.ts +88 -0
  28. package/src/coordinates/constants.test.ts +15 -0
  29. package/src/coordinates/constants.ts +23 -0
  30. package/src/coordinates/index.ts +15 -0
  31. package/src/coordinates/memo.test.ts +47 -0
  32. package/src/coordinates/memo.ts +20 -0
  33. package/src/coordinates/permutation.ts +77 -0
  34. package/src/coordinates/regions.ts +48 -0
  35. package/src/coordinates/sectors.ts +115 -0
  36. package/src/data/capabilities.ts +31 -16
  37. package/src/data/capability-formulas.ts +21 -14
  38. package/src/data/catalog.ts +0 -5
  39. package/src/data/colors.ts +13 -47
  40. package/src/data/entities.json +154 -10
  41. package/src/data/item-ids.ts +31 -12
  42. package/src/data/items.json +192 -74
  43. package/src/data/kind-registry.json +131 -0
  44. package/src/data/kind-registry.ts +172 -0
  45. package/src/data/metadata.ts +166 -48
  46. package/src/data/recipes-runtime.ts +5 -23
  47. package/src/data/recipes.json +1003 -163
  48. package/src/derivation/build-methods.test.ts +13 -0
  49. package/src/derivation/build-methods.ts +48 -0
  50. package/src/derivation/capabilities.test.ts +151 -0
  51. package/src/derivation/capabilities.ts +527 -0
  52. package/src/derivation/capability-mappings.ts +58 -16
  53. package/src/derivation/crafting.ts +36 -33
  54. package/src/derivation/index.ts +28 -2
  55. package/src/derivation/recipe-usage.test.ts +81 -0
  56. package/src/derivation/recipe-usage.ts +141 -0
  57. package/src/derivation/reserve-regen.ts +34 -0
  58. package/src/derivation/resources.ts +98 -19
  59. package/src/derivation/rollups.test.ts +55 -0
  60. package/src/derivation/rollups.ts +56 -0
  61. package/src/derivation/stars.test.ts +67 -0
  62. package/src/derivation/stars.ts +25 -0
  63. package/src/derivation/stats.ts +6 -6
  64. package/src/derivation/stratum.ts +26 -22
  65. package/src/derivation/tiers.ts +40 -7
  66. package/src/derivation/upgrades.ts +14 -0
  67. package/src/derivation/wormhole.ts +141 -0
  68. package/src/entities/entity.ts +98 -0
  69. package/src/entities/gamestate.ts +3 -28
  70. package/src/entities/makers.ts +131 -134
  71. package/src/entities/slot-multiplier.ts +43 -0
  72. package/src/errors.ts +12 -16
  73. package/src/format.ts +26 -4
  74. package/src/index-module.ts +290 -34
  75. package/src/managers/actions.ts +602 -105
  76. package/src/managers/base.ts +6 -2
  77. package/src/managers/cluster.test.ts +39 -0
  78. package/src/managers/cluster.ts +53 -0
  79. package/src/managers/construction-types.ts +80 -0
  80. package/src/managers/construction.ts +412 -0
  81. package/src/managers/context.ts +29 -1
  82. package/src/managers/coordinates.ts +14 -0
  83. package/src/managers/entities.ts +27 -66
  84. package/src/managers/epochs.ts +40 -0
  85. package/src/managers/flatten-gather-plan.test.ts +80 -0
  86. package/src/managers/index.ts +20 -1
  87. package/src/managers/locations.ts +25 -29
  88. package/src/managers/nft.test.ts +14 -0
  89. package/src/managers/nft.ts +70 -0
  90. package/src/managers/players.ts +25 -0
  91. package/src/managers/plot.ts +122 -0
  92. package/src/nft/atomicassets.abi.json +1342 -0
  93. package/src/nft/atomicassets.ts +237 -0
  94. package/src/nft/atomicdata.ts +130 -0
  95. package/src/nft/buildImmutableData.ts +336 -0
  96. package/src/nft/description.ts +104 -36
  97. package/src/nft/index.ts +3 -0
  98. package/src/planner/index.ts +242 -0
  99. package/src/planner/planner.test.ts +325 -0
  100. package/src/resolution/describe-module.ts +43 -25
  101. package/src/resolution/display-name.ts +38 -10
  102. package/src/resolution/resolve-item.test.ts +48 -0
  103. package/src/resolution/resolve-item.ts +74 -47
  104. package/src/scan/index.ts +244 -0
  105. package/src/scan/scan-wasm.base64.ts +2 -0
  106. package/src/scheduling/accessor.ts +65 -23
  107. package/src/scheduling/availability.ts +108 -0
  108. package/src/scheduling/cancel.test.ts +348 -0
  109. package/src/scheduling/cancel.ts +209 -0
  110. package/src/scheduling/energy.ts +47 -0
  111. package/src/scheduling/idle-resolve.ts +45 -0
  112. package/src/scheduling/lane-core.ts +128 -0
  113. package/src/scheduling/lanes.test.ts +249 -0
  114. package/src/scheduling/lanes.ts +198 -0
  115. package/src/scheduling/projection.ts +210 -107
  116. package/src/scheduling/schedule.ts +240 -117
  117. package/src/scheduling/task-cargo.ts +46 -0
  118. package/src/scheduling/unwrap.test.ts +86 -0
  119. package/src/scheduling/unwrap.ts +190 -0
  120. package/src/shipload.ts +26 -1
  121. package/src/subscriptions/manager.cluster.test.ts +51 -0
  122. package/src/subscriptions/manager.ts +245 -172
  123. package/src/subscriptions/mappers.ts +5 -8
  124. package/src/subscriptions/types.ts +28 -3
  125. package/src/testing/catalog-hash.ts +19 -0
  126. package/src/testing/index.ts +2 -0
  127. package/src/testing/projection-parity.ts +167 -0
  128. package/src/travel/reach.ts +23 -0
  129. package/src/travel/route-planner.ts +277 -0
  130. package/src/travel/travel.ts +148 -117
  131. package/src/types/capabilities.ts +29 -6
  132. package/src/types/entity.ts +3 -3
  133. package/src/types/index.ts +0 -1
  134. package/src/types.ts +36 -14
  135. package/src/utils/cargo.test.ts +14 -0
  136. package/src/utils/cargo.ts +29 -0
  137. package/src/utils/display-name.ts +70 -0
  138. package/src/utils/system.ts +36 -24
  139. package/src/capabilities/loading.ts +0 -8
  140. package/src/entities/container.ts +0 -123
  141. package/src/entities/ship-deploy.ts +0 -295
  142. package/src/entities/ship.ts +0 -221
  143. package/src/entities/warehouse.ts +0 -127
  144. package/src/types/entity-traits.ts +0 -69
@@ -28,12 +28,22 @@ import {
28
28
  type Distance,
29
29
  MAX_ORBITAL_ALTITUDE,
30
30
  MIN_ORBITAL_ALTITUDE,
31
+ MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL,
32
+ MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE,
31
33
  PRECISION,
32
34
  type ShipLike,
33
35
  TaskType,
34
36
  } from '../types'
37
+ import {EntityClass} from '../data/kind-registry'
35
38
  import {getItem} from '../data/catalog'
36
39
  import {hasSystem} from '../utils/system'
40
+ import {WH} from '../derivation/wormhole'
41
+ import * as scheduleModel from '../scheduling/schedule'
42
+ import type {ScheduleData} from '../scheduling/schedule'
43
+
44
+ function isPositionalTask(task: ServerContract.Types.task): boolean {
45
+ return task.type.equals(TaskType.TRAVEL) || task.type.equals(TaskType.TRANSIT)
46
+ }
37
47
 
38
48
  export function calc_orbital_altitude(mass: number): number {
39
49
  if (mass <= BASE_ORBITAL_MASS) {
@@ -111,15 +121,16 @@ export function getInterpolatedPosition(
111
121
  taskIndex: number,
112
122
  taskProgress: number
113
123
  ): FloatPosition {
114
- if (!entity.schedule || entity.schedule.tasks.length === 0) {
124
+ const tasks = mobilityTasks(entity)
125
+ if (tasks.length === 0) {
115
126
  return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
116
127
  }
117
128
  if (taskIndex < 0) {
118
- const settled = getFlightOrigin(entity, entity.schedule.tasks.length)
129
+ const settled = getFlightOrigin(entity, tasks.length)
119
130
  return {x: Number(settled.x), y: Number(settled.y)}
120
131
  }
121
- const task = entity.schedule.tasks[taskIndex]
122
- if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
132
+ const task = tasks[taskIndex]
133
+ if (!isPositionalTask(task) || !task.coordinates) {
123
134
  const origin = getFlightOrigin(entity, taskIndex)
124
135
  return {x: Number(origin.x), y: Number(origin.y)}
125
136
  }
@@ -192,15 +203,31 @@ export function calc_flighttime(distance: UInt64Type, acceleration: number): UIn
192
203
  return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
193
204
  }
194
205
 
206
+ export function calc_transit_duration(ax: number, ay: number, bx: number, by: number): UInt32 {
207
+ const distance = distanceBetweenPoints(ax, ay, bx, by)
208
+ return UInt32.from(Math.floor(distance.toNumber() / (PRECISION * WH.TRANSIT_SPEED)))
209
+ }
210
+
211
+ // The active entity's chosen loader lane (lowest slot), mirroring cargo.cpp lane selection.
212
+ export function shipLoaderLane(ship: ShipLike): {thrust: number; mass: number} | undefined {
213
+ const lanes = ship.loader_lanes ?? []
214
+ if (lanes.length === 0) return undefined
215
+ let lowest = lanes[0]
216
+ for (const lane of lanes) {
217
+ if (Number(lane.slot_index) < Number(lowest.slot_index)) lowest = lane
218
+ }
219
+ return {thrust: Number(lowest.thrust), mass: Number(lowest.mass)}
220
+ }
221
+
195
222
  export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?: number): UInt32 {
196
223
  const z = altitude ?? ship.coordinates.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
197
224
  return calc_flighttime(z, calc_loader_acceleration(ship, mass))
198
225
  }
199
226
 
200
227
  export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
201
- const thrust = ship.loaders ? Number(ship.loaders.thrust) : 0
202
- const loaderMass = ship.loaders ? Number(ship.loaders.mass) : 0
203
- return calc_acceleration(thrust, Number(mass) + loaderMass)
228
+ const lane = shipLoaderLane(ship)
229
+ const thrust = lane ? lane.thrust : 0
230
+ return calc_acceleration(thrust, Number(mass))
204
231
  }
205
232
 
206
233
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -222,8 +249,10 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
222
249
 
223
250
  mass.add(ship.hullmass)
224
251
 
225
- if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
226
- mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
252
+ if (ship.loader_lanes && ship.loader_lanes.length > 0) {
253
+ for (const l of ship.loader_lanes) {
254
+ mass.add(UInt64.from(l.mass))
255
+ }
227
256
  }
228
257
 
229
258
  for (const cargo of cargos) {
@@ -258,10 +287,10 @@ export function calculateTransferTime(
258
287
  return UInt32.from(0)
259
288
  }
260
289
 
261
- if (!ship.loaders) return UInt32.from(0)
262
- mass = UInt64.from(mass).adding(ship.loaders.mass)
263
- const transfer_time = calc_loader_flighttime(ship, mass)
264
- return transfer_time.dividing(ship.loaders.quantity)
290
+ const lane = shipLoaderLane(ship)
291
+ if (!lane) return UInt32.from(0)
292
+ mass = UInt64.from(mass).adding(UInt64.from(lane.mass))
293
+ return calc_loader_flighttime(ship, mass)
265
294
  }
266
295
 
267
296
  export function calculateRefuelingTime(ship: ShipLike): UInt32 {
@@ -316,25 +345,22 @@ export function calculateLoadTimeBreakdown(
316
345
  let unloadTime = 0
317
346
  let loadTime = 0
318
347
 
319
- if (mass_unload.gt(UInt64.zero) && ship.loaders) {
320
- const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
348
+ const lane = shipLoaderLane(ship)
349
+
350
+ if (mass_unload.gt(UInt64.zero) && lane) {
351
+ const totalMass = UInt64.from(mass_unload).adding(UInt64.from(lane.mass))
321
352
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
322
353
  }
323
354
 
324
- if (mass_load.gt(UInt64.zero) && ship.loaders) {
325
- const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
355
+ if (mass_load.gt(UInt64.zero) && lane) {
356
+ const totalMass = UInt64.from(mass_load).adding(UInt64.from(lane.mass))
326
357
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
327
358
  }
328
359
 
329
- const numLoaders = ship.loaders ? Number(ship.loaders.quantity) : 0
330
- const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
331
- const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
332
- const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
333
-
334
360
  return {
335
- unloadTime: unloadTimePerLoader,
336
- loadTime: loadTimePerLoader,
337
- totalTime,
361
+ unloadTime,
362
+ loadTime,
363
+ totalTime: unloadTime + loadTime,
338
364
  unloadMass: Number(mass_unload),
339
365
  loadMass: Number(mass_load),
340
366
  }
@@ -368,24 +394,16 @@ export function estimateTravelTime(
368
394
  let loadTime = UInt32.zero
369
395
  let unloadTime = UInt32.zero
370
396
 
371
- if (
372
- loadMass &&
373
- UInt32.from(loadMass).gt(UInt32.zero) &&
374
- ship.loaders &&
375
- ship.loaders.quantity.gt(UInt32.zero)
376
- ) {
377
- const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
378
- loadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
397
+ const lane = shipLoaderLane(ship)
398
+
399
+ if (loadMass && UInt32.from(loadMass).gt(UInt32.zero) && lane) {
400
+ const totalMass = UInt64.from(loadMass).adding(UInt64.from(lane.mass))
401
+ loadTime = calc_loader_flighttime(ship, totalMass)
379
402
  }
380
403
 
381
- if (
382
- unloadMass &&
383
- UInt32.from(unloadMass).gt(UInt32.zero) &&
384
- ship.loaders &&
385
- ship.loaders.quantity.gt(UInt32.zero)
386
- ) {
387
- const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
388
- unloadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
404
+ if (unloadMass && UInt32.from(unloadMass).gt(UInt32.zero) && lane) {
405
+ const totalMass = UInt64.from(unloadMass).adding(UInt64.from(lane.mass))
406
+ unloadTime = calc_loader_flighttime(ship, totalMass)
389
407
  }
390
408
 
391
409
  return {
@@ -417,30 +435,51 @@ export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): bool
417
435
  return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
418
436
  }
419
437
 
438
+ export interface TransferLoaderLane {
439
+ slot_index?: {toNumber(): number} | number
440
+ thrust: {toNumber(): number} | number
441
+ mass: {toNumber(): number} | number
442
+ }
443
+
420
444
  export interface TransferEntity {
421
445
  location: {z?: {toNumber(): number} | number}
422
- loaders?: {
423
- thrust: {toNumber(): number} | number
424
- mass: {toNumber(): number} | number
425
- quantity: {toNumber(): number} | number
446
+ entityClass: EntityClass
447
+ loaderLanes?: TransferLoaderLane[]
448
+ }
449
+
450
+ function toNum(v: {toNumber(): number} | number | undefined): number {
451
+ if (v === undefined) return 0
452
+ return typeof v === 'number' ? v : v.toNumber()
453
+ }
454
+
455
+ // Mirrors cargo.cpp worker_lane_key_or_mobility: lowest-slot loader lane (display has no busy context).
456
+ function chosenLoaderLane(entity: TransferEntity): TransferLoaderLane | undefined {
457
+ const lanes = entity.loaderLanes ?? []
458
+ if (lanes.length === 0) return undefined
459
+ let lowest = lanes[0]
460
+ for (const lane of lanes) {
461
+ if (toNum(lane.slot_index) < toNum(lowest.slot_index)) lowest = lane
426
462
  }
463
+ return lowest
427
464
  }
428
465
 
429
- export interface HasScheduleAndLocation {
466
+ export interface HasScheduleAndLocation extends ScheduleData {
430
467
  coordinates: ServerContract.ActionParams.Type.coordinates
431
- schedule?: ServerContract.Types.schedule
468
+ }
469
+
470
+ function mobilityTasks(entity: HasScheduleAndLocation): ServerContract.Types.task[] {
471
+ return scheduleModel.mobilityLane(entity)?.schedule.tasks ?? []
432
472
  }
433
473
 
434
474
  export function getFlightOrigin(
435
475
  entity: HasScheduleAndLocation,
436
476
  flightTaskIndex: number
437
477
  ): ServerContract.ActionParams.Type.coordinates {
438
- if (!entity.schedule) return entity.coordinates
439
-
478
+ const tasks = mobilityTasks(entity)
440
479
  let origin = entity.coordinates
441
- for (let i = 0; i < flightTaskIndex && i < entity.schedule.tasks.length; i++) {
442
- const task = entity.schedule.tasks[i]
443
- if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
480
+ for (let i = 0; i < flightTaskIndex && i < tasks.length; i++) {
481
+ const task = tasks[i]
482
+ if (isPositionalTask(task) && task.coordinates) {
444
483
  origin = task.coordinates
445
484
  }
446
485
  }
@@ -450,11 +489,10 @@ export function getFlightOrigin(
450
489
  export function getDestinationLocation(
451
490
  entity: HasScheduleAndLocation
452
491
  ): ServerContract.ActionParams.Type.coordinates | undefined {
453
- if (!entity.schedule) return undefined
454
-
455
- for (let i = entity.schedule.tasks.length - 1; i >= 0; i--) {
456
- const task = entity.schedule.tasks[i]
457
- if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
492
+ const tasks = mobilityTasks(entity)
493
+ for (let i = tasks.length - 1; i >= 0; i--) {
494
+ const task = tasks[i]
495
+ if (isPositionalTask(task) && task.coordinates) {
458
496
  return task.coordinates
459
497
  }
460
498
  }
@@ -467,16 +505,17 @@ export function getPositionAt(
467
505
  taskIndex: number,
468
506
  taskProgress: number
469
507
  ): ServerContract.ActionParams.Type.coordinates {
470
- if (!entity.schedule || entity.schedule.tasks.length === 0) {
508
+ const tasks = mobilityTasks(entity)
509
+ if (tasks.length === 0) {
471
510
  return entity.coordinates
472
511
  }
473
512
  if (taskIndex < 0) {
474
- return getFlightOrigin(entity, entity.schedule.tasks.length)
513
+ return getFlightOrigin(entity, tasks.length)
475
514
  }
476
515
 
477
- const task = entity.schedule.tasks[taskIndex]
516
+ const task = tasks[taskIndex]
478
517
 
479
- if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
518
+ if (!isPositionalTask(task) || !task.coordinates) {
480
519
  return getFlightOrigin(entity, taskIndex)
481
520
  }
482
521
 
@@ -490,68 +529,60 @@ export function getPositionAt(
490
529
  }
491
530
  }
492
531
 
493
- export function calc_transfer_duration(
494
- source: TransferEntity,
495
- dest: TransferEntity,
532
+ export function minTransferDistance(entityClass: EntityClass): number {
533
+ return entityClass === EntityClass.OrbitalVessel
534
+ ? MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL
535
+ : MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE
536
+ }
537
+
538
+ // Mirrors cargo.cpp calc_onesided_duration: single active loader's thrust + mass, no ÷quantity.
539
+ export function calc_onesided_duration(
540
+ loaderThrust: number,
541
+ loaderMass: number,
542
+ activeZ: number,
543
+ counterpartZ: number,
544
+ activeEntityClass: EntityClass,
545
+ counterpartEntityClass: EntityClass,
496
546
  cargoMass: number
497
547
  ): number {
498
- if (cargoMass === 0) {
548
+ if (cargoMass === 0 || loaderThrust === 0) {
499
549
  return 0
500
550
  }
551
+ const rawDistance = Math.abs(activeZ - counterpartZ)
552
+ const minDistance = Math.max(
553
+ minTransferDistance(activeEntityClass),
554
+ minTransferDistance(counterpartEntityClass)
555
+ )
556
+ const distance = rawDistance < minDistance ? minDistance : rawDistance
557
+ const totalMass = cargoMass + loaderMass
558
+ const acceleration = calc_acceleration(loaderThrust, totalMass)
559
+ const flightTime = Math.floor(2 * Math.sqrt(distance / acceleration))
560
+ return flightTime === 0 ? 1 : flightTime
561
+ }
501
562
 
502
- let totalThrust = 0
503
- let totalLoaderMass = 0
504
- let totalQuantity = 0
505
-
506
- if (source.loaders) {
507
- const thrust =
508
- typeof source.loaders.thrust === 'number'
509
- ? source.loaders.thrust
510
- : source.loaders.thrust.toNumber()
511
- const mass =
512
- typeof source.loaders.mass === 'number'
513
- ? source.loaders.mass
514
- : source.loaders.mass.toNumber()
515
- const qty =
516
- typeof source.loaders.quantity === 'number'
517
- ? source.loaders.quantity
518
- : source.loaders.quantity.toNumber()
519
- totalThrust += thrust * qty
520
- totalLoaderMass += mass * qty
521
- totalQuantity += qty
522
- }
523
-
524
- if (dest.loaders) {
525
- const thrust =
526
- typeof dest.loaders.thrust === 'number'
527
- ? dest.loaders.thrust
528
- : dest.loaders.thrust.toNumber()
529
- const mass =
530
- typeof dest.loaders.mass === 'number' ? dest.loaders.mass : dest.loaders.mass.toNumber()
531
- const qty =
532
- typeof dest.loaders.quantity === 'number'
533
- ? dest.loaders.quantity
534
- : dest.loaders.quantity.toNumber()
535
- totalThrust += thrust * qty
536
- totalLoaderMass += mass * qty
537
- totalQuantity += qty
538
- }
539
-
540
- if (totalThrust === 0 || totalQuantity === 0) {
563
+ // Mirrors cargo.cpp: the active (loader-bearing) entity's chosen loader lane drives the duration.
564
+ export function calc_transfer_duration(
565
+ source: TransferEntity,
566
+ dest: TransferEntity,
567
+ cargoMass: number
568
+ ): number {
569
+ const active = chosenLoaderLane(source) ? source : dest
570
+ const counterpart = active === source ? dest : source
571
+ const lane = chosenLoaderLane(active)
572
+ if (!lane) {
541
573
  return 0
542
574
  }
543
575
 
544
- const sourceZ =
545
- typeof source.location.z === 'number'
546
- ? source.location.z
547
- : (source.location.z?.toNumber() ?? 0)
548
- const destZ =
549
- typeof dest.location.z === 'number' ? dest.location.z : (dest.location.z?.toNumber() ?? 0)
550
- const distance = Math.abs(sourceZ - destZ)
551
-
552
- const totalMass = cargoMass + totalLoaderMass
553
- const acceleration = calc_acceleration(totalThrust, totalMass)
554
- const flightTime = 2 * Math.sqrt(distance / acceleration)
555
-
556
- return Math.floor(flightTime / totalQuantity)
576
+ const activeZ = toNum(active.location.z)
577
+ const counterpartZ = toNum(counterpart.location.z)
578
+
579
+ return calc_onesided_duration(
580
+ toNum(lane.thrust),
581
+ toNum(lane.mass),
582
+ activeZ,
583
+ counterpartZ,
584
+ active.entityClass,
585
+ counterpart.entityClass,
586
+ cargoMass
587
+ )
557
588
  }
@@ -1,6 +1,23 @@
1
- import type {Name, UInt16, UInt32} from '@wharfkit/antelope'
1
+ import type {Name, UInt16, UInt32, UInt8} from '@wharfkit/antelope'
2
2
  import type {ServerContract} from '../contracts'
3
3
 
4
+ export interface LoaderStats {
5
+ mass: {toNumber(): number; multiplying(v: unknown): {toNumber(): number}}
6
+ thrust: {toNumber(): number}
7
+ quantity: {toNumber(): number; gt(v: unknown): boolean}
8
+ }
9
+
10
+ export interface GathererStats {
11
+ yield: {toNumber(): number}
12
+ drain: {toNumber(): number}
13
+ depth: {toNumber(): number; toString(): string}
14
+ }
15
+
16
+ export interface CrafterStats {
17
+ speed: {toNumber(): number}
18
+ drain: {toNumber(): number}
19
+ }
20
+
4
21
  export interface MovementCapability {
5
22
  engines: ServerContract.Types.movement_stats
6
23
  generator: ServerContract.Types.energy_stats
@@ -17,11 +34,11 @@ export interface StorageCapability {
17
34
  }
18
35
 
19
36
  export interface LoaderCapability {
20
- loaders: ServerContract.Types.loader_stats
37
+ loaders: LoaderStats
21
38
  }
22
39
 
23
40
  export interface GathererCapability {
24
- gatherer: ServerContract.Types.gatherer_stats
41
+ gatherer: GathererStats
25
42
  }
26
43
 
27
44
  export interface MassCapability {
@@ -29,6 +46,7 @@ export interface MassCapability {
29
46
  }
30
47
 
31
48
  export interface ScheduleCapability {
49
+ lanes?: ServerContract.Types.lane[]
32
50
  schedule?: ServerContract.Types.schedule
33
51
  }
34
52
 
@@ -37,10 +55,11 @@ export interface EntityCapabilities {
37
55
  capacity?: UInt32
38
56
  engines?: ServerContract.Types.movement_stats
39
57
  generator?: ServerContract.Types.energy_stats
40
- loaders?: ServerContract.Types.loader_stats
41
- gatherer?: ServerContract.Types.gatherer_stats
42
- crafter?: ServerContract.Types.crafter_stats
58
+ loaders?: LoaderStats
59
+ gatherer?: GathererStats
60
+ crafter?: CrafterStats
43
61
  hauler?: ServerContract.Types.hauler_stats
62
+ launcher?: ServerContract.Types.launcher_stats
44
63
  }
45
64
 
46
65
  export interface EntityState {
@@ -74,3 +93,7 @@ export function capsHasMass(caps: EntityCapabilities): boolean {
74
93
  export function capsHasHauler(caps: EntityCapabilities): boolean {
75
94
  return caps.hauler !== undefined
76
95
  }
96
+
97
+ export function capsHasLauncher(caps: EntityCapabilities): boolean {
98
+ return caps.launcher !== undefined
99
+ }
@@ -3,6 +3,7 @@ import type {ServerContract} from '../contracts'
3
3
  import type {Coordinates} from '../types'
4
4
  import type {
5
5
  EnergyCapability,
6
+ GathererCapability,
6
7
  LoaderCapability,
7
8
  MassCapability,
8
9
  MovementCapability,
@@ -24,9 +25,8 @@ export type ShipEntity = Entity &
24
25
  StorageCapability &
25
26
  Partial<LoaderCapability> &
26
27
  MassCapability &
27
- ScheduleCapability & {
28
- gatherer?: ServerContract.Types.gatherer_stats
29
- }
28
+ ScheduleCapability &
29
+ Partial<GathererCapability>
30
30
 
31
31
  export type WarehouseEntity = Entity &
32
32
  StorageCapability &
@@ -1,3 +1,2 @@
1
1
  export * from './capabilities'
2
2
  export * from './entity'
3
- export * from './entity-traits'
package/src/types.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  type Int64Type,
3
- Name,
4
3
  type UInt16,
5
4
  type UInt16Type,
6
5
  type UInt32,
7
6
  type UInt32Type,
8
7
  UInt64,
8
+ type UInt64Type,
9
9
  } from '@wharfkit/antelope'
10
10
  import {ServerContract} from './contracts'
11
11
 
12
12
  export const PRECISION = 10000
13
13
  export const CRAFT_ENERGY_DIVISOR = 150000
14
14
 
15
- export const WAREHOUSE_Z = 500
15
+ export const PLANETARY_STRUCTURE_Z = 0
16
16
 
17
17
  export const CONTAINER_Z = 300
18
18
 
@@ -23,13 +23,22 @@ export const MAX_ORBITAL_ALTITUDE = 3000
23
23
 
24
24
  export const BASE_ORBITAL_MASS = 100000
25
25
 
26
+ export const MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE = 100
27
+ export const MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL = 200
28
+
29
+ export interface ClusterSlotType {
30
+ hub: UInt64Type
31
+ gx: number
32
+ gy: number
33
+ }
34
+
26
35
  export interface ShipLike {
27
36
  coordinates: ServerContract.Types.coordinates
28
37
  hullmass?: UInt32
29
38
  energy?: UInt16
30
39
  engines?: ServerContract.Types.movement_stats
31
40
  generator?: ServerContract.Types.energy_stats
32
- loaders?: ServerContract.Types.loader_stats
41
+ loader_lanes?: ServerContract.Types.loader_lane[]
33
42
  hauler?: ServerContract.Types.hauler_stats
34
43
  capacity?: UInt32
35
44
  }
@@ -49,11 +58,22 @@ export enum TaskType {
49
58
  WARP = 6,
50
59
  CRAFT = 7,
51
60
  DEPLOY = 8,
52
- WRAP = 9,
61
+ TRANSIT = 9,
53
62
  UNWRAP = 10,
54
63
  UNDEPLOY = 11,
55
- WRAP_ENTITY = 12,
56
64
  DEMOLISH = 13,
65
+ CLAIMPLOT = 14,
66
+ BUILDPLOT = 15,
67
+ CHARGE = 16,
68
+ UPGRADE = 17,
69
+ }
70
+
71
+ export enum HoldKind {
72
+ PULL = 1,
73
+ PUSH = 2,
74
+ GATHER = 3,
75
+ BUILD = 4,
76
+ UPGRADE = 6,
57
77
  }
58
78
 
59
79
  export enum LocationType {
@@ -61,6 +81,7 @@ export enum LocationType {
61
81
  PLANET = 1,
62
82
  ASTEROID = 2,
63
83
  NEBULA = 3,
84
+ ICE_FIELD = 4,
64
85
  }
65
86
 
66
87
  export enum TaskCancelable {
@@ -69,14 +90,6 @@ export enum TaskCancelable {
69
90
  ALWAYS = 2,
70
91
  }
71
92
 
72
- export const EntityType = {
73
- SHIP: Name.from('ship'),
74
- WAREHOUSE: Name.from('warehouse'),
75
- CONTAINER: Name.from('container'),
76
- } as const
77
-
78
- export type EntityTypeName = (typeof EntityType)[keyof typeof EntityType]
79
-
80
93
  export type CoordinatesType =
81
94
  | Coordinates
82
95
  | ServerContract.Types.coordinates
@@ -125,8 +138,10 @@ export type ModuleType =
125
138
  | 'launcher'
126
139
  | 'storage'
127
140
  | 'hauler'
141
+ | 'battery'
142
+ | 'catcher'
128
143
 
129
- export const TIER_ADJECTIVES: Record<number, string> = {
144
+ export const RESOURCE_TIER_ADJECTIVES: Record<number, string> = {
130
145
  1: 'Crude',
131
146
  2: 'Dense',
132
147
  3: 'Pure',
@@ -139,6 +154,9 @@ export const TIER_ADJECTIVES: Record<number, string> = {
139
154
  10: 'Ascendant',
140
155
  }
141
156
 
157
+ export const COMPONENT_TIER_PREFIXES: Record<number, string> = {}
158
+ export const MODULE_TIER_PREFIXES: Record<number, string> = {}
159
+
142
160
  export const CATEGORY_LABELS: Record<ResourceCategory, string> = {
143
161
  ore: 'Ore',
144
162
  crystal: 'Crystal',
@@ -162,3 +180,7 @@ export interface Item {
162
180
  export function formatTier(tier: number): string {
163
181
  return 'T' + tier
164
182
  }
183
+
184
+ export function tierAdjective(tier: number): string {
185
+ return RESOURCE_TIER_ADJECTIVES[tier] ?? `T${tier}`
186
+ }
@@ -0,0 +1,14 @@
1
+ import {describe, expect, test} from 'bun:test'
2
+ import {cargoRef} from './cargo'
3
+
4
+ describe('cargoRef', () => {
5
+ test('forwards entity_id when provided', () => {
6
+ const ref = cargoRef({item_id: 10201, stats: 196849n, modules: [], entity_id: 42n})
7
+ expect(ref.entity_id).toBe(42n)
8
+ })
9
+
10
+ test('omits entity_id when absent', () => {
11
+ const ref = cargoRef({item_id: 10201, stats: 196849n})
12
+ expect(ref.entity_id).toBeUndefined()
13
+ })
14
+ })
@@ -0,0 +1,29 @@
1
+ import type {ServerContract} from '../contracts'
2
+
3
+ export function cargoRef(src: {
4
+ item_id: number
5
+ stats: bigint | number
6
+ modules?: ServerContract.Types.module_entry[]
7
+ entity_id?: bigint | number
8
+ }): ServerContract.ActionParams.Type.cargo_ref {
9
+ return {
10
+ item_id: src.item_id,
11
+ stats: src.stats,
12
+ modules: src.modules ?? [],
13
+ entity_id: src.entity_id,
14
+ }
15
+ }
16
+
17
+ export function cargoItem(
18
+ src: {
19
+ item_id: number
20
+ stats: bigint | number
21
+ modules?: ServerContract.Types.module_entry[]
22
+ },
23
+ quantity: bigint | number
24
+ ): ServerContract.ActionParams.Type.cargo_item {
25
+ return {
26
+ ...cargoRef(src),
27
+ quantity,
28
+ }
29
+ }