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

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 (145) 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 +3167 -1353
  7. package/lib/shipload.js +13319 -5640
  8. package/lib/shipload.js.map +1 -1
  9. package/lib/shipload.m.js +13091 -5589
  10. package/lib/shipload.m.js.map +1 -1
  11. package/lib/testing.d.ts +1037 -0
  12. package/lib/testing.js +4363 -0
  13. package/lib/testing.js.map +1 -0
  14. package/lib/testing.m.js +4357 -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 +1178 -511
  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 +294 -34
  75. package/src/managers/actions.ts +616 -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/route-simulator.ts +174 -0
  131. package/src/travel/travel.ts +175 -118
  132. package/src/types/capabilities.ts +29 -6
  133. package/src/types/entity.ts +3 -3
  134. package/src/types/index.ts +0 -1
  135. package/src/types.ts +39 -14
  136. package/src/utils/cargo.test.ts +14 -0
  137. package/src/utils/cargo.ts +29 -0
  138. package/src/utils/display-name.ts +70 -0
  139. package/src/utils/system.ts +36 -24
  140. package/src/capabilities/loading.ts +0 -8
  141. package/src/entities/container.ts +0 -123
  142. package/src/entities/ship-deploy.ts +0 -295
  143. package/src/entities/ship.ts +0 -221
  144. package/src/entities/warehouse.ts +0 -127
  145. package/src/types/entity-traits.ts +0 -69
