@shipload/sdk 1.0.0-next.4 → 1.0.0-next.40

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 (127) hide show
  1. package/lib/shipload.d.ts +2473 -973
  2. package/lib/shipload.js +11529 -5211
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +11338 -5162
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +970 -0
  7. package/lib/testing.js +4013 -0
  8. package/lib/testing.js.map +1 -0
  9. package/lib/testing.m.js +4007 -0
  10. package/lib/testing.m.js.map +1 -0
  11. package/package.json +15 -2
  12. package/src/capabilities/craftable.ts +51 -0
  13. package/src/capabilities/crafting.test.ts +7 -0
  14. package/src/capabilities/crafting.ts +5 -6
  15. package/src/capabilities/gathering.test.ts +16 -0
  16. package/src/capabilities/gathering.ts +35 -18
  17. package/src/capabilities/index.ts +0 -1
  18. package/src/capabilities/modules.ts +9 -0
  19. package/src/capabilities/storage.ts +16 -1
  20. package/src/contracts/platform.ts +231 -3
  21. package/src/contracts/server.ts +1021 -481
  22. package/src/coordinates/address.ts +88 -0
  23. package/src/coordinates/constants.test.ts +15 -0
  24. package/src/coordinates/constants.ts +23 -0
  25. package/src/coordinates/index.ts +15 -0
  26. package/src/coordinates/memo.test.ts +47 -0
  27. package/src/coordinates/memo.ts +20 -0
  28. package/src/coordinates/permutation.ts +77 -0
  29. package/src/coordinates/regions.ts +48 -0
  30. package/src/coordinates/sectors.ts +115 -0
  31. package/src/data/capabilities.ts +12 -5
  32. package/src/data/capability-formulas.ts +14 -7
  33. package/src/data/catalog.ts +0 -5
  34. package/src/data/colors.ts +14 -47
  35. package/src/data/entities.json +76 -10
  36. package/src/data/item-ids.ts +18 -12
  37. package/src/data/items.json +321 -38
  38. package/src/data/kind-registry.json +109 -0
  39. package/src/data/kind-registry.ts +165 -0
  40. package/src/data/metadata.ts +119 -33
  41. package/src/data/recipes-runtime.ts +3 -23
  42. package/src/data/recipes.json +238 -117
  43. package/src/derivation/build-methods.ts +45 -0
  44. package/src/derivation/capabilities.test.ts +151 -0
  45. package/src/derivation/capabilities.ts +512 -0
  46. package/src/derivation/capability-mappings.ts +9 -12
  47. package/src/derivation/crafting.ts +23 -24
  48. package/src/derivation/index.ts +25 -2
  49. package/src/derivation/recipe-usage.test.ts +78 -0
  50. package/src/derivation/recipe-usage.ts +141 -0
  51. package/src/derivation/reserve-regen.ts +34 -0
  52. package/src/derivation/resources.ts +125 -38
  53. package/src/derivation/rollups.test.ts +55 -0
  54. package/src/derivation/rollups.ts +56 -0
  55. package/src/derivation/stars.test.ts +51 -0
  56. package/src/derivation/stars.ts +15 -0
  57. package/src/derivation/stats.ts +6 -6
  58. package/src/derivation/stratum.ts +17 -20
  59. package/src/derivation/tiers.ts +40 -7
  60. package/src/derivation/wormhole.ts +136 -0
  61. package/src/entities/entity.ts +98 -0
  62. package/src/entities/gamestate.ts +3 -28
  63. package/src/entities/makers.ts +124 -134
  64. package/src/entities/slot-multiplier.ts +43 -0
  65. package/src/errors.ts +12 -16
  66. package/src/format.ts +26 -4
  67. package/src/index-module.ts +267 -47
  68. package/src/managers/actions.ts +528 -95
  69. package/src/managers/base.ts +6 -2
  70. package/src/managers/construction-types.ts +80 -0
  71. package/src/managers/construction.ts +412 -0
  72. package/src/managers/context.ts +20 -1
  73. package/src/managers/coordinates.ts +14 -0
  74. package/src/managers/entities.ts +18 -66
  75. package/src/managers/epochs.ts +40 -0
  76. package/src/managers/index.ts +17 -1
  77. package/src/managers/locations.ts +25 -29
  78. package/src/managers/nft.test.ts +14 -0
  79. package/src/managers/nft.ts +70 -0
  80. package/src/managers/plot.ts +122 -0
  81. package/src/nft/atomicassets.abi.json +1342 -0
  82. package/src/nft/atomicassets.ts +237 -0
  83. package/src/nft/atomicdata.ts +130 -0
  84. package/src/nft/buildImmutableData.ts +338 -0
  85. package/src/nft/description.ts +98 -24
  86. package/src/nft/index.ts +3 -0
  87. package/src/planner/index.ts +127 -0
  88. package/src/planner/planner.test.ts +319 -0
  89. package/src/resolution/describe-module.ts +18 -13
  90. package/src/resolution/display-name.ts +38 -10
  91. package/src/resolution/resolve-item.test.ts +37 -0
  92. package/src/resolution/resolve-item.ts +55 -24
  93. package/src/scheduling/accessor.ts +68 -22
  94. package/src/scheduling/availability.ts +108 -0
  95. package/src/scheduling/cancel.test.ts +348 -0
  96. package/src/scheduling/cancel.ts +209 -0
  97. package/src/scheduling/energy.ts +47 -0
  98. package/src/scheduling/idle-resolve.ts +45 -0
  99. package/src/scheduling/lane-core.ts +128 -0
  100. package/src/scheduling/lanes.test.ts +249 -0
  101. package/src/scheduling/lanes.ts +198 -0
  102. package/src/scheduling/projection.ts +209 -105
  103. package/src/scheduling/schedule.ts +241 -104
  104. package/src/scheduling/task-cargo.ts +46 -0
  105. package/src/shipload.ts +21 -1
  106. package/src/subscriptions/manager.ts +229 -142
  107. package/src/subscriptions/mappers.ts +5 -8
  108. package/src/subscriptions/types.ts +11 -3
  109. package/src/testing/catalog-hash.ts +19 -0
  110. package/src/testing/index.ts +2 -0
  111. package/src/testing/projection-parity.ts +167 -0
  112. package/src/travel/reach.ts +23 -0
  113. package/src/travel/route-planner.ts +196 -0
  114. package/src/travel/travel.ts +200 -112
  115. package/src/types/capabilities.ts +29 -6
  116. package/src/types/entity.ts +3 -3
  117. package/src/types/index.ts +0 -1
  118. package/src/types.ts +28 -13
  119. package/src/utils/cargo.ts +27 -0
  120. package/src/utils/display-name.ts +70 -0
  121. package/src/utils/system.ts +36 -24
  122. package/src/capabilities/loading.ts +0 -8
  123. package/src/entities/container.ts +0 -108
  124. package/src/entities/ship-deploy.ts +0 -259
  125. package/src/entities/ship.ts +0 -204
  126. package/src/entities/warehouse.ts +0 -119
  127. 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) {
@@ -77,6 +87,60 @@ export function lerp(
77
87
  }
78
88
  }
