@shipload/sdk 1.0.0-next.43 → 1.0.0-next.44

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 (39) hide show
  1. package/lib/shipload.d.ts +141 -172
  2. package/lib/shipload.js +503 -300
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +500 -302
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +50 -67
  7. package/lib/testing.js +168 -208
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +169 -209
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/contracts/server.ts +126 -214
  13. package/src/data/capabilities.ts +14 -14
  14. package/src/data/capability-formulas.ts +7 -7
  15. package/src/data/entities.json +4 -0
  16. package/src/data/item-ids.ts +1 -0
  17. package/src/data/items.json +6 -0
  18. package/src/data/kind-registry.json +18 -6
  19. package/src/data/kind-registry.ts +7 -0
  20. package/src/data/metadata.ts +22 -15
  21. package/src/data/recipes.json +170 -19
  22. package/src/derivation/build-methods.test.ts +13 -0
  23. package/src/derivation/build-methods.ts +5 -2
  24. package/src/derivation/capabilities.ts +8 -8
  25. package/src/index-module.ts +5 -0
  26. package/src/managers/actions.ts +25 -8
  27. package/src/managers/cluster.test.ts +39 -0
  28. package/src/managers/cluster.ts +53 -0
  29. package/src/managers/context.ts +9 -0
  30. package/src/managers/index.ts +2 -0
  31. package/src/nft/buildImmutableData.ts +15 -17
  32. package/src/nft/description.ts +8 -8
  33. package/src/resolution/describe-module.ts +6 -6
  34. package/src/resolution/resolve-item.ts +3 -3
  35. package/src/shipload.ts +5 -0
  36. package/src/subscriptions/manager.cluster.test.ts +46 -0
  37. package/src/subscriptions/manager.ts +22 -0
  38. package/src/subscriptions/types.ts +16 -0
  39. package/src/types.ts +7 -0
@@ -24,6 +24,14 @@
24
24
  "statIndex": 2
25
25
  }
26
26
  ]
27
+ },
28
+ {
29
+ "sources": [
30
+ {
31
+ "inputIndex": 0,
32
+ "statIndex": 1
33
+ }
34
+ ]
27
35
  }
28
36
  ],
29
37
  "blendWeights": []
@@ -57,6 +65,22 @@
57
65
  "statIndex": 0
58
66
  }
59
67
  ]
68
+ },
69
+ {
70
+ "sources": [
71
+ {
72
+ "inputIndex": 0,
73
+ "statIndex": 2
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ "sources": [
79
+ {
80
+ "inputIndex": 1,
81
+ "statIndex": 2
82
+ }
83
+ ]
60
84
  }
61
85
  ],
62
86
  "blendWeights": []
@@ -86,6 +110,14 @@
86
110
  "statIndex": 2
87
111
  }
88
112
  ]
113
+ },
114
+ {
115
+ "sources": [
116
+ {
117
+ "inputIndex": 0,
118
+ "statIndex": 1
119
+ }
120
+ ]
89
121
  }
90
122
  ],
91
123
  "blendWeights": []
@@ -119,6 +151,14 @@
119
151
  "statIndex": 2
120
152
  }
121
153
  ]
154
+ },
155
+ {
156
+ "sources": [
157
+ {
158
+ "inputIndex": 0,
159
+ "statIndex": 0
160
+ }
161
+ ]
122
162
  }
123
163
  ],
124
164
  "blendWeights": []
@@ -152,6 +192,14 @@
152
192
  "statIndex": 1
153
193
  }
154
194
  ]
195
+ },
196
+ {
197
+ "sources": [
198
+ {
199
+ "inputIndex": 0,
200
+ "statIndex": 2
201
+ }
202
+ ]
155
203
  }
156
204
  ],
157
205
  "blendWeights": []
@@ -181,6 +229,14 @@
181
229
  "statIndex": 2
182
230
  }
183
231
  ]
232
+ },
233
+ {
234
+ "sources": [
235
+ {
236
+ "inputIndex": 0,
237
+ "statIndex": 1
238
+ }
239
+ ]
184
240
  }
185
241
  ],
186
242
  "blendWeights": []