@@ -23,17 +23,29 @@ import {
23
23
 
24
24
  import type {ServerContract} from '../contracts'
25
25
  import {
26
+ BASE_HAUL_PENALTY_MILLI,
26
27
  BASE_ORBITAL_MASS,
27
28
  type CargoMassInfo,
28
29
  type Distance,
30
+ HAULER_EFFICIENCY_DENOM,
29
31
  MAX_ORBITAL_ALTITUDE,
30
32
  MIN_ORBITAL_ALTITUDE,
33
+ MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL,
34
+ MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE,
31
35
  PRECISION,
32
36
  type ShipLike,
33
37
  TaskType,
34
38
  } from '../types'
39
+ import {EntityClass} from '../data/kind-registry'
35
40
  import {getItem} from '../data/catalog'
36
41
  import {hasSystem} from '../utils/system'
42
+ import {WH} from '../derivation/wormhole'
43
+ import * as scheduleModel from '../scheduling/schedule'
44
+ import type {ScheduleData} from '../scheduling/schedule'
45
+
46
+ function isPositionalTask(task: ServerContract.Types.task): boolean {
47
+ return task.type.equals(TaskType.TRAVEL) || task.type.equals(TaskType.TRANSIT)
48
+ }
37
49
 
38
50
  export function calc_orbital_altitude(mass: number): number {
39
51
  if (mass <= BASE_ORBITAL_MASS) {
@@ -111,15 +123,16 @@ export function getInterpolatedPosition(
111
123
  taskIndex: number,
112
124
  taskProgress: number
113
125
  ): FloatPosition {
114
- if (!entity.schedule || entity.schedule.tasks.length === 0) {
126
+ const tasks = mobilityTasks(entity)
127
+ if (tasks.length === 0) {
115
128
  return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
116
129
  }
117
130
  if (taskIndex < 0) {
118
- const settled = getFlightOrigin(entity, entity.schedule.tasks.length)
131
+ const settled = getFlightOrigin(entity, tasks.length)
119
132
  return {x: Number(settled.x), y: Number(settled.y)}
120
133
  }
121
- const task = entity.schedule.tasks[taskIndex]
122
- if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
134
+ const task = tasks[taskIndex]
135
+ if (!isPositionalTask(task) || !task.coordinates) {
123
136
  const origin = getFlightOrigin(entity, taskIndex)
124
137
  return {x: Number(origin.x), y: Number(origin.y)}
125
138
  }
@@ -176,7 +189,8 @@ export function calc_rechargetime(
176
189
  const cap = UInt32.from(capacity)
177
190
  const eng = UInt32.from(energy)
178
191
  if (eng.gte(cap)) return UInt32.zero
179
- return cap.subtracting(eng).dividing(recharge)
192
+ const ticks = cap.subtracting(eng).dividing(recharge)
193
+ return ticks.equals(UInt32.zero) ? UInt32.from(1) : ticks
180
194
  }
181
195
 
182
196
  export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
@@ -192,15 +206,31 @@ export function calc_flighttime(distance: UInt64Type, acceleration: number): UIn
192
206
  return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
193
207
  }
194
208
 
209
+ export function calc_transit_duration(ax: number, ay: number, bx: number, by: number): UInt32 {
210
+ const distance = distanceBetweenPoints(ax, ay, bx, by)
211
+ return UInt32.from(Math.floor(distance.toNumber() / (PRECISION * WH.TRANSIT_SPEED)))
212
+ }
213
+
214
+ // The active entity's chosen loader lane (lowest slot), mirroring cargo.cpp lane selection.
215
+ export function shipLoaderLane(ship: ShipLike): {thrust: number; mass: number} | undefined {
216
+ const lanes = ship.loader_lanes ?? []
217
+ if (lanes.length === 0) return undefined
218
+ let lowest = lanes[0]
219
+ for (const lane of lanes) {
220
+ if (Number(lane.slot_index) < Number(lowest.slot_index)) lowest = lane
221
+ }
222
+ return {thrust: Number(lowest.thrust), mass: Number(lowest.mass)}
223
+ }
224
+
195
225
  export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?: number): UInt32 {
196
226
  const z = altitude ?? ship.coordinates.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
197
227
  return calc_flighttime(z, calc_loader_acceleration(ship, mass))
198
228
  }
199
229
 
200
230
  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)
231
+ const lane = shipLoaderLane(ship)
232
+ const thrust = lane ? lane.thrust : 0
233
+ return calc_acceleration(thrust, Number(mass))
204
234
  }
205
235
 
206
236
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -222,8 +252,10 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
222
252
 
223
253
  mass.add(ship.hullmass)
224
254
 
225
- if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
226
- mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
255
+ if (ship.loader_lanes && ship.loader_lanes.length > 0) {
256
+ for (const l of ship.loader_lanes) {
257
+ mass.add(UInt64.from(l.mass))
258
+ }
227
259
  }
228
260
 
229
261
  for (const cargo of cargos) {
@@ -234,6 +266,29 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
234
266
  return mass
235
267
  }
236
268
 
269
+ export function calc_group_flighttime(
270
+ totalThrust: number,
271
+ haulCount: number,
272
+ pooledHaulCap: number,
273
+ weightedHaulEffNum: number,
274
+ totalMass: number,
275
+ distance: UInt64Type
276
+ ): UInt32 {
277
+ const avgHaulEff = pooledHaulCap > 0 ? Math.trunc(weightedHaulEffNum / pooledHaulCap) : 0
278
+ let effectiveThrust = totalThrust
279
+ if (haulCount > 0) {
280
+ const penaltyMilli =
281
+ 1000 +
282
+ Math.trunc(
283
+ (haulCount * BASE_HAUL_PENALTY_MILLI * (HAULER_EFFICIENCY_DENOM - avgHaulEff)) /
284
+ HAULER_EFFICIENCY_DENOM
285
+ )
286
+ effectiveThrust = Math.trunc((totalThrust * 1000) / penaltyMilli)
287
+ }
288
+ const acceleration = calc_acceleration(effectiveThrust, totalMass)
289
+ return calc_flighttime(distance, acceleration)
290
+ }
291
+
237
292
  export function calc_energyusage(distance: UInt64Type, drain: UInt32Type): UInt32 {
238
293
  return UInt64.from(distance).dividing(PRECISION).multiplying(drain)
239
294
  }
@@ -258,10 +313,10 @@ export function calculateTransferTime(
258
313
  return UInt32.from(0)
259
314
  }
260
315
 
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)
316
+ const lane = shipLoaderLane(ship)
317
+ if (!lane) return UInt32.from(0)
318
+ mass = UInt64.from(mass).adding(UInt64.from(lane.mass))
319
+ return calc_loader_flighttime(ship, mass)
265
320
  }
266
321
 
