@shipload/sdk 1.0.0-next.15 → 1.0.0-next.17

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 (40) hide show
  1. package/lib/shipload.d.ts +273 -101
  2. package/lib/shipload.js +3419 -2914
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +3397 -2902
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +45 -39
  7. package/lib/testing.js +171 -143
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +171 -143
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/capabilities/gathering.ts +15 -6
  13. package/src/capabilities/modules.ts +6 -0
  14. package/src/contracts/platform.ts +1 -1
  15. package/src/contracts/server.ts +212 -111
  16. package/src/data/capabilities.ts +6 -1
  17. package/src/data/capability-formulas.ts +7 -1
  18. package/src/data/colors.ts +12 -12
  19. package/src/data/item-ids.ts +13 -12
  20. package/src/data/items.json +7 -0
  21. package/src/data/metadata.ts +36 -23
  22. package/src/data/recipes.json +49 -0
  23. package/src/derivation/capabilities.ts +18 -7
  24. package/src/derivation/capability-mappings.ts +2 -0
  25. package/src/derivation/stratum.ts +5 -9
  26. package/src/index-module.ts +18 -2
  27. package/src/managers/actions.ts +124 -12
  28. package/src/managers/context.ts +9 -0
  29. package/src/managers/index.ts +2 -0
  30. package/src/managers/nft.ts +28 -0
  31. package/src/nft/atomicassets.ts +124 -1
  32. package/src/nft/buildImmutableData.ts +316 -0
  33. package/src/nft/description.ts +1 -3
  34. package/src/nft/index.ts +1 -0
  35. package/src/resolution/describe-module.ts +3 -4
  36. package/src/resolution/resolve-item.ts +0 -1
  37. package/src/scheduling/projection.ts +0 -4
  38. package/src/scheduling/task-cargo.ts +0 -1
  39. package/src/shipload.ts +5 -0
  40. package/src/types.ts +1 -2
@@ -21,6 +21,7 @@ export const capabilityNames: string[] = [
21
21
  'Crafter',
22
22
  'Launch',
23
23
  'Hauler',
24
+ 'Battery',
24
25
  ]
25
26
 