79
89
 
90
+ export interface FloatPosition {
91
+ x: number
92
+ y: number
93
+ }
94
+
95
+ export function easeFlightProgress(t: number): number {
96
+ if (t <= 0) return 0
97
+ if (t >= 1) return 1
98
+ return t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)
99
+ }
100
+
101
+ export function flightSpeedFactor(t: number): number {
102
+ if (t <= 0 || t >= 1) return 0
103
+ return t < 0.5 ? 4 * t : 4 * (1 - t)
104
+ }
105
+
106
+ export function interpolateFlightPosition(
107
+ origin: {x: Int64Type | number; y: Int64Type | number},
108
+ destination: {x: Int64Type | number; y: Int64Type | number},
109
+ taskProgress: number,
110
+ options?: {easing?: 'physics' | 'linear'}
111
+ ): FloatPosition {
112
+ const t = options?.easing === 'linear' ? taskProgress : easeFlightProgress(taskProgress)
113
+ return {
114
+ x: (1 - t) * Number(origin.x) + t * Number(destination.x),
115
+ y: (1 - t) * Number(origin.y) + t * Number(destination.y),
116
+ }
117
+ }
118
+
119
+ export function getInterpolatedPosition(
120
+ entity: HasScheduleAndLocation,
121
+ taskIndex: number,
122
+ taskProgress: number
123
+ ): FloatPosition {
124
+ const tasks = mobilityTasks(entity)
125
+ if (tasks.length === 0) {
126
+ return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
127
+ }
128
+ if (taskIndex < 0) {
129
+ const settled = getFlightOrigin(entity, tasks.length)
130
+ return {x: Number(settled.x), y: Number(settled.y)}
131
+ }
132
+ const task = tasks[taskIndex]
133
+ if (!isPositionalTask(task) || !task.coordinates) {
134
+ const origin = getFlightOrigin(entity, taskIndex)
135
+ return {x: Number(origin.x), y: Number(origin.y)}
136
+ }
137
+ return interpolateFlightPosition(
138
+ getFlightOrigin(entity, taskIndex),
139
+ task.coordinates,
140
+ taskProgress
141
+ )
142
+ }
143
+
80
144
  export function rotation(
81
145
  origin: ServerContract.ActionParams.Type.coordinates,
82
146
  destination: ServerContract.ActionParams.Type.coordinates
@@ -139,15 +203,31 @@ export function calc_flighttime(distance: UInt64Type, acceleration: number): UIn
139
203
  return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
140
204
  }