267
322
  export function calculateRefuelingTime(ship: ShipLike): UInt32 {
@@ -316,25 +371,22 @@ export function calculateLoadTimeBreakdown(
316
371
  let unloadTime = 0
317
372
  let loadTime = 0
318
373
 
319
- if (mass_unload.gt(UInt64.zero) && ship.loaders) {
320
- const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
374
+ const lane = shipLoaderLane(ship)
375
+
376
+ if (mass_unload.gt(UInt64.zero) && lane) {
377
+ const totalMass = UInt64.from(mass_unload).adding(UInt64.from(lane.mass))
321
378
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
322
379
  }
323
380
 
324
- if (mass_load.gt(UInt64.zero) && ship.loaders) {
325
- const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
381
+ if (mass_load.gt(UInt64.zero) && lane) {
382
+ const totalMass = UInt64.from(mass_load).adding(UInt64.from(lane.mass))
326
383
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
327
384
  }
328
385
 
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
386
  return {
335
- unloadTime: unloadTimePerLoader,
336
- loadTime: loadTimePerLoader,
337
- totalTime,
387
+ unloadTime,
388
+ loadTime,
389
+ totalTime: unloadTime + loadTime,
338
390
  unloadMass: Number(mass_unload),
339
391
  loadMass: Number(mass_load),
340
392
  }
@@ -368,24 +420,16 @@ export function estimateTravelTime(
368
420
  let loadTime = UInt32.zero
369
421
  let unloadTime = UInt32.zero
370
422
 
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)
423
+ const lane = shipLoaderLane(ship)
424
+
425
+ if (loadMass && UInt32.from(loadMass).gt(UInt32.zero) && lane) {
426
+ const totalMass = UInt64.from(loadMass).adding(UInt64.from(lane.mass))
427
+ loadTime = calc_loader_flighttime(ship, totalMass)
379
428
  }
380
429
 
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)
430
+ if (unloadMass && UInt32.from(unloadMass).gt(UInt32.zero) && lane) {
431
+ const totalMass = UInt64.from(unloadMass).adding(UInt64.from(lane.mass))
432
+ unloadTime = calc_loader_flighttime(ship, totalMass)
389
433
  }
390
434
 
391
435
  return {
@@ -417,30 +461,51 @@ export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): bool
417
461
  return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
418
462
  }
419
463
 
464
+ export interface TransferLoaderLane {
465
+ slot_index?: {toNumber(): number} | number
466
+ thrust: {toNumber(): number} | number
467
+ mass: {toNumber(): number} | number
468
+ }
469
+
420
470
  export interface TransferEntity {
421
471
  location: {z?: {toNumber(): number} | number}
422
- loaders?: {
423
- thrust: {toNumber(): number} | number
424
- mass: {toNumber(): number} | number
425
- quantity: {toNumber(): number} | number
472
+ entityClass: EntityClass
473
+ loaderLanes?: TransferLoaderLane[]
474
+ }
475
+
476
+ function toNum(v: {toNumber(): number} | number | undefined): number {
477
+ if (v === undefined) return 0
478
+ return typeof v === 'number' ? v : v.toNumber()
479
+ }
480
+
481
+ // Mirrors cargo.cpp worker_lane_key_or_mobility: lowest-slot loader lane (display has no busy context).
482
+ function chosenLoaderLane(entity: TransferEntity): TransferLoaderLane | undefined {
483
+ const lanes = entity.loaderLanes ?? []
484
+ if (lanes.length === 0) return undefined
485
+ let lowest = lanes[0]
486
+ for (const lane of lanes) {
487
+ if (toNum(lane.slot_index) < toNum(lowest.slot_index)) lowest = lane
426
488
  }
489
+ return lowest
427
490
  }
428
491
 
429
- export interface HasScheduleAndLocation {
492
+ export interface HasScheduleAndLocation extends ScheduleData {
430
493
  coordinates: ServerContract.ActionParams.Type.coordinates
431
- schedule?: ServerContract.Types.schedule
494
+ }
495
+
496
+ function mobilityTasks(entity: HasScheduleAndLocation): ServerContract.Types.task[] {
497
+ return scheduleModel.mobilityLane(entity)?.schedule.tasks ?? []
432
498
  }
433
499
 
434
500
  export function getFlightOrigin(
435
501
  entity: HasScheduleAndLocation,
436
502
  flightTaskIndex: number
437
503
  ): ServerContract.ActionParams.Type.coordinates {
438
- if (!entity.schedule) return entity.coordinates
439
-
504
+ const tasks = mobilityTasks(entity)
440
505
  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) {
506
+ for (let i = 0; i < flightTaskIndex && i < tasks.length; i++) {
507
+ const task = tasks[i]
508
+ if (isPositionalTask(task) && task.coordinates) {
444
509
  origin = task.coordinates
445
510
  }
446
511
  }
@@ -450,11 +515,10 @@ export function getFlightOrigin(
450
515
  export function getDestinationLocation(
451
516
  entity: HasScheduleAndLocation
452
517
  ): 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) {
518
+ const tasks = mobilityTasks(entity)
519
+ for (let i = tasks.length - 1; i >= 0; i--) {
520
+ const task = tasks[i]
521
+ if (isPositionalTask(task) && task.coordinates) {
458
522
  return task.coordinates
459
523
  }
460
524
  }
@@ -467,16 +531,17 @@ export function getPositionAt(
467
531
  taskIndex: number,
468
532
  taskProgress: number
469
533
  ): ServerContract.ActionParams.Type.coordinates {
470
- if (!entity.schedule || entity.schedule.tasks.length === 0) {
534
+ const tasks = mobilityTasks(entity)
535
+ if (tasks.length === 0) {
471
536
  return entity.coordinates
472
537
  }
473
538
  if (taskIndex < 0) {
474
- return getFlightOrigin(entity, entity.schedule.tasks.length)
539
+ return getFlightOrigin(entity, tasks.length)
475
540
  }
476
541
 
477
- const task = entity.schedule.tasks[taskIndex]
542
+ const task = tasks[taskIndex]
478
543
 
479
- if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
544
+ if (!isPositionalTask(task) || !task.coordinates) {
480
545
  return getFlightOrigin(entity, taskIndex)
481
546
  }
482
547
 
@@ -490,68 +555,60 @@ export function getPositionAt(
490
555
  }
491
556
  }
492
557
 
493
- export function calc_transfer_duration(
494
- source: TransferEntity,
495
- dest: TransferEntity,
558
+ export function minTransferDistance(entityClass: EntityClass): number {
559
+ return entityClass === EntityClass.OrbitalVessel
560
+ ? MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL
561
+ : MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE
562
+ }
563
+
564
+ // Mirrors cargo.cpp calc_onesided_duration: single active loader's thrust + mass, no ÷quantity.
565
+ export function calc_onesided_duration(
566
+ loaderThrust: number,
567
+ loaderMass: number,
568
+ activeZ: number,
569
+ counterpartZ: number,
570
+ activeEntityClass: EntityClass,
571
+ counterpartEntityClass: EntityClass,
496
572
  cargoMass: number
497
573
  ): number {
498
- if (cargoMass === 0) {
574
+ if (cargoMass === 0 || loaderThrust === 0) {
499
575
  return 0
500
576
  }
577
+ const rawDistance = Math.abs(activeZ - counterpartZ)
578
+ const minDistance = Math.max(
579
+ minTransferDistance(activeEntityClass),
580
+ minTransferDistance(counterpartEntityClass)
581
+ )
582
+ const distance = rawDistance < minDistance ? minDistance : rawDistance
583
+ const totalMass = cargoMass + loaderMass
584
+ const acceleration = calc_acceleration(loaderThrust, totalMass)
585
+ const flightTime = Math.floor(2 * Math.sqrt(distance / acceleration))
586
+ return flightTime === 0 ? 1 : flightTime
587
+ }
501
588
 
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) {
589
+ // Mirrors cargo.cpp: the active (loader-bearing) entity's chosen loader lane drives the duration.
590
+ export function calc_transfer_duration(
591
+ source: TransferEntity,
592
+ dest: TransferEntity,
593
+ cargoMass: number
594
+ ): number {
595
+ const active = chosenLoaderLane(source) ? source : dest
596
+ const counterpart = active === source ? dest : source
597
+ const lane = chosenLoaderLane(active)
598
+ if (!lane) {
541
599
  return 0
542
600
  }
543
601
 
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)
602
+ const activeZ = toNum(active.location.z)
603
+ const counterpartZ = toNum(counterpart.location.z)
604
+
605
+ return calc_onesided_duration(
606
+ toNum(lane.thrust),
607
+ toNum(lane.mass),
608
+ activeZ,
609
+ counterpartZ,
610
+ active.entityClass,
611
+ counterpart.entityClass,
612
+ cargoMass
613
+ )
557
614
  }
@@ -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,35 +1,47 @@
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
 
19
19
  export const TRAVEL_MAX_DURATION = 86400
20
20
 
21
+ export const BASE_HAUL_PENALTY_MILLI = 300
22
+ export const HAULER_EFFICIENCY_DENOM = 10000
23
+
21
24
  export const MIN_ORBITAL_ALTITUDE = 800
22
25
  export const MAX_ORBITAL_ALTITUDE = 3000
23
26
 
24
27
  export const BASE_ORBITAL_MASS = 100000
25
28
 
29
+ export const MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE = 100
30
+ export const MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL = 200
31
+
32
+ export interface ClusterSlotType {
33
+ hub: UInt64Type
34
+ gx: number
35
+ gy: number
36
+ }
37
+
26
38
  export interface ShipLike {
27
39
  coordinates: ServerContract.Types.coordinates
28
40
  hullmass?: UInt32
29
41
  energy?: UInt16
30
42
  engines?: ServerContract.Types.movement_stats
31
43
  generator?: ServerContract.Types.energy_stats
32
- loaders?: ServerContract.Types.loader_stats
44
+ loader_lanes?: ServerContract.Types.loader_lane[]
33
45
  hauler?: ServerContract.Types.hauler_stats
34
46
  capacity?: UInt32
35
47
  }
@@ -49,11 +61,22 @@ export enum TaskType {
49
61
  WARP = 6,
50
62
  CRAFT = 7,
51
63
  DEPLOY = 8,
52
- WRAP = 9,
64
+ TRANSIT = 9,
53
65
  UNWRAP = 10,
54
66
  UNDEPLOY = 11,
55
- WRAP_ENTITY = 12,
56
67
  DEMOLISH = 13,
68
+ CLAIMPLOT = 14,
69
+ BUILDPLOT = 15,
70
+ CHARGE = 16,
71
+ UPGRADE = 17,
72
+ }
73
+
74
+ export enum HoldKind {
75
+ PULL = 1,
76
+ PUSH = 2,
77
+ GATHER = 3,
78
+ BUILD = 4,
79
+ UPGRADE = 6,
57
80
  }
58
81
 
59
82
  export enum LocationType {
@@ -61,6 +84,7 @@ export enum LocationType {
61
84
  PLANET = 1,
62
85
  ASTEROID = 2,
63
86
  NEBULA = 3,
87
+ ICE_FIELD = 4,
64
88
  }
65
89
 
66
90
  export enum TaskCancelable {
@@ -69,14 +93,6 @@ export enum TaskCancelable {
69
93
  ALWAYS = 2,
70
94
  }
71
95
 
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
96
  export type CoordinatesType =
81
97
  | Coordinates
82
98
  | ServerContract.Types.coordinates
@@ -125,8 +141,10 @@ export type ModuleType =
125
141
  | 'launcher'
126
142
  | 'storage'
127
143
  | 'hauler'
144
+ | 'battery'
145
+ | 'catcher'
128
146
 
129
- export const TIER_ADJECTIVES: Record<number, string> = {
147
+ export const RESOURCE_TIER_ADJECTIVES: Record<number, string> = {
130
148
  1: 'Crude',
131
149
  2: 'Dense',
132
150
  3: 'Pure',
@@ -139,6 +157,9 @@ export const TIER_ADJECTIVES: Record<number, string> = {
139
157
  10: 'Ascendant',
140
158
  }
141
159
 
160
+ export const COMPONENT_TIER_PREFIXES: Record<number, string> = {}
161
+ export const MODULE_TIER_PREFIXES: Record<number, string> = {}
162
+
142
163
  export const CATEGORY_LABELS: Record<ResourceCategory, string> = {
143
164
  ore: 'Ore',
144
165
  crystal: 'Crystal',
@@ -162,3 +183,7 @@ export interface Item {
162
183
  export function formatTier(tier: number): string {
163
184
  return 'T' + tier
164
185
  }
186
+
187
+ export function tierAdjective(tier: number): string {
188
+ return RESOURCE_TIER_ADJECTIVES[tier] ?? `T${tier}`
189
+ }
@@ -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
+ })