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

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 (58) hide show
  1. package/lib/shipload.d.ts +544 -149
  2. package/lib/shipload.js +2424 -448
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +2390 -447
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +131 -7
  7. package/lib/testing.js +469 -11
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +470 -12
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/capabilities/crafting.ts +10 -1
  13. package/src/capabilities/gathering.ts +1 -1
  14. package/src/capabilities/hauling.ts +0 -5
  15. package/src/capabilities/modules.ts +6 -0
  16. package/src/capabilities/movement.ts +1 -1
  17. package/src/contracts/server.ts +315 -8
  18. package/src/data/capabilities.ts +11 -2
  19. package/src/data/entities.json +235 -20
  20. package/src/data/item-ids.ts +10 -0
  21. package/src/data/items.json +61 -0
  22. package/src/data/kind-registry.json +53 -1
  23. package/src/data/kind-registry.ts +5 -0
  24. package/src/data/metadata.ts +74 -5
  25. package/src/data/recipes-runtime.ts +1 -0
  26. package/src/data/recipes.json +887 -118
  27. package/src/derivation/capabilities.test.ts +81 -4
  28. package/src/derivation/capabilities.ts +162 -57
  29. package/src/derivation/crafting.ts +2 -0
  30. package/src/derivation/recipe-usage.test.ts +10 -7
  31. package/src/derivation/rollups.ts +16 -0
  32. package/src/derivation/stat-scaling.ts +12 -0
  33. package/src/entities/makers.ts +10 -1
  34. package/src/index-module.ts +33 -3
  35. package/src/managers/actions.ts +89 -44
  36. package/src/managers/construction-types.ts +2 -2
  37. package/src/managers/construction.ts +15 -15
  38. package/src/managers/plot.ts +1 -1
  39. package/src/nft/buildImmutableData.ts +55 -9
  40. package/src/nft/description.ts +99 -36
  41. package/src/planner/planner.test.ts +50 -41
  42. package/src/resolution/resolve-item.test.ts +1 -1
  43. package/src/resolution/resolve-item.ts +26 -11
  44. package/src/scheduling/availability.ts +7 -6
  45. package/src/scheduling/cancel.test.ts +40 -6
  46. package/src/scheduling/cancel.ts +21 -29
  47. package/src/scheduling/jobs.ts +71 -0
  48. package/src/scheduling/lanes.ts +29 -0
  49. package/src/scheduling/projection.ts +42 -25
  50. package/src/scheduling/task-cargo.ts +1 -1
  51. package/src/testing/projection-parity.ts +2 -2
  52. package/src/travel/reach.ts +4 -6
  53. package/src/travel/route-planner.ts +60 -49
  54. package/src/travel/route-simulator.ts +170 -0
  55. package/src/travel/travel.ts +40 -5
  56. package/src/types/capabilities.ts +9 -3
  57. package/src/types.ts +8 -3
  58. package/src/managers/flatten-gather-plan.test.ts +0 -80
@@ -1,7 +1,4 @@
1
- import {distanceBetweenPoints, findNearbyPlanets} from './travel'
2
- import {hasSystem} from '../utils/system'
3
1
  import {nearbyWormholes, wormholeAt} from '../derivation/wormhole'
4
- import {PRECISION} from '../types'
5
2
  import {Checksum256, type Checksum256Type} from '@wharfkit/antelope'
6
3
 