141
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
+
142
222
  export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?: number): UInt32 {
143
223
  const z = altitude ?? ship.coordinates.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
144
224
  return calc_flighttime(z, calc_loader_acceleration(ship, mass))
145
225
  }
146
226
 
147
227
  export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
148
- const thrust = ship.loaders ? Number(ship.loaders.thrust) : 0
149
- const loaderMass = ship.loaders ? Number(ship.loaders.mass) : 0
150
- 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))
151
231
  }
152
232
 
153
233
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -169,8 +249,10 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
169
249
 
170
250
  mass.add(ship.hullmass)
171
251
 
172
- if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
173
- 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
+ }
174
256
  }
175
257
 
176
258
  for (const cargo of cargos) {
@@ -205,10 +287,10 @@ export function calculateTransferTime(
205
287
  return UInt32.from(0)
206
288
  }
207
289
 
208
- if (!ship.loaders) return UInt32.from(0)
209
- mass = UInt64.from(mass).adding(ship.loaders.mass)
210
- const transfer_time = calc_loader_flighttime(ship, mass)
211
- 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)
212
294
  }
213
295
 
214
296
  export function calculateRefuelingTime(ship: ShipLike): UInt32 {
@@ -263,25 +345,22 @@ export function calculateLoadTimeBreakdown(
263
345
  let unloadTime = 0
264
346
  let loadTime = 0
265
347
 
266
- if (mass_unload.gt(UInt64.zero) && ship.loaders) {
267
- 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))
268
352
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
269
353
  }
270
354
 
271
- if (mass_load.gt(UInt64.zero) && ship.loaders) {
272
- 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))
273
357
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
274
358
  }
275
359
 
276
- const numLoaders = ship.loaders ? Number(ship.loaders.quantity) : 0
277
- const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
278
- const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
279
- const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
280
-
281
360
  return {
282
- unloadTime: unloadTimePerLoader,
283
- loadTime: loadTimePerLoader,
284
- totalTime,
361
+ unloadTime,
362
+ loadTime,
363
+ totalTime: unloadTime + loadTime,
285
364
  unloadMass: Number(mass_unload),
286
365
  loadMass: Number(mass_load),
287
366
  }
