@shipload/sdk 1.0.0-next.6 → 1.0.0-next.61

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 (156) hide show
  1. package/lib/scan.d.ts +52 -0
  2. package/lib/scan.js +162 -0
  3. package/lib/scan.js.map +1 -0
  4. package/lib/scan.m.js +152 -0
  5. package/lib/scan.m.js.map +1 -0
  6. package/lib/shipload.d.ts +3601 -1364
  7. package/lib/shipload.js +15671 -5261
  8. package/lib/shipload.js.map +1 -1
  9. package/lib/shipload.m.js +15392 -5209
  10. package/lib/shipload.m.js.map +1 -1
  11. package/lib/testing.d.ts +1173 -0
  12. package/lib/testing.js +4971 -0
  13. package/lib/testing.js.map +1 -0
  14. package/lib/testing.m.js +4965 -0
  15. package/lib/testing.m.js.map +1 -0
  16. package/package.json +20 -2
  17. package/src/capabilities/craftable.test.ts +82 -0
  18. package/src/capabilities/craftable.ts +82 -0
  19. package/src/capabilities/crafting.test.ts +35 -0
  20. package/src/capabilities/crafting.ts +34 -7
  21. package/src/capabilities/gathering.test.ts +29 -0
  22. package/src/capabilities/gathering.ts +37 -19
  23. package/src/capabilities/hauling.ts +0 -5
  24. package/src/capabilities/index.ts +0 -1
  25. package/src/capabilities/modules.ts +27 -30
  26. package/src/capabilities/movement.ts +1 -1
  27. package/src/capabilities/storage.ts +16 -1
  28. package/src/contracts/platform.ts +231 -3
  29. package/src/contracts/server.ts +1518 -501
  30. package/src/coordinates/address.ts +88 -0
  31. package/src/coordinates/constants.test.ts +15 -0
  32. package/src/coordinates/constants.ts +23 -0
  33. package/src/coordinates/index.ts +15 -0
  34. package/src/coordinates/memo.test.ts +47 -0
  35. package/src/coordinates/memo.ts +20 -0
  36. package/src/coordinates/permutation.ts +77 -0
  37. package/src/coordinates/regions.ts +48 -0
  38. package/src/coordinates/sectors.ts +115 -0
  39. package/src/data/capabilities.ts +49 -18
  40. package/src/data/capability-formulas.ts +26 -14
  41. package/src/data/catalog.ts +7 -8
  42. package/src/data/colors.ts +14 -48
  43. package/src/data/entities.json +380 -15
  44. package/src/data/item-ids.ts +51 -13
  45. package/src/data/items.json +318 -77
  46. package/src/data/kind-registry.json +195 -0
  47. package/src/data/kind-registry.ts +182 -0
  48. package/src/data/metadata.ts +291 -51
  49. package/src/data/recipes-runtime.ts +6 -23
  50. package/src/data/recipes.json +2260 -173
  51. package/src/data/tiers.ts +9 -6
  52. package/src/derivation/build-methods.test.ts +13 -0
  53. package/src/derivation/build-methods.ts +48 -0
  54. package/src/derivation/capabilities.test.ts +348 -0
  55. package/src/derivation/capabilities.ts +693 -0
  56. package/src/derivation/capability-mappings.ts +60 -16
  57. package/src/derivation/crafting.test.ts +17 -0
  58. package/src/derivation/crafting.ts +57 -34
  59. package/src/derivation/index.ts +27 -2
  60. package/src/derivation/recipe-usage.test.ts +90 -0
  61. package/src/derivation/recipe-usage.ts +141 -0
  62. package/src/derivation/reserve-regen.ts +34 -0
  63. package/src/derivation/resources.ts +9 -1
  64. package/src/derivation/rollups.test.ts +55 -0
  65. package/src/derivation/rollups.ts +72 -0
  66. package/src/derivation/stars.test.ts +67 -0
  67. package/src/derivation/stars.ts +25 -0
  68. package/src/derivation/stat-scaling.ts +12 -0
  69. package/src/derivation/stats.ts +6 -6
  70. package/src/derivation/stratum.ts +26 -22
  71. package/src/derivation/tiers.ts +40 -7
  72. package/src/derivation/upgrades.ts +14 -0
  73. package/src/derivation/wormhole.ts +154 -0
  74. package/src/entities/entity.ts +102 -0
  75. package/src/entities/gamestate.ts +3 -28
  76. package/src/entities/makers.ts +141 -135
  77. package/src/entities/slot-multiplier.ts +43 -0
  78. package/src/errors.ts +12 -16
  79. package/src/format.ts +26 -4
  80. package/src/index-module.ts +333 -35
  81. package/src/managers/actions.ts +668 -103
  82. package/src/managers/base.ts +6 -2
  83. package/src/managers/cluster.test.ts +39 -0
  84. package/src/managers/cluster.ts +53 -0
  85. package/src/managers/construction-types.ts +80 -0
  86. package/src/managers/construction.ts +443 -0
  87. package/src/managers/context.ts +29 -1
  88. package/src/managers/coordinates.ts +14 -0
  89. package/src/managers/entities.ts +27 -66
  90. package/src/managers/epochs.ts +40 -0
  91. package/src/managers/index.ts +20 -1
  92. package/src/managers/locations.ts +25 -29
  93. package/src/managers/nft.test.ts +14 -0
  94. package/src/managers/nft.ts +70 -0
  95. package/src/managers/players.ts +25 -0
  96. package/src/managers/plot.ts +122 -0
  97. package/src/nft/atomicassets.abi.json +1342 -0
  98. package/src/nft/atomicassets.ts +237 -0
  99. package/src/nft/atomicdata.ts +130 -0
  100. package/src/nft/buildImmutableData.ts +388 -0
  101. package/src/nft/description.ts +215 -99
  102. package/src/nft/index.ts +3 -0
  103. package/src/planner/index.ts +242 -0
  104. package/src/planner/planner.test.ts +334 -0
  105. package/src/resolution/describe-module.ts +43 -25
  106. package/src/resolution/display-name.ts +38 -10
  107. package/src/resolution/resolve-item.test.ts +48 -0
  108. package/src/resolution/resolve-item.ts +112 -58
  109. package/src/scan/index.ts +244 -0
  110. package/src/scan/scan-wasm.base64.ts +2 -0
  111. package/src/scheduling/accessor.ts +65 -23
  112. package/src/scheduling/availability.test.ts +204 -0
  113. package/src/scheduling/availability.ts +211 -0
  114. package/src/scheduling/cancel.test.ts +542 -0
  115. package/src/scheduling/cancel.ts +254 -0
  116. package/src/scheduling/cluster-stock.test.ts +31 -0
  117. package/src/scheduling/cluster-stock.ts +15 -0
  118. package/src/scheduling/energy.ts +47 -0
  119. package/src/scheduling/idle-resolve.ts +45 -0
  120. package/src/scheduling/jobs.ts +71 -0
  121. package/src/scheduling/lane-core.ts +128 -0
  122. package/src/scheduling/lanes.test.ts +250 -0
  123. package/src/scheduling/lanes.ts +227 -0
  124. package/src/scheduling/projection.ts +257 -133
  125. package/src/scheduling/schedule.test.ts +119 -0
  126. package/src/scheduling/schedule.ts +257 -117
  127. package/src/scheduling/task-cargo.test.ts +44 -0
  128. package/src/scheduling/task-cargo.ts +46 -0
  129. package/src/scheduling/unwrap.test.ts +86 -0
  130. package/src/scheduling/unwrap.ts +190 -0
  131. package/src/shipload.ts +26 -1
  132. package/src/subscriptions/manager.cluster.test.ts +51 -0
  133. package/src/subscriptions/manager.ts +245 -172
  134. package/src/subscriptions/mappers.ts +5 -8
  135. package/src/subscriptions/types.ts +28 -3
  136. package/src/testing/catalog-hash.ts +19 -0
  137. package/src/testing/index.ts +2 -0
  138. package/src/testing/projection-parity.ts +167 -0
  139. package/src/travel/reach.ts +21 -0
  140. package/src/travel/route-planner.ts +288 -0
  141. package/src/travel/route-simulator.ts +170 -0
  142. package/src/travel/travel.ts +188 -122
  143. package/src/types/capabilities.ts +37 -8
  144. package/src/types/entity.ts +3 -3
  145. package/src/types/index.ts +0 -1
  146. package/src/types.ts +51 -16
  147. package/src/utils/cargo.test.ts +14 -0
  148. package/src/utils/cargo.ts +29 -0
  149. package/src/utils/display-name.ts +70 -0
  150. package/src/utils/system.ts +15 -16
  151. package/src/capabilities/loading.ts +0 -8
  152. package/src/entities/container.ts +0 -123
  153. package/src/entities/ship-deploy.ts +0 -295
  154. package/src/entities/ship.ts +0 -221
  155. package/src/entities/warehouse.ts +0 -127
  156. package/src/types/entity-traits.ts +0 -69