@@ -210,6 +266,14 @@
210
266
  "statIndex": 1
211
267
  }
212
268
  ]
269
+ },
270
+ {
271
+ "sources": [
272
+ {
273
+ "inputIndex": 0,
274
+ "statIndex": 2
275
+ }
276
+ ]
213
277
  }
214
278
  ],
215
279
  "blendWeights": []
@@ -272,6 +336,22 @@
272
336
  "statIndex": 2
273
337
  }
274
338
  ]
339
+ },
340
+ {
341
+ "sources": [
342
+ {
343
+ "inputIndex": 1,
344
+ "statIndex": 2
345
+ }
346
+ ]
347
+ },
348
+ {
349
+ "sources": [
350
+ {
351
+ "inputIndex": 1,
352
+ "statIndex": 0
353
+ }
354
+ ]
275
355
  }
276
356
  ],
277
357
  "blendWeights": []
@@ -305,6 +385,14 @@
305
385
  "statIndex": 0
306
386
  }
307
387
  ]
388
+ },
389
+ {
390
+ "sources": [
391
+ {
392
+ "inputIndex": 0,
393
+ "statIndex": 1
394
+ }
395
+ ]
308
396
  }
309
397
  ],
310
398
  "blendWeights": []
@@ -324,6 +412,10 @@
324
412
  {
325
413
  "inputIndex": 0,
326
414
  "statIndex": 0
415
+ },
416
+ {
417
+ "inputIndex": 0,
418
+ "statIndex": 2
327
419
  }
328
420
  ]
329
421
  },
@@ -336,7 +428,9 @@
336
428
  ]
337
429
  }
338
430
  ],
339
- "blendWeights": []
431
+ "blendWeights": [
432
+ 1
433
+ ]
340
434
  },
341
435
  {
342
436
  "outputItemId": 10101,
@@ -353,6 +447,10 @@
353
447
  {
354
448
  "inputIndex": 0,
355
449
  "statIndex": 0
450
+ },
451
+ {
452
+ "inputIndex": 0,
453
+ "statIndex": 2
356
454
  }
357
455
  ]
358
456
  },
@@ -365,7 +463,9 @@
365
463
  ]
366
464
  }
367
465
  ],
368
- "blendWeights": []
466
+ "blendWeights": [
467
+ 1
468
+ ]
369
469
  },
370
470
  {
371
471
  "outputItemId": 10102,
@@ -376,7 +476,7 @@
376
476
  "quantity": 300
377
477
  },
378
478
  {
379
- "itemId": 10010,
479
+ "itemId": 10002,
380
480
  "quantity": 300
381
481
  }
382
482
  ],
@@ -386,14 +486,10 @@
386
486
  {
387
487
  "inputIndex": 0,
388
488
  "statIndex": 0
389
- }
390
- ]
391
- },
392
- {
393
- "sources": [
489
+ },
394
490
  {
395
491
  "inputIndex": 0,
396
- "statIndex": 1
492
+ "statIndex": 2
397
493
  }
398
494
  ]
399
495
  },
@@ -402,6 +498,10 @@
402
498
  {
403
499
  "inputIndex": 1,
404
500
  "statIndex": 0
501
+ },
502
+ {
503
+ "inputIndex": 0,
504
+ "statIndex": 1
405
505
  }
406
506
  ]
407
507
  },
@@ -409,12 +509,15 @@
409
509
  "sources": [
410
510
  {
411
511
  "inputIndex": 1,
412
- "statIndex": 1
512
+ "statIndex": 3
413
513
  }
414
514
  ]
415
515
  }
416
516
  ],
417
- "blendWeights": []
517
+ "blendWeights": [
518
+ 1,
519
+ 1
520
+ ]
418
521
  },
419
522
  {
420
523
  "outputItemId": 10103,
@@ -439,11 +542,17 @@
439
542
  {
440
543
  "inputIndex": 0,
441
544
  "statIndex": 0
545
+ },
546
+ {
547
+ "inputIndex": 0,
548
+ "statIndex": 2
442
549
  }
443
550
  ]
444
551
  }
445
552
  ],