@@ -315,24 +394,16 @@ export function estimateTravelTime(
315
394
  let loadTime = UInt32.zero
316
395
  let unloadTime = UInt32.zero
317
396
 
318
- if (
319
- loadMass &&
320
- UInt32.from(loadMass).gt(UInt32.zero) &&
321
- ship.loaders &&
322
- ship.loaders.quantity.gt(UInt32.zero)
323
- ) {
324
- const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
325
- 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)
326
402
  }
327
403
 
328
- if (
329
- unloadMass &&
330
- UInt32.from(unloadMass).gt(UInt32.zero) &&
331
- ship.loaders &&
332
- ship.loaders.quantity.gt(UInt32.zero)
333
- ) {
334
- const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
335
- 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)
336
407
  }
337
408
 
338
409
  return {
@@ -364,30 +435,51 @@ export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): bool
364
435
  return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
365
436
  }
366
437
 
438
+ export interface TransferLoaderLane {
439
+ slot_index?: {toNumber(): number} | number
440
+ thrust: {toNumber(): number} | number
441
+ mass: {toNumber(): number} | number
442
+ }
443
+
367
444
  export interface TransferEntity {
368
445
  location: {z?: {toNumber(): number} | number}
369
- loaders?: {
370
- thrust: {toNumber(): number} | number
371
- mass: {toNumber(): number} | number
372
- 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
373
462
  }
463
+ return lowest
374
464
  }
375
465
 