26
27
  export const capabilityAttributes: CapabilityAttribute[] = [
@@ -40,7 +41,6 @@ export const capabilityAttributes: CapabilityAttribute[] = [
40
41
  {capability: 'Gathering', attribute: 'yield', description: 'Mass gathered per second'},
41
42
  {capability: 'Gathering', attribute: 'drain', description: 'Energy consumed per gather'},
42
43
  {capability: 'Gathering', attribute: 'depth', description: 'Maximum gather depth'},
43
- {capability: 'Gathering', attribute: 'speed', description: 'Gathering speed/penetration'},
44
44
  {capability: 'Warp', attribute: 'range', description: 'Maximum warp distance'},
45
45
  {capability: 'Crafter', attribute: 'speed', description: 'Crafting time per item'},
46
46
  {
@@ -67,6 +67,11 @@ export const capabilityAttributes: CapabilityAttribute[] = [
67
67
  attribute: 'drain',
68
68
  description: 'Energy consumed per target during haul-beam operation',
69
69
  },
70
+ {
71
+ capability: 'Battery',
72
+ attribute: 'bonus',
73
+ description: 'Energy capacity bonus added by an installed Battery module',
74
+ },
70
75
  ]
71
76
 
72
77
  const invertedAttributes = new Set(['drain', 'mass'])
@@ -12,6 +12,7 @@ export type SlotConsumerKind =
12
12
  | 'storage'
13
13
  | 'hauler'
14
14
  | 'warp'
15
+ | 'battery'
15
16
  | 'ship-t1'
16
17
  | 'container-t1'
17
18
  | 'warehouse-t1'
@@ -38,7 +39,6 @@ export const SLOT_FORMULAS: Record<SlotConsumerKind, Record<number, SlotConsumer
38
39
  0: {capability: 'Gathering', attribute: 'yield'},
39
40
  1: {capability: 'Gathering', attribute: 'depth'},
40
41
  3: {capability: 'Gathering', attribute: 'drain'},
41
- 4: {capability: 'Gathering', attribute: 'speed'},
42
42
  },
43
43
  loader: {
44
44
  0: {capability: 'Loader', attribute: 'mass'},
@@ -62,6 +62,12 @@ export const SLOT_FORMULAS: Record<SlotConsumerKind, Record<number, SlotConsumer
62
62
  warp: {
63
63
  0: {capability: 'Warp', attribute: 'range'},
64
64
  },
65
+ battery: {
66
+ 0: {capability: 'Battery', attribute: 'bonus'},
67
+ 1: {capability: 'Battery', attribute: 'bonus'},
68
+ 2: {capability: 'Battery', attribute: 'bonus'},
69
+ 3: {capability: 'Battery', attribute: 'bonus'},
70
+ },
65
71
  'ship-t1': ENTITY_HULL_SLOTS,
66
72
  'container-t1': ENTITY_HULL_SLOTS,
67
73
  'warehouse-t1': ENTITY_HULL_SLOTS,
@@ -43,16 +43,16 @@ export const componentIcon = '▣'
43
43
  export const moduleIcon = '⬢'
44
44
 
45
45
  export const itemAbbreviations: Record<number, string> = {
46
- 10001: 'HP',
47
- 10002: 'CL',
48
- 10003: 'TC',
49
- 10004: 'PC',
50
- 10005: 'DS',
51
- 10006: 'EP',
52
- 10007: 'CA',
53
- 10008: 'TB',
54
- 10009: 'RC',
55
- 10010: 'FA',
46
+ 10001: 'PL',
47
+ 10002: 'FR',
48
+ 10003: 'PC',
49
+ 10004: 'RS',
50
+ 10005: 'BM',
51
+ 10006: 'SN',
52
+ 10007: 'PM',
53
+ 10008: 'CR',
54
+ 10009: 'RX',
55
+ 10010: 'EM',
56
56
  10100: 'EN',
57
57
  10101: 'GN',
58
58
  10102: 'EX',
@@ -64,7 +64,7 @@ export const itemAbbreviations: Record<number, string> = {
64
64
  10200: 'CT',
65
65
  10201: 'SH',
66
66
  10202: 'WH',
67
- 20001: 'HP',
68
- 20002: 'CL',
67
+ 20001: 'PL',
68
+ 20002: 'FR',
69
69
  20200: 'CT',
70
70
  }
@@ -50,16 +50,16 @@ export const ITEM_BIOMASS_T7 = 507
50
50
  export const ITEM_BIOMASS_T8 = 508
51
51
  export const ITEM_BIOMASS_T9 = 509
52
52
  export const ITEM_BIOMASS_T10 = 510
53
- export const ITEM_HULL_PLATES = 10001
54
- export const ITEM_CARGO_LINING = 10002
55
- export const ITEM_THRUSTER_CORE = 10003
56
- export const ITEM_POWER_CELL = 10004
57
- export const ITEM_MATTER_CONDUIT = 10005
58
- export const ITEM_SURVEY_PROBE = 10006
59
- export const ITEM_CARGO_ARM = 10007
60
- export const ITEM_TOOL_BIT = 10008
61
- export const ITEM_REACTION_CHAMBER = 10009
62
- export const ITEM_FOCUSING_ARRAY = 10010
53
+ export const ITEM_PLATE = 10001
54
+ export const ITEM_FRAME = 10002
55
+ export const ITEM_PLASMA_CELL = 10003
56
+ export const ITEM_RESONATOR = 10004
57
+ export const ITEM_BEAM = 10005
58
+ export const ITEM_SENSOR = 10006
59
+ export const ITEM_POLYMER = 10007
60
+ export const ITEM_CERAMIC = 10008
61
+ export const ITEM_REACTOR = 10009
62
+ export const ITEM_EMITTER = 10010
63
63
  export const ITEM_ENGINE_T1 = 10100
64
64
  export const ITEM_GENERATOR_T1 = 10101
65
65
  export const ITEM_GATHERER_T1 = 10102
@@ -68,11 +68,12 @@ export const ITEM_CRAFTER_T1 = 10104
68
68
  export const ITEM_STORAGE_T1 = 10105
69
69
  export const ITEM_HAULER_T1 = 10106
70
70
  export const ITEM_WARP_T1 = 10107
71
+ export const ITEM_BATTERY_T1 = 10108
71
72
  export const ITEM_CONTAINER_T1_PACKED = 10200
72
73
  export const ITEM_SHIP_T1_PACKED = 10201
73
74
  export const ITEM_WAREHOUSE_T1_PACKED = 10202
74
75
  export const ITEM_EXTRACTOR_T1_PACKED = 10203
75
76
  export const ITEM_FACTORY_T1_PACKED = 10204
76
- export const ITEM_HULL_PLATES_T2 = 20001
77
- export const ITEM_CARGO_LINING_T2 = 20002
77
+ export const ITEM_PLATE_T2 = 20001
78
+ export const ITEM_FRAME_T2 = 20002
78
79
  export const ITEM_CONTAINER_T2_PACKED = 20200
@@ -465,6 +465,13 @@
465
465
  "tier": 1,
466
466
  "subtype": "warp"
467
467
  },
468
+ {
469
+ "id": 10108,
470
+ "mass": 90000,
471
+ "type": "module",
472
+ "tier": 1,
473
+ "subtype": "battery"
474
+ },
468
475
  {
469
476
  "id": 10200,
470
477
  "mass": 80000,
@@ -109,56 +109,63 @@ export const itemMetadata: Record<number, ItemMetadata> = {
109
109
 
110
110
  // === Components (T1) ===
111
111
  10001: {
112
- name: 'Hull Plates',
113
- description: 'Structural plating formed from ore. Used in hulls, containers, and frames.',
112
+ name: 'Plate',
113
+ description:
114
+ 'Structural plating formed from ore. Used in hulls, containers, and storage modules.',
114
115
  color: '#7B8D9E',
115
116
  },
116
117
  10002: {
117
- name: 'Cargo Lining',
118
+ name: 'Frame',
118
119
  description:
119
- 'Composite lining formed from fine regolith bound in biomass polymer. Dense enough to seal cargo holds, flexible enough to absorb vibration.',
120
+ 'Composite framing formed from fine regolith bound in biomass polymer. Dense enough to seal cargo holds, flexible enough to absorb vibration.',
120
121
  color: '#C4A57B',
121
122
  },
122
123
  10003: {
123
- name: 'Thruster Core',
124
- description: 'High-energy propulsion component formed from volatile gases.',
124
+ name: 'Plasma Cell',
125
+ description:
126
+ 'High-energy gaseous storage cell. Volatile gas held under controlled thermal conditions.',
125
127
  color: '#E86344',
126
128
  },
127
129
  10004: {
128
- name: 'Power Cell',
130
+ name: 'Resonator',
129
131
  description:
130
- 'Crystalline energy storage matrix. Resonant lattices retain and release charge.',
132
+ 'Crystalline resonance lattice. Stores and releases charge through coherent oscillation.',
131
133
  color: '#4ADBFF',
132
134
  },
133
135
  10005: {
134
- name: 'Matter Conduit',
135
- description: 'Heavy-duty ore shaft used in gathering equipment.',
136
+ name: 'Beam',
137
+ description:
138
+ 'Heavy-duty structural beam machined from refined ore. Strong enough to bear load, tolerant enough to survive harsh environments.',
136
139
  color: '#7B8D9E',
137
140
  },
138
141
  10006: {
139
- name: 'Survey Probe',
140
- description: 'Crystal-lattice sensor array for deep resource detection.',
142
+ name: 'Sensor',
143
+ description:
144
+ 'Crystal-lattice sensing element with conductive and reflective properties. Reads signal and surface alike.',
141
145
  color: '#4ADBFF',
142
146
  },
143
147
  10007: {
144
- name: 'Cargo Arm',
145
- description: 'Flexible biomass composite arm for cargo handling.',
148
+ name: 'Polymer',
149
+ description:
150
+ 'Pliable biomass-derived polymer with high insulation. Flexible, durable, electrically inert.',
146
151
  color: '#5A8B3E',
147
152
  },
148
153
  10008: {
149
- name: 'Tool Bit',
150
- description: 'Dense regolith cutting head for crafting operations.',
154
+ name: 'Ceramic',
155
+ description:
156
+ 'Hardened fine-grained ceramic refined from regolith. Hard enough to cut, fine enough to finish.',
151
157
  color: '#C4A57B',
152
158
  },
153
159
  10009: {
154
- name: 'Reaction Chamber',
155
- description: 'Gas-pressurized vessel for controlled crafting reactions.',
160
+ name: 'Reactor',
161
+ description:
162
+ 'Gas-pressurized vessel for controlled reactions. Vents heat and contains volatility.',
156
163
  color: '#B8E4A0',
157
164
  },
158
165
  10010: {
159
- name: 'Focusing Array',
166
+ name: 'Emitter',
160
167
  description:
161
- "Precision-formed crystal lens array. Routes the haul beam's energy efficiently to the target lock.",
168
+ 'Precision-formed crystal emitter array. Routes energy efficiently to a target lock.',
162
169
  color: '#4ADBFF',
163
170
  },
164
171
 
@@ -206,6 +213,12 @@ export const itemMetadata: Record<number, ItemMetadata> = {
206
213
  'Folds local space-time around the hull, projecting the ship across vast distances in a single discharge of the entire energy reserve.',
207
214
  color: '#9be4ff',
208
215
  },
216
+ 10108: {
217
+ name: 'Battery',
218
+ description:
219
+ 'Extends energy capacity. Stores additional charge produced by generators, letting builds chain more high-drain actions between recharges.',
220
+ color: '#4ADBFF',
221
+ },
209
222
 
210
223
  // === Entities (packed, T1) ===
211
224
  10200: {
@@ -237,14 +250,14 @@ export const itemMetadata: Record<number, ItemMetadata> = {
237
250
 
238
251
  // === Components (T2) ===
239
252
  20001: {
240
- name: 'Hull Plates',
253
+ name: 'Plate',
241
254
  description: 'Advanced structural plating reinforced with tier 2 ore.',
242
255
  color: '#9BADB8',
243
256
  },
244
257
  20002: {
245
- name: 'Cargo Lining',
258
+ name: 'Frame',
246
259
  description:
247
- 'Advanced composite lining reinforced with tier 2 regolith and biomass polymer.',
260
+ 'Advanced composite framing reinforced with tier 2 regolith and biomass polymer.',
248
261
  color: '#C4A57B',
249
262
  },
250
263
 
@@ -605,6 +605,55 @@
605
605
  1
606
606
  ]
607
607
  },
608
+ {
609
+ "outputItemId": 10108,
610
+ "outputMass": 90000,
611
+ "inputs": [
612
+ {
613
+ "itemId": 10003,
614
+ "quantity": 4
615
+ },
616
+ {
617
+ "itemId": 10007,
618
+ "quantity": 3
619
+ }
620
+ ],
621
+ "statSlots": [
622
+ {
623
+ "sources": [
624
+ {
625
+ "inputIndex": 0,
626
+ "statIndex": 0
627
+ }
628
+ ]
629
+ },
630
+ {
631
+ "sources": [
632
+ {
633
+ "inputIndex": 0,
634
+ "statIndex": 1
635
+ }
636
+ ]
637
+ },
638
+ {
639
+ "sources": [
640
+ {
641
+ "inputIndex": 1,
642
+ "statIndex": 0
643
+ }
644
+ ]
645
+ },
646
+ {
647
+ "sources": [
648
+ {
649
+ "inputIndex": 1,
650
+ "statIndex": 1
651
+ }
652
+ ]
653
+ }
654
+ ],
655
+ "blendWeights": []
656
+ },
608
657
  {
609
658
  "outputItemId": 10200,
610
659
  "outputMass": 80000,
@@ -75,18 +75,15 @@ export function computeGathererCapabilities(
75
75
  yield: number
76
76
  drain: number
77
77
  depth: number
78
- speed: number
79
78
  } {
80
79
  const str = stats.strength
81
80
  const con = stats.conductivity
82
- const ref = stats.reflectivity
83
81
  const tol = stats.tolerance
84
82
 
85
83
  return {
86
84
  yield: 200 + str,
87
85
  drain: Math.max(250, 1250 - Math.floor((con * 25) / 20)),
88
86
  depth: gathererDepthForTier(tol, tier),
89
- speed: 100 + Math.floor((ref * 4) / 5),
90
87
  }
91
88
  }
92
89
 
@@ -163,6 +160,7 @@ import {
163
160
  } from '../data/item-ids'
164
161
  import {
165
162
  getModuleCapabilityType,
163
+ MODULE_BATTERY,
166
164
  MODULE_ENGINE,
167
165
  MODULE_GENERATOR,
168
166
  MODULE_GATHERER,
@@ -222,7 +220,7 @@ export interface ComputedCapabilities {
222
220
  capacity: number
223
221
  engines?: {thrust: number; drain: number}
224
222
  generator?: {capacity: number; recharge: number}
225
- gatherer?: {yield: number; drain: number; depth: number; speed: number}
223
+ gatherer?: {yield: number; drain: number; depth: number}
226
224
  loaders?: {mass: number; thrust: number; quantity: number}
227
225
  crafter?: {speed: number; drain: number}
228
226
  hauler?: {capacity: number; efficiency: number; drain: number}
@@ -251,7 +249,6 @@ export function computeEntityCapabilities(
251
249
  let totalGathYield = 0
252
250
  let totalGathDrain = 0
253
251
  let maxGathDepth = 0
254
- let totalGathSpeed = 0
255
252
  let hasGatherer = false
256
253
 
257
254
  let totalStorageBonus = 0
@@ -270,6 +267,9 @@ export function computeEntityCapabilities(
270
267
  let totalWarpRange = 0
271
268
  let hasWarp = false
272
269
 
270
+ let totalBatteryStatSum = 0
271
+ let batteryCount = 0
272
+
273
273
  for (const mod of modules) {
274
274
  const item = getItem(mod.itemId)
275
275
  const modType = getModuleCapabilityType(mod.itemId)
@@ -294,7 +294,6 @@ export function computeEntityCapabilities(
294
294
  totalGathYield += applySlotMultiplier(caps.yield, amp)
295
295
  totalGathDrain += caps.drain
296
296
  if (caps.depth > maxGathDepth) maxGathDepth = caps.depth
297
- totalGathSpeed += applySlotMultiplier(caps.speed, amp)
298
297
  } else if (modType === MODULE_LOADER) {
299
298
  hasLoader = true
300
299
  const caps = computeLoaderCapabilities(decodedStats)
@@ -320,9 +319,22 @@ export function computeEntityCapabilities(
320
319
  hasWarp = true
321
320
  const caps = computeWarpCapabilities(decodedStats)
322
321
  totalWarpRange += applySlotMultiplier(caps.range, amp)
322
+ } else if (modType === MODULE_BATTERY) {
323
+ batteryCount++
324
+ const vol = decodedStats.volatility ?? 0
325
+ const thm = decodedStats.thermal ?? 0
326
+ const pla = decodedStats.plasticity ?? 0
327
+ const ins = decodedStats.insulation ?? 0
328
+ totalBatteryStatSum += vol + thm + pla + ins
323
329
  }
324
330
  }
325
331
 
332
+ if (hasGenerator && batteryCount > 0) {
333
+ const genCapBase = totalGenCapacity
334
+ const bonusPctNum = 10 * batteryCount + Math.floor((totalBatteryStatSum * 10) / 2997)
335
+ totalGenCapacity += Math.floor((genCapBase * bonusPctNum) / 100)
336
+ }
337
+
326
338
  const result: ComputedCapabilities = {
327
339
  hullmass: computeBaseHullmass(stats) + installedModuleMass,
328
340
  capacity: baseCapacity + totalStorageBonus,
@@ -342,7 +354,6 @@ export function computeEntityCapabilities(
342
354
  yield: clampUint16(totalGathYield),
343
355
  drain: totalGathDrain,
344
356
  depth: maxGathDepth,
345
- speed: clampUint16(totalGathSpeed),
346
357
  }
347
358
  }
348
359
  if (hasLoader) {
@@ -16,6 +16,7 @@ import {
16
16
  ITEM_STORAGE_T1,
17
17
  ITEM_HAULER_T1,
18
18
  ITEM_WARP_T1,
19
+ ITEM_BATTERY_T1,
19
20
  ITEM_SHIP_T1_PACKED,
20
21
  ITEM_CONTAINER_T1_PACKED,
21
22
  ITEM_WAREHOUSE_T1_PACKED,
@@ -32,6 +33,7 @@ export const KIND_TO_ITEM_ID: Record<SlotConsumerKind, number> = {
32
33
  storage: ITEM_STORAGE_T1,
33
34
  hauler: ITEM_HAULER_T1,
34
35
  warp: ITEM_WARP_T1,
36
+ battery: ITEM_BATTERY_T1,
35
37
  'ship-t1': ITEM_SHIP_T1_PACKED,
36
38
  'container-t1': ITEM_CONTAINER_T1_PACKED,
37
39
  'warehouse-t1': ITEM_WAREHOUSE_T1_PACKED,
@@ -76,15 +76,11 @@ export function deriveStratum(
76
76
  (BigInt(bytes[14]) << 8n) |
77
77
  BigInt(bytes[15])
78
78
 
79
- const rawRichness = (bytes[16] << 8) | bytes[17]
80
- const normalized = rawRichness / 65535
81
- const baseRichness = Math.floor(normalized * normalized * 999) + 1
82
-
83
- let depthBonus = 0
84
- if (stratum > 1) {
85
- depthBonus = (50 * Math.log(stratum)) / Math.log(65535)
86
- }
87
- const richness = Math.min(Math.floor(baseRichness + depthBonus), 1000)
79
+ let byteSum = 0
80
+ for (let i = 22; i <= 33; i++) byteSum += bytes[i]
81
+ const z = (byteSum - 1530) / 256
82
+ const roll = 500 + 100 * z
83
+ const richness = Math.max(1, Math.min(999, Math.round(roll)))
88
84
 
89
85
  return {itemId: selectedItemId, seed: seedBigInt, richness, reserve}
90
86
  }
@@ -47,8 +47,9 @@ export {
47
47
  LocationsManager,
48
48
  EpochsManager,
49
49
  ActionsManager,
50
+ NftManager,
50
51
  } from './managers'
51
- export type {LocationStratum} from './managers'
52
+ export type {LocationStratum, NftConfigForItem} from './managers'
52
53
  export type {EntityRefInput} from './managers/actions'
53
54
 
54
55
  export {
@@ -331,10 +332,25 @@ export type {
331
332
  export {deserializeAtomicData} from './nft/atomicdata'
332
333
  export type {SchemaField, RawData} from './nft/atomicdata'
333
334
 
335
+ export {
336
+ buildImmutableData,
337
+ buildResourceImmutable,
338
+ buildComponentImmutable,
339
+ buildModuleImmutable,
340
+ buildEntityImmutable,
341
+ computeNftImageUrl,
342
+ } from './nft/buildImmutableData'
343
+ export type {
344
+ AtomicAttributeType,
345
+ ImmutableEntry,
346
+ ImmutableModuleSlot,
347
+ } from './nft/buildImmutableData'
348
+
334
349
  export {
335
350
  fetchAtomicAssetsForOwner,
336
351
  fetchAtomicSchemas,
337
352
  decodeAtomicAsset,
353
+ buildMintAssetAction,
338
354
  ATOMICASSETS_ACCOUNT,
339
355
  SHIPLOAD_COLLECTION,
340
356
  } from './nft/atomicassets'
@@ -343,6 +359,7 @@ export type {
343
359
  AtomicSchemaRow,
344
360
  DecodedAtomicAsset,
345
361
  FetchAssetsOptions,
362
+ MintAssetParams,
346
363
  } from './nft/atomicassets'
347
364
 
348
365
  export {
@@ -360,7 +377,6 @@ export {
360
377
  computeGathererYield,
361
378
  computeGathererDrain,
362
379
  computeGathererDepth,
363
- computeGathererSpeed,
364
380
  computeLoaderMass,
365
381
  computeLoaderThrust,
366
382
  computeCrafterSpeed,
@@ -13,6 +13,12 @@ import {
13
13
  import {BaseManager} from './base'
14
14
  import type {CoordinatesType} from '../types'
15
15
  import {ServerContract} from '../contracts'
16
+ import {
17
+ buildImmutableData,
18
+ type ImmutableModuleSlot,
19
+ moduleSlotsForImmutable,
20
+ } from '../nft/buildImmutableData'
21
+ import {buildMintAssetAction, SHIPLOAD_COLLECTION} from '../nft/atomicassets'
16
22
 
17
23
  export type EntityRefInput = {
18
24
  entityType: NameType
@@ -183,18 +189,81 @@ export class ActionsManager extends BaseManager {
183
189
  })
184
190
  }
185
191
 
186
- wrap(
192
+ private async buildPairedMintAction(args: {
193
+ owner: NameType
194
+ itemId: number
195
+ quantity: number
196
+ stats: bigint
197
+ originX: number
198
+ originY: number
199
+ moduleSlots: ImmutableModuleSlot[]
200
+ }): Promise<Action> {
201
+ const nftCfg = await this.context.nft.getNftConfigForItem(args.itemId)
202
+ if (!nftCfg) {
203
+ throw new Error(`item ${args.itemId} has no nftconfig`)
204
+ }
205
+ const immutableData = buildImmutableData(
206
+ args.itemId,
207
+ args.quantity,
208
+ args.stats,
209
+ args.originX,
210
+ args.originY,
211
+ args.moduleSlots
212
+ )
213
+ return buildMintAssetAction({
214
+ authorizedMinter: Name.from(args.owner),
215
+ collectionName: SHIPLOAD_COLLECTION,
216
+ schemaName: nftCfg.schemaName,
217
+ templateId: nftCfg.templateId,
218
+ newAssetOwner: Name.from(args.owner),
219
+ immutableData,
220
+ })
221
+ }
222
+
223
+ async wrap(
187
224
  owner: NameType,
188
225
  entityId: UInt64Type,
189
226
  nexusId: UInt64Type,
190
- items: ServerContract.ActionParams.Type.cargo_item[]
191
- ): Action {
192
- return this.server.action('wrap', {
193
- owner: Name.from(owner),
194
- entity_id: UInt64.from(entityId),
195
- nexus_id: UInt64.from(nexusId),
196
- items,
227
+ cargoId: UInt64Type,
228
+ quantity: UInt64Type
229
+ ): Promise<Action[]> {
230
+ const cargoIdKey = UInt64.from(cargoId)
231
+ const entityIdKey = UInt64.from(entityId)
232
+ const [cargoRow, entityRow] = (await Promise.all([
233
+ this.server.table('cargo').get(cargoIdKey),
234
+ this.server.table('entity').get(entityIdKey),
235
+ ])) as [
236
+ ServerContract.Types.cargo_row | undefined,
237
+ ServerContract.Types.entity_row | undefined,
238
+ ]
239
+ if (!cargoRow) {
240
+ throw new Error(`cargo row ${cargoIdKey} not found`)
241
+ }
242
+ if (!entityRow) {
243
+ throw new Error(`entity ${entityIdKey} not found`)
244
+ }
245
+
246
+ const quantityValue = UInt64.from(quantity)
247
+ const mintAction = await this.buildPairedMintAction({
248
+ owner,
249
+ itemId: Number(cargoRow.item_id.toString()),
250
+ quantity: Number(quantityValue.toString()),
251
+ stats: BigInt(cargoRow.stats.toString()),
252
+ originX: Number(entityRow.coordinates.x.toString()),
253
+ originY: Number(entityRow.coordinates.y.toString()),
254
+ moduleSlots: moduleSlotsForImmutable(cargoRow.modules),
197
255
  })
256
+
257
+ return [
258
+ this.server.action('wrap', {
259
+ owner: Name.from(owner),
260
+ entity_id: UInt64.from(entityId),
261
+ nexus_id: UInt64.from(nexusId),
262
+ cargo_id: cargoIdKey,
263
+ quantity: quantityValue,
264
+ }),
265
+ mintAction,
266
+ ]
198
267
  }
199
268
 
200
269
  undeploy(hostId: UInt64Type, targetId: UInt64Type): Action {
@@ -204,11 +273,54 @@ export class ActionsManager extends BaseManager {
204
273
  })
205
274
  }
206
275
 
207
- wrapEntity(entityId: UInt64Type, nexusId: UInt64Type): Action {
208
- return this.server.action('wrapentity', {
209
- entity_id: UInt64.from(entityId),
210
- nexus_id: UInt64.from(nexusId),
276
+ async wrapEntity(
277
+ owner: NameType,
278
+ entityId: UInt64Type,
279
+ nexusId: UInt64Type
280
+ ): Promise<Action[]> {
281
+ const entityIdKey = UInt64.from(entityId)
282
+ const entityRow = (await this.server.table('entity').get(entityIdKey)) as
283
+ | ServerContract.Types.entity_row
284
+ | undefined
285
+ if (!entityRow) {
286
+ throw new Error(`entity ${entityIdKey} not found`)
287
+ }
288
+
289
+ const mintAction = await this.buildPairedMintAction({
290
+ owner,
291
+ itemId: Number(entityRow.item_id.toString()),
292
+ quantity: 1,
293
+ stats: BigInt(entityRow.stats.toString()),
294
+ originX: Number(entityRow.coordinates.x.toString()),
295
+ originY: Number(entityRow.coordinates.y.toString()),
296
+ moduleSlots: moduleSlotsForImmutable(entityRow.modules),
211
297
  })
298
+
299
+ return [
300
+ this.server.action('wrapentity', {
301
+ entity_id: entityIdKey,
302
+ nexus_id: UInt64.from(nexusId),
303
+ }),
304
+ mintAction,
305
+ ]
306
+ }
307
+
308
+ deploynft(owner: NameType, assetId: UInt64Type, targetNexusId: UInt64Type): Action {
309
+ const params: ServerContract.ActionParams.deploynft = {
310
+ owner: Name.from(owner),
311
+ asset_id: UInt64.from(assetId),
312
+ target_nexus_id: UInt64.from(targetNexusId),
313
+ }
314
+ return this.server.action('deploynft', params)
315
+ }
316
+
317
+ unwrapnft(owner: NameType, assetId: UInt64Type, hostId: UInt64Type): Action {
318
+ const params: ServerContract.ActionParams.unwrapnft = {
319
+ owner: Name.from(owner),
320
+ asset_id: UInt64.from(assetId),
321
+ host_id: UInt64.from(hostId),
322
+ }
323
+ return this.server.action('unwrapnft', params)
212
324
  }
213
325
 
214
326
  demolish(entityId: UInt64Type): Action {