446
- "blendWeights": []
553
+ "blendWeights": [
554
+ 1
555
+ ]
447
556
  },
448
557
  {
449
558
  "outputItemId": 10104,
@@ -463,7 +572,11 @@
463
572
  "sources": [
464
573
  {
465
574
  "inputIndex": 0,
466
- "statIndex": 0
575
+ "statIndex": 2
576
+ },
577
+ {
578
+ "inputIndex": 0,
579
+ "statIndex": 3
467
580
  }
468
581
  ]
469
582
  },
@@ -476,7 +589,10 @@
476
589
  ]
477
590
  }
478
591
  ],
479
- "blendWeights": []
592
+ "blendWeights": [
593
+ 1,
594
+ 1
595
+ ]
480
596
  },
481
597
  {
482
598
  "outputItemId": 10105,
@@ -546,6 +662,10 @@
546
662
  {
547
663
  "inputIndex": 0,
548
664
  "statIndex": 0
665
+ },
666
+ {
667
+ "inputIndex": 0,
668
+ "statIndex": 1
549
669
  }
550
670
  ]
551
671
  },
@@ -561,12 +681,15 @@
561
681
  "sources": [
562
682
  {
563
683
  "inputIndex": 0,
564
- "statIndex": 1
684
+ "statIndex": 2
565
685
  }
566
686
  ]
567
687
  }
568
688
  ],
569
- "blendWeights": []
689
+ "blendWeights": [
690
+ 1,
691
+ 1
692
+ ]
570
693
  },
571
694
  {
572
695
  "outputItemId": 10107,
@@ -586,11 +709,11 @@
586
709
  "sources": [
587
710
  {
588
711
  "inputIndex": 0,
589
- "statIndex": 0
712
+ "statIndex": 1
590
713
  },
591
714
  {
592
- "inputIndex": 1,
593
- "statIndex": 1
715
+ "inputIndex": 0,
716
+ "statIndex": 2
594
717
  }
595
718
  ]
596
719
  }
@@ -875,5 +998,33 @@
875
998
  }
876
999
  ],
877
1000
  "blendWeights": []
1001
+ },
1002
+ {
1003
+ "outputItemId": 10207,
1004
+ "outputMass": 2400000,
1005
+ "inputs": [
1006
+ {
1007
+ "itemId": 10005,
1008
+ "quantity": 200
1009
+ },
1010
+ {
1011
+ "itemId": 10010,
1012
+ "quantity": 200
1013
+ }
1014
+ ],
1015
+ "statSlots": [
1016
+ {
1017
+ "sources": []
1018
+ },
1019
+ {
1020
+ "sources": [
1021
+ {
1022
+ "inputIndex": 1,
1023
+ "statIndex": 1
1024
+ }
1025
+ ]
1026
+ }
1027
+ ],
1028
+ "blendWeights": []
878
1029
  }
879
1030
  ]
@@ -0,0 +1,13 @@
1
+ import {describe, expect, test} from 'bun:test'
2
+ import {availableBuildMethods} from './build-methods'
3
+ import {ITEM_HUB_T1_PACKED, ITEM_WAREHOUSE_T1_PACKED} from '../data/item-ids'
4
+
5
+ describe('availableBuildMethods', () => {
6
+ test('orbital structures build via craft+deploy or plot', () => {
7
+ expect(availableBuildMethods(ITEM_WAREHOUSE_T1_PACKED)).toEqual(['craft+deploy', 'plot'])
8
+ })
9
+
10
+ test('hub is craft+deploy only — excluded from the plot path', () => {
11
+ expect(availableBuildMethods(ITEM_HUB_T1_PACKED)).toEqual(['craft+deploy'])
12
+ })
13
+ })
@@ -1,4 +1,4 @@
1
- import {EntityClass, getKindMeta, getTemplateMeta} from '../data/kind-registry'
1
+ import {ENTITY_HUB, EntityClass, getKindMeta, getTemplateMeta} from '../data/kind-registry'
2
2
  import {getRecipe} from '../data/recipes-runtime'
3
3
  import {getItems} from '../data/catalog'
4
4
  import type {Item} from '../types'