376
- export interface HasScheduleAndLocation {
466
+ export interface HasScheduleAndLocation extends ScheduleData {
377
467
  coordinates: ServerContract.ActionParams.Type.coordinates
378
- schedule?: ServerContract.Types.schedule
468
+ }
469
+
470
+ function mobilityTasks(entity: HasScheduleAndLocation): ServerContract.Types.task[] {
471
+ return scheduleModel.mobilityLane(entity)?.schedule.tasks ?? []
379
472
  }
380
473
 
381
474
  export function getFlightOrigin(
382
475
  entity: HasScheduleAndLocation,
383
476
  flightTaskIndex: number
384
477
  ): ServerContract.ActionParams.Type.coordinates {
385
- if (!entity.schedule) return entity.coordinates
386
-
478
+ const tasks = mobilityTasks(entity)
387
479
  let origin = entity.coordinates
388
- for (let i = 0; i < flightTaskIndex && i < entity.schedule.tasks.length; i++) {
389
- const task = entity.schedule.tasks[i]
390
- 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) {
391
483
  origin = task.coordinates
392
484
  }
393
485
  }
@@ -397,29 +489,33 @@ export function getFlightOrigin(
397
489
  export function getDestinationLocation(
398
490
  entity: HasScheduleAndLocation
399
491
  ): ServerContract.ActionParams.Type.coordinates | undefined {
400
- if (!entity.schedule) return undefined
401
-
402
- for (let i = entity.schedule.tasks.length - 1; i >= 0; i--) {
403
- const task = entity.schedule.tasks[i]
404
- 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) {
405
496
  return task.coordinates
406
497
  }
407
498
  }
408
499
  return undefined
409
500
  }
410
501
 
502
+ /** Returns chain-tile coordinates (rounded). For visual position use getInterpolatedPosition. */
411
503
  export function getPositionAt(
412
504
  entity: HasScheduleAndLocation,
413
505
  taskIndex: number,
414
506
  taskProgress: number
415
507
  ): ServerContract.ActionParams.Type.coordinates {
416
- if (!entity.schedule || entity.schedule.tasks.length === 0 || taskIndex < 0) {
508
+ const tasks = mobilityTasks(entity)
509
+ if (tasks.length === 0) {
417
510
  return entity.coordinates
418
511
  }
512
+ if (taskIndex < 0) {
513
+ return getFlightOrigin(entity, tasks.length)
514
+ }
419
515
 
420
- const task = entity.schedule.tasks[taskIndex]
516
+ const task = tasks[taskIndex]
421
517
 
422
- if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
518
+ if (!isPositionalTask(task) || !task.coordinates) {
423
519
  return getFlightOrigin(entity, taskIndex)
424
520
  }
425
521
 
@@ -433,68 +529,60 @@ export function getPositionAt(
433
529
  }
434
530
  }
435
531
 
436
- export function calc_transfer_duration(
437
- source: TransferEntity,
438
- 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,
439
546
  cargoMass: number
440
547
  ): number {
441
- if (cargoMass === 0) {
548
+ if (cargoMass === 0 || loaderThrust === 0) {
442
549
  return 0
443
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
+ }
444
562
 
445
- let totalThrust = 0
446
- let totalLoaderMass = 0
447
- let totalQuantity = 0
448
-
449
- if (source.loaders) {
450
- const thrust =
451
- typeof source.loaders.thrust === 'number'
452
- ? source.loaders.thrust
453
- : source.loaders.thrust.toNumber()
454
- const mass =
455
- typeof source.loaders.mass === 'number'
456
- ? source.loaders.mass
457
- : source.loaders.mass.toNumber()
458
- const qty =
459
- typeof source.loaders.quantity === 'number'
460
- ? source.loaders.quantity
461
- : source.loaders.quantity.toNumber()
462
- totalThrust += thrust * qty
463
- totalLoaderMass += mass * qty
464
- totalQuantity += qty
465
- }
466
-
467
- if (dest.loaders) {
468
- const thrust =
469
- typeof dest.loaders.thrust === 'number'
470
- ? dest.loaders.thrust
471
- : dest.loaders.thrust.toNumber()
472
- const mass =
473
- typeof dest.loaders.mass === 'number' ? dest.loaders.mass : dest.loaders.mass.toNumber()
474
- const qty =
475
- typeof dest.loaders.quantity === 'number'
476
- ? dest.loaders.quantity
477
- : dest.loaders.quantity.toNumber()
478
- totalThrust += thrust * qty
479
- totalLoaderMass += mass * qty
480
- totalQuantity += qty
481
- }
482
-
483
- 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) {
484
573
  return 0
485
574
  }
486
575
 
487
- const sourceZ =
488
- typeof source.location.z === 'number'
489
- ? source.location.z
490
- : (source.location.z?.toNumber() ?? 0)
491
- const destZ =
492
- typeof dest.location.z === 'number' ? dest.location.z : (dest.location.z?.toNumber() ?? 0)
493
- const distance = Math.abs(sourceZ - destZ)
494
-
495
- const totalMass = cargoMass + totalLoaderMass
496
- const acceleration = calc_acceleration(totalThrust, totalMass)
497
- const flightTime = 2 * Math.sqrt(distance / acceleration)
498
-
499
- 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
+ )
500
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,6 +1,5 @@
1
1
  import {
2
2
  type Int64Type,
3
- Name,
4
3
  type UInt16,
5
4
  type UInt16Type,
6
5
  type UInt32,
@@ -12,7 +11,7 @@ import {ServerContract} from './contracts'
12
11
  export const PRECISION = 10000
13
12
  export const CRAFT_ENERGY_DIVISOR = 150000
14
13
 
15
- export const WAREHOUSE_Z = 500
14
+ export const PLANETARY_STRUCTURE_Z = 0
16
15
 
17
16
  export const CONTAINER_Z = 300
18
17
 
@@ -23,13 +22,16 @@ export const MAX_ORBITAL_ALTITUDE = 3000
23
22
 
24
23
  export const BASE_ORBITAL_MASS = 100000
25
24
 
25
+ export const MIN_TRANSFER_DISTANCE_PLANETARY_STRUCTURE = 100
26
+ export const MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL = 200
27
+
26
28
  export interface ShipLike {
27
29
  coordinates: ServerContract.Types.coordinates
28
30
  hullmass?: UInt32
29
31
  energy?: UInt16
30
32
  engines?: ServerContract.Types.movement_stats
31
33
  generator?: ServerContract.Types.energy_stats
32
- loaders?: ServerContract.Types.loader_stats
34
+ loader_lanes?: ServerContract.Types.loader_lane[]
33
35
  hauler?: ServerContract.Types.hauler_stats
34
36
  capacity?: UInt32
35
37
  }
@@ -49,8 +51,19 @@ export enum TaskType {
49
51
  WARP = 6,
50
52
  CRAFT = 7,
51
53
  DEPLOY = 8,
52
- WRAP = 9,
54
+ TRANSIT = 9,
53
55
  UNWRAP = 10,
56
+ UNDEPLOY = 11,
57
+ DEMOLISH = 13,
58
+ CLAIMPLOT = 14,
59
+ BUILDPLOT = 15,
60
+ }
61
+
62
+ export enum HoldKind {
63
+ PULL = 1,
64
+ PUSH = 2,
65
+ GATHER = 3,
66
+ BUILD = 4,
54
67
  }
55
68
 
56
69
  export enum LocationType {
@@ -58,6 +71,7 @@ export enum LocationType {
58
71
  PLANET = 1,
59
72
  ASTEROID = 2,
60
73
  NEBULA = 3,
74
+ ICE_FIELD = 4,
61
75
  }
62
76
 
63
77
  export enum TaskCancelable {
@@ -66,14 +80,6 @@ export enum TaskCancelable {
66
80
  ALWAYS = 2,
67
81
  }
68
82
 
69
- export const EntityType = {
70
- SHIP: Name.from('ship'),
71
- WAREHOUSE: Name.from('warehouse'),
72
- CONTAINER: Name.from('container'),
73
- } as const
74
-
75
- export type EntityTypeName = (typeof EntityType)[keyof typeof EntityType]
76
-
77
83
  export type CoordinatesType =
78
84
  | Coordinates
79
85
  | ServerContract.Types.coordinates
@@ -122,8 +128,10 @@ export type ModuleType =
122
128
  | 'launcher'
123
129
  | 'storage'
124
130
  | 'hauler'
131
+ | 'battery'
132
+ | 'catcher'
125
133
 
126
- export const TIER_ADJECTIVES: Record<number, string> = {
134
+ export const RESOURCE_TIER_ADJECTIVES: Record<number, string> = {
127
135
  1: 'Crude',
128
136
  2: 'Dense',
129
137
  3: 'Pure',
@@ -136,6 +144,9 @@ export const TIER_ADJECTIVES: Record<number, string> = {
136
144
  10: 'Ascendant',
137
145
  }
138
146
 
147
+ export const COMPONENT_TIER_PREFIXES: Record<number, string> = {}
148
+ export const MODULE_TIER_PREFIXES: Record<number, string> = {}
149
+
139
150
  export const CATEGORY_LABELS: Record<ResourceCategory, string> = {
140
151
  ore: 'Ore',
141
152
  crystal: 'Crystal',
@@ -159,3 +170,7 @@ export interface Item {
159
170
  export function formatTier(tier: number): string {
160
171
  return 'T' + tier
161
172
  }
173
+
174
+ export function tierAdjective(tier: number): string {
175
+ return RESOURCE_TIER_ADJECTIVES[tier] ?? `T${tier}`
176
+ }
@@ -0,0 +1,27 @@
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
+ }): ServerContract.ActionParams.Type.cargo_ref {
8
+ return {
9
+ item_id: src.item_id,
10
+ stats: src.stats,
11
+ modules: src.modules ?? [],
12
+ }
13
+ }
14
+
15
+ export function cargoItem(
16
+ src: {
17
+ item_id: number
18
+ stats: bigint | number
19
+ modules?: ServerContract.Types.module_entry[]
20
+ },
21
+ quantity: bigint | number
22
+ ): ServerContract.ActionParams.Type.cargo_item {
23
+ return {
24
+ ...cargoRef(src),
25
+ quantity,
26
+ }
27
+ }