7
4
  export interface Coord {
@@ -26,6 +23,19 @@ export interface RoutePlan {
26
23
  totalDistance: number
27
24
  }
28
25
 
26
+ export interface RouteLegInput {
27
+ from: Coord
28
+ to: Coord
29
+ distance: number
30
+ isDestination: boolean
31
+ }
32
+
33
+ /**
34
+ * Returns the elapsed-time search cost for a leg, or null when the leg is not contract-feasible.
35
+ */
36
+ export type RouteLegCost = (leg: RouteLegInput) => number | null
37
+ export type RouteHeuristicCost = (from: Coord, dest: Coord) => number
38
+
29
39
  export type RouteFailureReason = 'empty-destination' | 'no-path' | 'max-legs'
30
40
 
31
41
  export interface RouteFailure {
@@ -46,6 +56,8 @@ export interface PlanRouteParams {
46
56
  corridorSlack?: number
47
57
  nodeBudget?: number
48
58
  maxLegs?: number
59
+ legCost?: RouteLegCost
60
+ heuristicCost?: RouteHeuristicCost
49
61
  }
50
62
 
51
63
  const key = (c: Coord): string => `${c.x},${c.y}`
@@ -65,12 +77,25 @@ export function planRoute(params: PlanRouteParams): RouteResult {
65
77
  }
66
78
 
67
79
  const straightLine = dist(origin, dest)
68
- const heuristic = (c: Coord): number => Math.ceil(dist(c, dest) / perLegReach)
80
+ if (straightLine <= perLegReach) {
81
+ const directCost = params.legCost?.({
82
+ from: origin,
83
+ to: dest,
84
+ distance: straightLine,
85
+ isDestination: true,
86
+ })
87
+ if (directCost !== null) {
88
+ return {ok: true, waypoints: [dest], legs: 1, totalDistance: straightLine}
89
+ }
90
+ }
91
+ const heuristic = (c: Coord): number =>
92
+ params.heuristicCost?.(c, dest) ??
93
+ (params.legCost ? 0 : Math.ceil(dist(c, dest) / perLegReach))
69
94
 
70
95
  const gScore = new Map<string, number>([[key(origin), 0]])
71
96
  const cameFrom = new Map<string, Coord>()
72
- const frontier: {coord: Coord; g: number; f: number; remaining: number}[] = [
73
- {coord: origin, g: 0, f: heuristic(origin), remaining: straightLine},
97
+ const frontier: {coord: Coord; legs: number; cost: number; f: number; remaining: number}[] = [
98
+ {coord: origin, legs: 0, cost: 0, f: heuristic(origin), remaining: straightLine},
74
99
  ]
75
100
 
76
101
  let furthest = origin
@@ -88,6 +113,7 @@ export function planRoute(params: PlanRouteParams): RouteResult {
88
113
  }
89
114
  }
90
115
  const current = frontier.splice(bestIdx, 1)[0]
116
+ if (current.cost !== gScore.get(key(current.coord))) continue
91
117
 
92
118
  if (sameCoord(current.coord, dest)) {
93
119
  return reconstruct(cameFrom, origin, dest)
@@ -105,20 +131,31 @@ export function planRoute(params: PlanRouteParams): RouteResult {
105
131
  dist(origin, n.coord) + dist(n.coord, dest) <= straightLine + corridorSlack
106
132
  if (!inCorridor) continue
107
133
 
108
- const tentativeG = current.g + 1
109
- if (tentativeG > maxLegs) {
134
+ const tentativeLegs = current.legs + 1
135
+ if (tentativeLegs > maxLegs) {
110
136
  cappedByMaxLegs = true
111
137
  continue
112
138
  }
139
+ const evaluatedCost = params.legCost?.({
140
+ from: current.coord,
141
+ to: n.coord,
142
+ distance: n.dist,
143
+ isDestination: sameCoord(n.coord, dest),
144
+ })
145
+ if (evaluatedCost === null) continue
146
+ const legCost = evaluatedCost ?? 1
147
+ if (!(legCost >= 0) || !Number.isFinite(legCost)) continue
113
148
  const nk = key(n.coord)
114
- if (tentativeG < (gScore.get(nk) ?? Infinity)) {
115
- gScore.set(nk, tentativeG)
149
+ const nextCost = current.cost + legCost
150
+ if (nextCost < (gScore.get(nk) ?? Infinity)) {
151
+ gScore.set(nk, nextCost)
116
152
  cameFrom.set(nk, current.coord)
117
153
  const remaining = dist(n.coord, dest)
118
154
  frontier.push({
119
155
  coord: n.coord,
120
- g: tentativeG,
121
- f: tentativeG + Math.ceil(remaining / perLegReach),
156
+ legs: tentativeLegs,
157
+ cost: nextCost,
158
+ f: nextCost + heuristic(n.coord),
122
159
  remaining,
123
160
  })
124
161
  }
@@ -180,50 +217,24 @@ export interface ScanProvider {
180
217
  ): {x: number; y: number; locType: number}[]
181
218
  }
182
219
 
183
- let scanProvider: ScanProvider | null = null
184
- const graphCache = new Map<string, SystemGraph>()
185
-
186
- // Inject a fast (e.g. wasm) location-type backend; null restores the pure-JS path. Clears the graph cache.
187
- export function setScanProvider(provider: ScanProvider | null): void {
188
- scanProvider = provider
189
- graphCache.clear()
190
- }
220
+ // Keyed by provider identity, so pass a stable one (the `@shipload/sdk/scan` namespace).
221
+ const graphCache = new WeakMap<ScanProvider, Map<string, SystemGraph>>()
191
222
 
192
- export function sdkSystemGraph(seed: Checksum256Type): SystemGraph {
223
+ export function sdkSystemGraph(seed: Checksum256Type, scan: ScanProvider): SystemGraph {
193
224
  const s = Checksum256.from(seed)
194
225
  const seedHex = s.toString()
195
- const cached = graphCache.get(seedHex)
226
+ let bySeed = graphCache.get(scan)
227
+ if (!bySeed) {
228
+ bySeed = new Map()
229
+ graphCache.set(scan, bySeed)
230
+ }
231
+ const cached = bySeed.get(seedHex)
196
232
  if (cached) return cached
197
- const graph = scanProvider ? wasmSystemGraph(s, seedHex, scanProvider) : jsSystemGraph(s)
198
- graphCache.set(seedHex, graph)
233
+ const graph = wasmSystemGraph(s, seedHex, scan)
234
+ bySeed.set(seedHex, graph)
199
235
  return graph
200
236
  }
201
237
 
202
- // Travelable nodes mirror the contract's is_travelable: systems plus wormhole mouths.
203
- function jsSystemGraph(s: Checksum256): SystemGraph {
204
- return {
205
- hasSystem: (c) => hasSystem(s, {x: c.x, y: c.y}) || wormholeAt(s, c.x, c.y) !== null,
206
- nearby: (c, reachTiles) => {
207
- const seen = new Set<string>([`${c.x},${c.y}`])
208
- const out: Neighbor[] = []
209
- for (const d of findNearbyPlanets(s, {x: c.x, y: c.y}, reachTiles * PRECISION)) {
210
- const coord = {x: Number(d.destination.x), y: Number(d.destination.y)}
211
- const k = `${coord.x},${coord.y}`
212
- if (seen.has(k)) continue
213
- seen.add(k)
214
- out.push({coord, dist: Number(d.distance) / PRECISION})
215
- }
216
- for (const coord of nearbyWormholes(s, c.x, c.y, reachTiles)) {
217
- const k = `${coord.x},${coord.y}`
218
- if (seen.has(k)) continue
219
- seen.add(k)
220
- out.push({coord, dist: Math.hypot(coord.x - c.x, coord.y - c.y)})
221
- }
222
- return out
223
- },
224
- }
225
- }
226
-
227
238
  const SCAN_BUCKET = 48
228
239
 
229
240
  function wasmSystemGraph(s: Checksum256, seedHex: string, scan: ScanProvider): SystemGraph {
@@ -0,0 +1,170 @@
1
+ import type {UInt64Type} from '@wharfkit/antelope'
2
+ import {PRECISION, TRAVEL_MAX_DURATION} from '../types'
3
+ import {
4
+ calc_energyusage,
5
+ calc_group_flighttime,
6
+ calc_rechargetime,
7
+ distanceBetweenPoints,
8
+ } from './travel'
9
+
10
+ export interface RouteMoverInput {
11
+ ref: {entityType: string; entityId: UInt64Type}
12
+ hasMovement: boolean
13
+ engines?: {thrust: number; drain: number}
14
+ generator?: {capacity: number; recharge: number}
15
+ hauler?: {capacity: number; efficiency: number}
16
+ mass: number
17
+ energy: number
18
+ priorMobilityEnd: number
19
+ narrowBarrierEnd: number
20
+ /** Max end (seconds-from-now) over all this entity's lanes incl. worker/craft; gates recharges like the contract's all_lanes_end. Default 0. */
21
+ allLanesEnd?: number
22
+ }
23
+
24
+ export interface RouteLegSim {
25
+ from: {x: number; y: number}
26
+ to: {x: number; y: number}
27
+ distanceCells: number
28
+ energyCostByMover: Record<string, number>
29
+ rechargeBefore: boolean
30
+ rechargeSeconds: number
31
+ flightSeconds: number
32
+ }
33
+
34
+ export interface RouteSim {
35
+ legs: RouteLegSim[]
36
+ totalSeconds: number
37
+ reachable: boolean
38
+ }
39
+
40
+ export function simulateRoute(
41
+ movers: RouteMoverInput[],
42
+ waypoints: {x: number; y: number}[],
43
+ origin: {x: number; y: number},
44
+ recharge: boolean
45
+ ): RouteSim {
46
+ const totalThrust = movers
47
+ .filter((m) => m.hasMovement && m.engines)
48
+ .reduce((sum, m) => sum + m.engines!.thrust, 0)
49
+
50
+ const totalMass = movers.reduce((sum, m) => sum + m.mass, 0)
51
+
52
+ const haulCount = movers.filter((m) => !m.hasMovement).length
53
+
54
+ const pooledHaulCap = movers
55
+ .filter((m) => m.hasMovement && m.hauler)
56
+ .reduce((sum, m) => sum + m.hauler!.capacity, 0)
57
+
58
+ const weightedHaulEffNum = movers
59
+ .filter((m) => m.hasMovement && m.hauler)
60
+ .reduce((sum, m) => sum + m.hauler!.efficiency * m.hauler!.capacity, 0)
61
+
62
+ const energyByMover: Map<string, number> = new Map(
63
+ movers.map((m) => [String(m.ref.entityId), m.energy])
64
+ )
65
+
66
+ let reachable = true
67
+ const legs: RouteLegSim[] = []
68
+
69
+ const mobilityBarrier = movers
70
+ .filter((m) => m.hasMovement)
71
+ .reduce((mx, m) => Math.max(mx, m.priorMobilityEnd, m.narrowBarrierEnd), 0)
72
+
73
+ const rechargeFloor = movers
74
+ .filter((m) => m.hasMovement && m.generator)
75
+ .reduce((mx, m) => Math.max(mx, m.allLanesEnd ?? 0), 0)
76
+
77
+ let clock = 0
78
+
79
+ let from = origin
80
+ for (const to of waypoints) {
81
+ const distance = distanceBetweenPoints(from.x, from.y, to.x, to.y)
82
+ const distanceNum = Number(distance)
83
+ const distanceCells = distanceNum / PRECISION
84
+
85
+ const energyCostByMover: Record<string, number> = {}
86
+
87
+ for (const m of movers) {
88
+ if (!m.hasMovement || !m.engines) continue
89
+ const key = String(m.ref.entityId)
90
+ energyCostByMover[key] = Number(calc_energyusage(distance, m.engines.drain))
91
+ }
92
+
93
+ let rechargeBefore = false
94
+ let rechargeSeconds = 0
95
+
96
+ if (recharge) {
97
+ let maxDur = 0
98
+ for (const m of movers) {
99
+ if (!m.hasMovement || !m.generator) continue
100
+ const key = String(m.ref.entityId)
101
+ const curEnergy = energyByMover.get(key) ?? 0
102
+ const dur = Number(
103
+ calc_rechargetime(m.generator.capacity, curEnergy, m.generator.recharge)
104
+ )
105
+ if (dur > maxDur) maxDur = dur
106
+ }
107
+ rechargeSeconds = maxDur
108
+ rechargeBefore = rechargeSeconds > 0
109
+
110
+ if (rechargeBefore) {
111
+ for (const m of movers) {
112
+ if (!m.hasMovement || !m.generator) continue
113
+ const key = String(m.ref.entityId)
114
+ energyByMover.set(key, m.generator.capacity)
115
+ }
116
+ clock = Math.max(clock, rechargeFloor) + rechargeSeconds
117
+ }
118
+ }
119
+
120
+ for (const m of movers) {
121
+ if (!m.hasMovement || !m.engines) continue
122
+ const key = String(m.ref.entityId)
123
+ const cost = energyCostByMover[key] ?? 0
124
+ const curEnergy = energyByMover.get(key) ?? 0
125
+
126
+ if (recharge && m.generator) {
127
+ if (cost > m.generator.capacity) reachable = false
128
+ } else {
129
+ if (cost > curEnergy) reachable = false
130
+ }
131
+ }
132
+
133
+ const flightSeconds = Number(
134
+ calc_group_flighttime(
135
+ totalThrust,
136
+ haulCount,
137
+ pooledHaulCap,
138
+ weightedHaulEffNum,
139
+ totalMass,
140
+ distance
141
+ )
142
+ )
143
+
144
+ if (flightSeconds > TRAVEL_MAX_DURATION) reachable = false
145
+
146
+ for (const m of movers) {
147
+ if (!m.hasMovement || !m.engines) continue
148
+ const key = String(m.ref.entityId)
149
+ const cost = energyCostByMover[key] ?? 0
150
+ const curEnergy = energyByMover.get(key) ?? 0
151
+ energyByMover.set(key, Math.max(0, curEnergy - cost))
152
+ }
153
+
154
+ clock = Math.max(clock, mobilityBarrier) + flightSeconds
155
+
156
+ legs.push({
157
+ from,
158
+ to,
159
+ distanceCells,
160
+ energyCostByMover,
161
+ rechargeBefore,
162
+ rechargeSeconds,
163
+ flightSeconds,
164
+ })
165
+
166
+ from = to
167
+ }
168
+
169
+ return {legs, totalSeconds: clock, reachable}
170
+ }
@@ -14,7 +14,6 @@ import {
14
14
  type Checksum256,
15
15
  Int64,
16
16
  type Int64Type,
17
- UInt16,
18
17
  UInt32,
19
18
  type UInt32Type,
20
19
  UInt64,
@@ -23,9 +22,11 @@ import {
23
22
 
24
23
  import type {ServerContract} from '../contracts'
25
24
  import {
25
+ BASE_HAUL_PENALTY_MILLI,
26
26
  BASE_ORBITAL_MASS,
27
27
  type CargoMassInfo,
28
28
  type Distance,
29
+ HAULER_EFFICIENCY_DENOM,
29
30
  MAX_ORBITAL_ALTITUDE,
30
31
  MIN_ORBITAL_ALTITUDE,
31
32
  MIN_TRANSFER_DISTANCE_ORBITAL_VESSEL,
@@ -187,14 +188,15 @@ export function calc_rechargetime(
187
188
  const cap = UInt32.from(capacity)
188
189
  const eng = UInt32.from(energy)
189
190
  if (eng.gte(cap)) return UInt32.zero
190
- return cap.subtracting(eng).dividing(recharge)
191
+ const ticks = cap.subtracting(eng).dividing(recharge)
192
+ return ticks.equals(UInt32.zero) ? UInt32.from(1) : ticks
191
193
  }
192
194
 
193
195
  export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
194
196
  if (!ship.generator) return UInt32.from(0)
195
197
  return calc_rechargetime(
196
198
  ship.generator.capacity,
197
- ship.energy ?? UInt16.from(0),
199
+ ship.energy ?? UInt32.from(0),
198
200
  ship.generator.recharge
199
201
  )
200
202
  }
@@ -203,6 +205,16 @@ export function calc_flighttime(distance: UInt64Type, acceleration: number): UIn
203
205
  return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
204
206
  }
205
207
 
208
+ export function calc_travel_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
209
+ const cruiseTransitionDistance = 2 * PRECISION
210
+ if (Number(distance) <= cruiseTransitionDistance) {
211
+ return calc_flighttime(distance, acceleration)
212
+ }
213
+
214
+ const cruiseVelocity = Math.sqrt(acceleration * cruiseTransitionDistance)
215
+ return UInt32.from(Number(distance) / cruiseVelocity + cruiseVelocity / acceleration)
216
+ }
217
+
206
218
  export function calc_transit_duration(ax: number, ay: number, bx: number, by: number): UInt32 {
207
219
  const distance = distanceBetweenPoints(ax, ay, bx, by)
208
220
  return UInt32.from(Math.floor(distance.toNumber() / (PRECISION * WH.TRANSIT_SPEED)))
@@ -232,7 +244,7 @@ export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
232
244
 
233
245
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
234
246
  const acceleration = calc_ship_acceleration(ship, mass)
235
- return calc_flighttime(distance, acceleration)
247
+ return calc_travel_flighttime(distance, acceleration)
236
248
  }
237
249
 
238
250
  export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
@@ -263,8 +275,31 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
263
275
  return mass
264
276
  }
265
277
 
278
+ export function calc_group_flighttime(
279
+ totalThrust: number,
280
+ haulCount: number,
281
+ pooledHaulCap: number,
282
+ weightedHaulEffNum: number,
283
+ totalMass: number,
284
+ distance: UInt64Type
285
+ ): UInt32 {
286
+ const avgHaulEff = pooledHaulCap > 0 ? Math.trunc(weightedHaulEffNum / pooledHaulCap) : 0
287
+ let effectiveThrust = totalThrust
288
+ if (haulCount > 0) {
289
+ const penaltyMilli =
290
+ 1000 +
291
+ Math.trunc(
292
+ (haulCount * BASE_HAUL_PENALTY_MILLI * (HAULER_EFFICIENCY_DENOM - avgHaulEff)) /
293
+ HAULER_EFFICIENCY_DENOM
294
+ )
295
+ effectiveThrust = Math.trunc((totalThrust * 1000) / penaltyMilli)
296
+ }
297
+ const acceleration = calc_acceleration(effectiveThrust, totalMass)
298
+ return calc_travel_flighttime(distance, acceleration)
299
+ }
300
+
266
301
  export function calc_energyusage(distance: UInt64Type, drain: UInt32Type): UInt32 {
267
- return UInt64.from(distance).dividing(PRECISION).multiplying(drain)
302
+ return UInt64.from(distance).multiplying(drain).dividing(PRECISION)
268
303
  }
269
304
 
270
305
  export function calculateTransferTime(
@@ -1,4 +1,4 @@
1
- import type {Name, UInt16, UInt32, UInt8} from '@wharfkit/antelope'
1
+ import type {Name, UInt32, UInt8} from '@wharfkit/antelope'
2
2
  import type {ServerContract} from '../contracts'
3
3
 
4
4
  export interface LoaderStats {
@@ -18,13 +18,18 @@ export interface CrafterStats {
18
18
  drain: {toNumber(): number}
19
19
  }
20
20
 
21
+ export interface BuilderStats {
22
+ speed: {toNumber(): number}
23
+ drain: {toNumber(): number}
24
+ }
25
+
21
26
  export interface MovementCapability {
22
27
  engines: ServerContract.Types.movement_stats
23
28
  generator: ServerContract.Types.energy_stats
24
29
  }
25
30
 
26
31
  export interface EnergyCapability {
27
- energy: UInt16
32
+ energy: UInt32
28
33
  }
29
34
 
30
35
  export interface StorageCapability {
@@ -58,6 +63,7 @@ export interface EntityCapabilities {
58
63
  loaders?: LoaderStats
59
64
  gatherer?: GathererStats
60
65
  crafter?: CrafterStats
66
+ builder?: BuilderStats
61
67
  hauler?: ServerContract.Types.hauler_stats
62
68
  launcher?: ServerContract.Types.launcher_stats
63
69
  }
@@ -65,7 +71,7 @@ export interface EntityCapabilities {
65
71
  export interface EntityState {
66
72
  owner: Name
67
73
  location: ServerContract.Types.coordinates
68
- energy?: UInt16
74
+ energy?: UInt32
69
75
  cargomass: UInt32
70
76
  cargo: ServerContract.Types.cargo_item[]
71
77
  }
package/src/types.ts CHANGED
@@ -18,6 +18,9 @@ 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
 
@@ -35,7 +38,7 @@ export interface ClusterSlotType {
35
38
  export interface ShipLike {
36
39
  coordinates: ServerContract.Types.coordinates
37
40
  hullmass?: UInt32
38
- energy?: UInt16
41
+ energy?: UInt32
39
42
  engines?: ServerContract.Types.movement_stats
40
43
  generator?: ServerContract.Types.energy_stats
41
44
  loader_lanes?: ServerContract.Types.loader_lane[]
@@ -57,15 +60,15 @@ export enum TaskType {
57
60
  GATHER = 5,
58
61
  WARP = 6,
59
62
  CRAFT = 7,
60
- DEPLOY = 8,
61
63
  TRANSIT = 9,
62
64
  UNWRAP = 10,
63
65
  UNDEPLOY = 11,
66
+ LAUNCH = 12,
64
67
  DEMOLISH = 13,
65
- CLAIMPLOT = 14,
66
68
  BUILDPLOT = 15,
67
69
  CHARGE = 16,
68
70
  UPGRADE = 17,
71
+ SHUTTLE = 18,
69
72
  }
70
73
 
71
74
  export enum HoldKind {
@@ -73,6 +76,7 @@ export enum HoldKind {
73
76
  PUSH = 2,
74
77
  GATHER = 3,
75
78
  BUILD = 4,
79
+ FLIGHT = 5,
76
80
  UPGRADE = 6,
77
81
  }
78
82
 
@@ -135,6 +139,7 @@ export type ModuleType =
135
139
  | 'loader'
136
140
  | 'warp'
137
141
  | 'crafter'
142
+ | 'builder'
138
143
  | 'launcher'
139
144
  | 'storage'
140
145
  | 'hauler'
@@ -1,80 +0,0 @@
1
- import {expect, test, describe} from 'bun:test'
2
- import {makeClient} from '@wharfkit/mock-data'
3
- import {Serializer} from '@wharfkit/antelope'
4
- import type {GatherPlan} from '../planner'
5
- import {ActionsManager} from './actions'
6
- import {ServerContract} from '../contracts'
7
-
8
- const client = makeClient('https://jungle4.greymass.com')
9
-
10
- function makeActions() {
11
- const realServer = new ServerContract.Contract({client})
12
- const stubServer = {
13
- account: realServer.account,
14
- action: realServer.action.bind(realServer),
15
- }
16
- const context = {server: stubServer} as any
17
- return new ActionsManager(context)
18
- }
19
-
20
- function fakePlan(): GatherPlan {
21
- return {
22
- cycles: [
23
- {
24
- rechargeBefore: false,
25
- rechargeSeconds: 0,
26
- gatherSeconds: 10,
27
- batchOre: 30,
28
- limpets: [
29
- {slot: 0, quantity: 20, durationSeconds: 10},
30
- {slot: 1, quantity: 10, durationSeconds: 8},
31
- ],
32
- },
33
- {
34
- rechargeBefore: true,
35
- rechargeSeconds: 5,
36
- gatherSeconds: 10,
37
- batchOre: 30,
38
- limpets: [{slot: 0, quantity: 30, durationSeconds: 10}],
39
- },
40
- ],
41
- cycleCount: 2,
42
- totalOre: 60,
43
- totalSeconds: 25,
44
- cap: 'requested',
45
- reachingCount: 2,
46
- totalLimpets: 2,
47
- warnings: [],
48
- }
49
- }
50
-
51
- describe('flattenGatherPlan', () => {
52
- test('flattens cycles to [recharge?, gather x limpets] in order with slots', () => {
53
- const actions = makeActions().flattenGatherPlan(fakePlan(), {
54
- sourceId: 1,
55
- destinationId: 1,
56
- stratum: 100,
57
- })
58
- expect(actions.map((a) => a.name.toString())).toEqual([
59
- 'gather',
60
- 'gather',
61
- 'recharge',
62
- 'gather',
63
- ])
64
- expect(actions.filter((a) => a.name.toString() === 'recharge').length).toBe(1)
65
- const gatherSlots = actions
66
- .filter((a) => a.name.toString() === 'gather')
67
- .map((a) => {
68
- const decoded = Serializer.decode({data: a.data, type: ServerContract.Types.gather})
69
- return Number(decoded.slot)
70
- })
71
- expect(gatherSlots).toEqual([0, 1, 0])
72
- })
73
-
74
- test('empty plan produces no actions', () => {
75
- const empty = {...fakePlan(), cycles: [], cycleCount: 0, totalOre: 0}
76
- expect(
77
- makeActions().flattenGatherPlan(empty, {sourceId: 1, destinationId: 1, stratum: 100})
78
- ).toHaveLength(0)
79
- })
80
- })