@@ -15,7 +15,10 @@ export function availableBuildMethods(itemId: number): BuildMethod[] {
15
15
  const kindMeta = getKindMeta(template.kind)
16
16
  if (!kindMeta) return ['craft+deploy']
17
17
 
18
- if (kindMeta.classification === EntityClass.PlanetaryStructure) {
18
+ if (
19
+ kindMeta.classification === EntityClass.OrbitalStructure &&
20
+ !kindMeta.kind.equals(ENTITY_HUB)
21
+ ) {
19
22
  return ['craft+deploy', 'plot']
20
23
  }
21
24
  return ['craft+deploy']
@@ -78,12 +78,12 @@ export function computeGathererCapabilities(
78
78
  } {
79
79
  const str = stats.strength
80
80
  const con = stats.saturation
81
- const tol = stats.tolerance
81
+ const hrd = stats.hardness
82
82
 
83
83
  return {
84
84
  yield: 200 + str,
85
85
  drain: 2 * Math.max(250, 1250 - Math.floor((con * 25) / 20)),
86
- depth: gathererDepthForTier(tol, tier),
86
+ depth: gathererDepthForTier(hrd, tier),
87
87
  }
88
88
  }
89
89
 
@@ -106,11 +106,11 @@ export function computeCrafterCapabilities(stats: Record<string, number>): {
106
106
  speed: number
107
107
  drain: number
108
108
  } {
109
- const rea = stats.reactivity
109
+ const fin = stats.fineness
110
110
  const con = stats.conductivity
111
111
 
112
112
  return {
113
- speed: 100 + Math.floor((rea * 4) / 5),
113
+ speed: 100 + Math.floor((fin * 4) / 5),
114
114
  drain: Math.max(5, 30 - Math.floor(con / 33)),
115
115
  }
116
116
  }
@@ -122,12 +122,12 @@ export function computeHaulerCapabilities(stats: Record<string, number>): {
122
122
  } {
123
123
  const resonance = stats.resonance
124
124
  const plasticity = stats.plasticity
125
- const reflectivity = stats.reflectivity
125
+ const conductivity = stats.conductivity
126
126
 
127
127
  return {
128
128
  capacity: Math.max(1, 1 + Math.floor(resonance / 400)),
129
129
  efficiency: 2000 + plasticity * 6,
130
- drain: Math.max(3, 15 - Math.floor(reflectivity / 80)),
130
+ drain: Math.max(3, 15 - Math.floor(conductivity / 80)),
131
131
  }
132
132
  }
133
133
 
@@ -224,8 +224,8 @@ export function computeBaseCapacity(itemId: number, stats: Record<string, number
224
224
  export function computeWarpCapabilities(stats: Record<string, number>): {
225
225
  range: number
226
226
  } {
227
- const resonance = stats.resonance
228
- return {range: 100 + resonance * 3}
227
+ const reflectivity = stats.reflectivity
228
+ return {range: 100 + reflectivity * 3}
229
229
  }
230
230
 
231
231
  export function computeWarehouseHullCapabilities(stats: Record<string, number>): {
@@ -46,9 +46,12 @@ export {
46
46
  LocationsManager,
47
47
  EpochsManager,
48
48
  ActionsManager,
49
+ ClusterManager,
50
+ computeFreeCells,
49
51
  NftManager,
50
52
  ConstructionManager,
51
53
  } from './managers'
54
+ export type {GridCell, ClusterCell, Cluster} from './managers'
52
55
  export type {
53
56
  PlayerRosterEntry,
54
57
  LocationStratum,
@@ -315,6 +318,7 @@ export {
315
318
  ENTITY_FACTORY,
316
319
  ENTITY_CONTAINER,
317
320
  ENTITY_NEXUS,
321
+ ENTITY_HUB,
318
322
  getEntityClass,
319
323
  getPackedEntityType,
320
324
  getKindMeta,
@@ -332,6 +336,7 @@ export {
332
336
  isContainer,
333
337
  isNexus,
334
338
  isPlot,
339
+ isHub,
335
340
  } from './data/kind-registry'
336
341
  export type {EntityTypeName, KindMeta, TemplateMeta} from './data/kind-registry'
337
342
  export * from './capabilities'
@@ -17,7 +17,7 @@ import {
17
17
  type UInt64Type,
18
18
  } from '@wharfkit/antelope'
19
19
  import {BaseManager} from './base'
20
- import {Coordinates, PRECISION, type CoordinatesType} from '../types'
20
+ import {Coordinates, PRECISION, type ClusterSlotType, type CoordinatesType} from '../types'
21
21
  import {ServerContract} from '../contracts'
22
22
  import {ATOMICASSETS_ABI, SHIPLOAD_COLLECTION} from '../nft/atomicassets'
23
23
  import {getItem} from '../data/catalog'
@@ -435,22 +435,39 @@ export class ActionsManager extends BaseManager {
435
435
  })
436
436
  }
437
437
 
438
- deploy(entityId: UInt64Type, ref: ServerContract.ActionParams.Type.cargo_ref): Action {
438
+ deploy(
439
+ entityId: UInt64Type,
440
+ ref: ServerContract.ActionParams.Type.cargo_ref,
441
+ slot?: ClusterSlotType
442
+ ): Action {
439
443
  return this.server.action('deploy', {
440
444
  id: UInt64.from(entityId),
441
445
  ref,
446
+ slot: slot ? {hub: UInt64.from(slot.hub), gx: slot.gx, gy: slot.gy} : undefined,
442
447
  })
443
448
  }
444
449
 
445
- claimplot(
446
- entityId: UInt64Type,
447
- targetItemId: UInt16Type,
448
- coords: ServerContract.ActionParams.Type.coordinates
449
- ): Action {
450
+ claimplot(entityId: UInt64Type, targetItemId: UInt16Type, slot: ClusterSlotType): Action {
450
451
  return this.server.action('claimplot', {
451
452
  builder_id: UInt64.from(entityId),
452
453
  target_item_id: UInt16.from(targetItemId),
453
- coords,
454
+ slot: {hub: UInt64.from(slot.hub), gx: slot.gx, gy: slot.gy},
455
+ })
456
+ }
457
+
458
+ movetile(
459
+ hubId: UInt64Type,
460
+ fromGx: number,
461
+ fromGy: number,
462
+ toGx: number,
463
+ toGy: number
464
+ ): Action {
465
+ return this.server.action('movetile', {
466
+ hub_id: UInt64.from(hubId),
467
+ from_gx: fromGx,
468
+ from_gy: fromGy,
469
+ to_gx: toGx,
470
+ to_gy: toGy,
454
471
  })
455
472
  }
456
473
 
@@ -0,0 +1,39 @@
1
+ import {describe, expect, test} from 'bun:test'
2
+ import {computeFreeCells} from './cluster'
3
+
4
+ describe('computeFreeCells', () => {
5
+ test('returns footprint cells that are not occupied', () => {
6
+ const footprint = [
7
+ {gx: 2, gy: 0},
8
+ {gx: 0, gy: 2},
9
+ {gx: 1, gy: 1},
10
+ ]
11
+ const occupied = [{gx: 2, gy: 0, entity: 7}]
12
+ expect(computeFreeCells(footprint, occupied)).toEqual([
13
+ {gx: 0, gy: 2},
14
+ {gx: 1, gy: 1},
15
+ ])
16
+ })
17
+
18
+ test('matches occupancy on signed coordinates', () => {
19
+ const footprint = [
20
+ {gx: -2, gy: 0},
21
+ {gx: 0, gy: -2},
22
+ {gx: -1, gy: 1},
23
+ ]
24
+ const occupied = [{gx: 0, gy: -2, entity: 9}]
25
+ expect(computeFreeCells(footprint, occupied)).toEqual([
26
+ {gx: -2, gy: 0},
27
+ {gx: -1, gy: 1},
28
+ ])
29
+ })
30
+
31
+ test('empty footprint yields no free cells', () => {
32
+ expect(computeFreeCells([], [])).toEqual([])
33
+ })
34
+
35
+ test('fully occupied footprint yields no free cells', () => {
36
+ const footprint = [{gx: 1, gy: 1}]
37
+ expect(computeFreeCells(footprint, [{gx: 1, gy: 1, entity: 3}])).toEqual([])
38
+ })
39
+ })
@@ -0,0 +1,53 @@
1
+ import {UInt16, type UInt16Type, UInt64, type UInt64Type} from '@wharfkit/antelope'
2
+ import {BaseManager} from './base'
3
+ import type {ServerContract} from '../contracts'
4
+
5
+ export interface GridCell {
6
+ gx: number
7
+ gy: number
8
+ }
9
+
10
+ export interface ClusterCell extends GridCell {
11
+ entity: number
12
+ }
13
+
14
+ export interface Cluster {
15
+ root: number
16
+ cells: ClusterCell[]
17
+ }
18
+
19
+ export function computeFreeCells(footprint: GridCell[], occupied: ClusterCell[]): GridCell[] {
20
+ const taken = new Set(occupied.map((c) => `${c.gx},${c.gy}`))
21
+ return footprint.filter((c) => !taken.has(`${c.gx},${c.gy}`))
22
+ }
23
+
24
+ export class ClusterManager extends BaseManager {
25
+ async getFootprint(itemId: UInt16Type): Promise<GridCell[]> {
26
+ const res = (await this.server.readonly('getfootprint', {
27
+ item_id: UInt16.from(itemId),
28
+ })) as ServerContract.Types.footprint_result
29
+ return res.cells.map((c) => ({gx: Number(c.gx), gy: Number(c.gy)}))
30
+ }
31
+
32
+ async getCluster(hubId: UInt64Type): Promise<Cluster> {
33
+ const res = (await this.server.readonly('getcluster', {
34
+ hub_id: UInt64.from(hubId),
35
+ })) as ServerContract.Types.cluster_row
36
+ return {
37
+ root: Number(res.root),
38
+ cells: res.cells.map((c) => ({
39
+ gx: Number(c.gx),
40
+ gy: Number(c.gy),
41
+ entity: Number(c.entity),
42
+ })),
43
+ }
44
+ }
45
+
46
+ async freeCells(hubId: UInt64Type, hubItemId: UInt16Type): Promise<GridCell[]> {
47
+ const [footprint, cluster] = await Promise.all([
48
+ this.getFootprint(hubItemId),
49
+ this.getCluster(hubId),
50
+ ])
51
+ return computeFreeCells(footprint, cluster.cells)
52
+ }
53
+ }
@@ -9,6 +9,7 @@ import {LocationsManager} from './locations'
9
9
  import {CoordinatesManager} from './coordinates'
10
10
  import {EpochsManager} from './epochs'
11
11
  import {ActionsManager} from './actions'
12
+ import {ClusterManager} from './cluster'
12
13
  import {NftManager} from './nft'
13
14
  import {SubscriptionsManager} from '../subscriptions/manager'
14
15
 
@@ -19,6 +20,7 @@ export class GameContext {
19
20
  private _coordinates?: CoordinatesManager
20
21
  private _epochs?: EpochsManager
21
22
  private _actions?: ActionsManager
23
+ private _clusters?: ClusterManager
22
24
  private _nft?: NftManager
23
25
  private _subscriptions?: SubscriptionsManager
24
26
  private _subscriptionsUrl?: string
@@ -75,6 +77,13 @@ export class GameContext {
75
77
  return this._actions
76
78
  }
77
79
 
80
+ get clusters(): ClusterManager {
81
+ if (!this._clusters) {
82
+ this._clusters = new ClusterManager(this)
83
+ }
84
+ return this._clusters
85
+ }
86
+
78
87
  get nft(): NftManager {
79
88
  if (!this._nft) {
80
89
  this._nft = new NftManager(this)
@@ -8,6 +8,8 @@ export {LocationsManager} from './locations'
8
8
  export type {LocationStratum} from './locations'
9
9
  export {EpochsManager} from './epochs'
10
10
  export {ActionsManager} from './actions'
11
+ export {ClusterManager, computeFreeCells} from './cluster'
12
+ export type {GridCell, ClusterCell, Cluster} from './cluster'
11
13
  export {NftManager} from './nft'
12
14
  export type {NftConfigForItem} from './nft'
13
15
  export {PlotManager} from './plot'