@@ -0,0 +1,388 @@
1
+ import {Serializer} from '@wharfkit/antelope'
2
+ import {getItem} from '../data/catalog'
3
+ import {
4
+ getModuleCapabilityType,
5
+ MODULE_BATTERY,
6
+ MODULE_BUILDER,
7
+ MODULE_CRAFTER,
8
+ MODULE_ENGINE,
9
+ MODULE_GATHERER,
10
+ MODULE_GENERATOR,
11
+ MODULE_HAULER,
12
+ MODULE_LOADER,
13
+ MODULE_STORAGE,
14
+ MODULE_WARP,
15
+ } from '../capabilities/modules'
16
+ import {decodeStat, decodeCraftedItemStats} from '../derivation/crafting'
17
+ import {computeGathererYield} from '../derivation/capabilities'
18
+ import {computeEffectiveModuleStat} from '../derivation/stat-scaling'
19
+ import {getStatDefinitions} from '../derivation/stats'
20
+ import type {ResourceCategory} from '../types'
21
+ import {Types as ServerTypes} from '../contracts/server'
22
+ import {
23
+ buildEntityDescription,
24
+ computeBuilderDrain,
25
+ computeBuilderSpeed,
26
+ computeCrafterDrain,
27
+ computeCrafterSpeed,
28
+ computeEngineDrain,
29
+ computeEngineThrust,
30
+ computeGathererDepth,
31
+ computeGathererDrain,
32
+ computeGeneratorCap,
33
+ computeGeneratorRech,
34
+ computeCargoBayCapacity,
35
+ computeCargoBayDrain,
36
+ computeBatteryBankCapacity,
37
+ computeHaulerCapacity,
38
+ computeHaulerDrain,
39
+ computeHaulerEfficiency,
40
+ computeLoaderMass,
41
+ computeLoaderThrust,
42
+ computeWarpRange,
43
+ } from './description'
44
+
45
+ export type AtomicAttributeType =
46
+ | 'string'
47
+ | 'uint8'
48
+ | 'uint16'
49
+ | 'uint32'
50
+ | 'uint64'
51
+ | 'int32'
52
+ | 'image'
53
+ | 'ipfs'
54
+ | 'UINT16_VEC'
55
+ | 'UINT64_VEC'
56
+
57
+ export interface ImmutableEntry {
58
+ first: string
59
+ second: [AtomicAttributeType, unknown]
60
+ }
61
+
62
+ export interface ImmutableModuleSlot {
63
+ type?: number | string | bigint
64
+ installed?: {item_id: number | string | bigint; stats: number | string | bigint}
65
+ }
66
+
67
+ export function moduleSlotsForImmutable(
68
+ modules: ServerTypes.module_entry[]
69
+ ): ImmutableModuleSlot[] {
70
+ return modules.map((m) => ({
71
+ type: Number(m.type.toString()),
72
+ installed: m.installed
73
+ ? {
74
+ item_id: Number(m.installed.item_id.toString()),
75
+ stats: BigInt(m.installed.stats.toString()),
76
+ }
77
+ : undefined,
78
+ }))
79
+ }
80
+
81
+ const IMAGE_HOST_URL = 'https://item.shiploadgame.com/item'
82
+
83
+ function toWholeEnergy(milli: number): number {
84
+ return Math.floor((milli + 500) / 1000)
85
+ }
86
+
87
+ function bytesToBase64Url(bytes: Uint8Array): string {
88
+ let binary = ''
89
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]!)
90
+ const b64 = btoa(binary)
91
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
92
+ }
93
+
94
+ export function computeNftImageUrl(
95
+ item: {item_id: number; stats: bigint; modules: ImmutableModuleSlot[]; quantity: number},
96
+ originX: number,
97
+ originY: number
98
+ ): string {
99
+ const payload = ServerTypes.nft_item_payload.from({
100
+ item: {
101
+ item_id: item.item_id,
102
+ stats: String(item.stats),
103
+ modules: item.modules,
104
+ quantity: item.quantity,
105
+ },
106
+ location: {x: String(originX), y: String(originY)},
107
+ })
108
+ const bytes = Serializer.encode({object: payload}).array
109
+ return `${IMAGE_HOST_URL}/${bytesToBase64Url(bytes)}.png`
110
+ }
111
+
112
+ function commonBaseImmutable(
113
+ quantity: number,
114
+ stats: bigint,
115
+ originX: number,
116
+ originY: number,
117
+ img: string
118
+ ): ImmutableEntry[] {
119
+ return [
120
+ {first: 'quantity', second: ['uint32', quantity]},
121
+ {first: 'stats', second: ['uint64', String(stats)]},
122
+ {first: 'origin_x', second: ['int32', originX]},
123
+ {first: 'origin_y', second: ['int32', originY]},
124
+ {first: 'img', second: ['string', img]},
125
+ {first: 'deposit_amount', second: ['uint64', '0']},
126
+ {first: 'deposit_token', second: ['uint64', '0']},
127
+ {first: 'deposit_symbol', second: ['uint64', '0']},
128
+ ]
129
+ }
130
+
131
+ export function buildResourceImmutable(
132
+ itemId: number,
133
+ quantity: number,
134
+ stats: bigint,
135
+ originX: number,
136
+ originY: number
137
+ ): ImmutableEntry[] {
138
+ const item = getItem(itemId)
139
+ const cat = item.category
140
+ if (!cat) throw new Error(`Resource item ${itemId} has no category`)
141
+ const definitions = getStatDefinitions(cat as ResourceCategory)
142
+ const img = computeNftImageUrl(
143
+ {item_id: itemId, stats, modules: [], quantity},
144
+ originX,
145
+ originY
146
+ )
147
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
148
+ base.push({first: definitions[0].key, second: ['uint16', decodeStat(stats, 0)]})
149
+ base.push({first: definitions[1].key, second: ['uint16', decodeStat(stats, 1)]})
150
+ base.push({first: definitions[2].key, second: ['uint16', decodeStat(stats, 2)]})
151
+ return base
152
+ }
153
+
154
+ export function buildComponentImmutable(
155
+ itemId: number,
156
+ quantity: number,
157
+ stats: bigint,
158
+ originX: number,
159
+ originY: number
160
+ ): ImmutableEntry[] {
161
+ const img = computeNftImageUrl(
162
+ {item_id: itemId, stats, modules: [], quantity},
163
+ originX,
164
+ originY
165
+ )
166
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
167
+ const decoded = decodeCraftedItemStats(itemId, stats)
168
+ for (const [key, value] of Object.entries(decoded)) {
169
+ base.push({first: key, second: ['uint16', value]})
170
+ }
171
+ return base
172
+ }
173
+
174
+ export function buildModuleImmutable(
175
+ itemId: number,
176
+ quantity: number,
177
+ stats: bigint,
178
+ originX: number,
179
+ originY: number
180
+ ): ImmutableEntry[] {
181
+ const img = computeNftImageUrl(
182
+ {item_id: itemId, stats, modules: [], quantity},
183
+ originX,
184
+ originY
185
+ )
186
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
187
+ const subtype = getModuleCapabilityType(itemId)
188
+ const item = getItem(itemId)
189
+ switch (subtype) {
190
+ case MODULE_ENGINE: {
191
+ const vol = decodeStat(stats, 0)
192
+ const thm = decodeStat(stats, 1)
193
+ base.push({first: 'volatility', second: ['uint16', vol]})
194
+ base.push({first: 'thermal', second: ['uint16', thm]})
195
+ base.push({
196
+ first: 'thrust',
197
+ second: ['uint32', computeEngineThrust(computeEffectiveModuleStat(vol), item.tier)],
198
+ })
199
+ base.push({
200
+ first: 'drain',
201
+ second: ['uint16', computeEngineDrain(computeEffectiveModuleStat(thm))],
202
+ })
203
+ break
204
+ }
205
+ case MODULE_GENERATOR: {
206
+ const res = decodeStat(stats, 0)
207
+ const ref = decodeStat(stats, 1)
208
+ base.push({first: 'resonance', second: ['uint16', res]})
209
+ base.push({first: 'reflectivity', second: ['uint16', ref]})
210
+ base.push({
211
+ first: 'capacity',
212
+ second: [
213
+ 'uint16',
214
+ toWholeEnergy(computeGeneratorCap(computeEffectiveModuleStat(res), item.tier)),
215
+ ],
216
+ })
217
+ base.push({
218
+ first: 'recharge',
219
+ second: [
220
+ 'uint16',
221
+ toWholeEnergy(computeGeneratorRech(computeEffectiveModuleStat(ref), item.tier)),
222
+ ],
223
+ })
224
+ break
225
+ }
226
+ case MODULE_GATHERER: {
227
+ const str = decodeStat(stats, 0)
228
+ const hrd = decodeStat(stats, 1)
229
+ const sat = decodeStat(stats, 2)
230
+ base.push({first: 'strength', second: ['uint16', str]})
231
+ base.push({first: 'hardness', second: ['uint16', hrd]})
232
+ base.push({first: 'saturation', second: ['uint16', sat]})
233
+ base.push({
234
+ first: 'yield',
235
+ second: ['uint16', computeGathererYield(str, item.tier)],
236
+ })
237
+ base.push({
238
+ first: 'drain',
239
+ second: ['uint16', toWholeEnergy(computeGathererDrain(sat))],
240
+ })
241
+ base.push({first: 'depth', second: ['uint16', computeGathererDepth(hrd, item.tier)]})
242
+ break
243
+ }
244
+ case MODULE_LOADER: {
245
+ const fin = decodeStat(stats, 0)
246
+ const pla = decodeStat(stats, 1)
247
+ base.push({first: 'fineness', second: ['uint16', fin]})
248
+ base.push({first: 'plasticity', second: ['uint16', pla]})
249
+ base.push({first: 'mass', second: ['uint32', computeLoaderMass(fin)]})
250
+ base.push({first: 'thrust', second: ['uint16', computeLoaderThrust(pla, item.tier)]})
251
+ break
252
+ }
253
+ case MODULE_WARP: {
254
+ const ref = decodeStat(stats, 0)
255
+ base.push({first: 'reflectivity', second: ['uint16', ref]})
256
+ base.push({first: 'range', second: ['uint32', computeWarpRange(ref, item.tier)]})
257
+ break
258
+ }
259
+ case MODULE_CRAFTER: {
260
+ const fin = decodeStat(stats, 0)
261
+ const con = decodeStat(stats, 1)
262
+ base.push({first: 'fineness', second: ['uint16', fin]})
263
+ base.push({first: 'conductivity', second: ['uint16', con]})
264
+ base.push({first: 'speed', second: ['uint16', computeCrafterSpeed(fin, item.tier)]})
265
+ base.push({first: 'drain', second: ['uint16', toWholeEnergy(computeCrafterDrain(con))]})
266
+ break
267
+ }
268
+ case MODULE_BUILDER: {
269
+ const res = decodeStat(stats, 0)
270
+ const fin = decodeStat(stats, 1)
271
+ base.push({first: 'resonance', second: ['uint16', res]})
272
+ base.push({first: 'fineness', second: ['uint16', fin]})
273
+ base.push({first: 'speed', second: ['uint16', computeBuilderSpeed(res, item.tier)]})
274
+ base.push({first: 'drain', second: ['uint16', toWholeEnergy(computeBuilderDrain(fin))]})
275
+ break
276
+ }
277
+ case MODULE_STORAGE: {
278
+ const str = decodeStat(stats, 0)
279
+ const den = decodeStat(stats, 1)
280
+ const hrd = decodeStat(stats, 2)
281
+ const com = decodeStat(stats, 3)
282
+ base.push({first: 'strength', second: ['uint16', str]})
283
+ base.push({first: 'density', second: ['uint16', den]})
284
+ base.push({first: 'hardness', second: ['uint16', hrd]})
285
+ base.push({first: 'cohesion', second: ['uint16', com]})
286
+ base.push({
287
+ first: 'capacity',
288
+ second: ['uint32', computeCargoBayCapacity(str, den, hrd, item.tier)],
289
+ })
290
+ base.push({
291
+ first: 'drain',
292
+ second: ['uint16', toWholeEnergy(computeCargoBayDrain(com, item.tier))],
293
+ })
294
+ break
295
+ }
296
+ case MODULE_BATTERY: {
297
+ const vol = decodeStat(stats, 0)
298
+ const thm = decodeStat(stats, 1)
299
+ const pla = decodeStat(stats, 2)
300
+ const ins = decodeStat(stats, 3)
301
+ base.push({first: 'volatility', second: ['uint16', vol]})
302
+ base.push({first: 'thermal', second: ['uint16', thm]})
303
+ base.push({first: 'plasticity', second: ['uint16', pla]})
304
+ base.push({first: 'insulation', second: ['uint16', ins]})
305
+ base.push({
306
+ first: 'capacity',
307
+ second: [
308
+ 'uint32',
309
+ toWholeEnergy(computeBatteryBankCapacity(vol, thm, pla, ins, item.tier)),
310
+ ],
311
+ })
312
+ break
313
+ }
314
+ case MODULE_HAULER: {
315
+ const res = decodeStat(stats, 0)
316
+ const pla = decodeStat(stats, 1)
317
+ const con = decodeStat(stats, 2)
318
+ base.push({first: 'resonance', second: ['uint16', res]})
319
+ base.push({first: 'plasticity', second: ['uint16', pla]})
320
+ base.push({first: 'conductivity', second: ['uint16', con]})
321
+ base.push({first: 'capacity', second: ['uint8', computeHaulerCapacity(res, item.tier)]})
322
+ base.push({first: 'efficiency', second: ['uint16', computeHaulerEfficiency(pla)]})
323
+ base.push({
324
+ first: 'drain',
325
+ second: ['uint16', toWholeEnergy(computeHaulerDrain(con, item.tier))],
326
+ })
327
+ break
328
+ }
329
+ }
330
+ return base
331
+ }
332
+
333
+ export function buildEntityImmutable(
334
+ itemId: number,
335
+ quantity: number,
336
+ stats: bigint,
337
+ originX: number,
338
+ originY: number,
339
+ modules: ImmutableModuleSlot[]
340
+ ): ImmutableEntry[] {
341
+ const moduleItems: number[] = []
342
+ const moduleStats: string[] = []
343
+ for (const m of modules) {
344
+ if (m.installed) {
345
+ moduleItems.push(Number(m.installed.item_id))
346
+ moduleStats.push(String(m.installed.stats))
347
+ } else {
348
+ moduleItems.push(0)
349
+ moduleStats.push('0')
350
+ }
351
+ }
352
+ const img = computeNftImageUrl({item_id: itemId, stats, modules, quantity}, originX, originY)
353
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
354
+ base.push({first: 'module_items', second: ['UINT16_VEC', moduleItems]})
355
+ base.push({first: 'module_stats', second: ['UINT64_VEC', moduleStats]})
356
+ const description = buildEntityDescription(
357
+ itemId,
358
+ stats,
359
+ moduleItems,
360
+ moduleStats.map((s) => BigInt(s))
361
+ )
362
+ base.push({first: 'description', second: ['string', description]})
363
+ return base
364
+ }
365
+
366
+ export function buildImmutableData(
367
+ itemId: number,
368
+ quantity: number,
369
+ stats: bigint,
370
+ originX: number,
371
+ originY: number,
372
+ modules: ImmutableModuleSlot[] = []
373
+ ): ImmutableEntry[] {
374
+ const item = getItem(itemId)
375
+ if (item.type === 'resource') {
376
+ return buildResourceImmutable(itemId, quantity, stats, originX, originY)
377
+ }
378
+ if (item.type === 'component') {
379
+ return buildComponentImmutable(itemId, quantity, stats, originX, originY)
380
+ }
381
+ if (item.type === 'module') {
382
+ return buildModuleImmutable(itemId, quantity, stats, originX, originY)
383
+ }
384
+ if (item.type === 'entity') {
385
+ return buildEntityImmutable(itemId, quantity, stats, originX, originY, modules)
386
+ }
387
+ throw new Error(`Unsupported item type for wrap: ${item.type}`)
388
+ }