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

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 (134) hide show
  1. package/lib/scan.d.ts +34 -0
  2. package/lib/scan.js +136 -0
  3. package/lib/scan.js.map +1 -0
  4. package/lib/scan.m.js +129 -0
  5. package/lib/scan.m.js.map +1 -0
  6. package/lib/shipload.d.ts +2473 -973
  7. package/lib/shipload.js +11529 -5211
  8. package/lib/shipload.js.map +1 -1
  9. package/lib/shipload.m.js +11338 -5162
  10. package/lib/shipload.m.js.map +1 -1
  11. package/lib/testing.d.ts +970 -0
  12. package/lib/testing.js +4013 -0
  13. package/lib/testing.js.map +1 -0
  14. package/lib/testing.m.js +4007 -0
  15. package/lib/testing.m.js.map +1 -0
  16. package/package.json +20 -2
  17. package/src/capabilities/craftable.ts +51 -0
  18. package/src/capabilities/crafting.test.ts +7 -0
  19. package/src/capabilities/crafting.ts +5 -6
  20. package/src/capabilities/gathering.test.ts +16 -0
  21. package/src/capabilities/gathering.ts +35 -18
  22. package/src/capabilities/index.ts +0 -1
  23. package/src/capabilities/modules.ts +9 -0
  24. package/src/capabilities/storage.ts +16 -1
  25. package/src/contracts/platform.ts +231 -3
  26. package/src/contracts/server.ts +1021 -481
  27. package/src/coordinates/address.ts +88 -0
  28. package/src/coordinates/constants.test.ts +15 -0
  29. package/src/coordinates/constants.ts +23 -0
  30. package/src/coordinates/index.ts +15 -0
  31. package/src/coordinates/memo.test.ts +47 -0
  32. package/src/coordinates/memo.ts +20 -0
  33. package/src/coordinates/permutation.ts +77 -0
  34. package/src/coordinates/regions.ts +48 -0
  35. package/src/coordinates/sectors.ts +115 -0
  36. package/src/data/capabilities.ts +12 -5
  37. package/src/data/capability-formulas.ts +14 -7
  38. package/src/data/catalog.ts +0 -5
  39. package/src/data/colors.ts +14 -47
  40. package/src/data/entities.json +76 -10
  41. package/src/data/item-ids.ts +18 -12
  42. package/src/data/items.json +321 -38
  43. package/src/data/kind-registry.json +109 -0
  44. package/src/data/kind-registry.ts +165 -0
  45. package/src/data/metadata.ts +119 -33
  46. package/src/data/recipes-runtime.ts +3 -23
  47. package/src/data/recipes.json +238 -117
  48. package/src/derivation/build-methods.ts +45 -0
  49. package/src/derivation/capabilities.test.ts +151 -0
  50. package/src/derivation/capabilities.ts +512 -0
  51. package/src/derivation/capability-mappings.ts +9 -12
  52. package/src/derivation/crafting.ts +23 -24
  53. package/src/derivation/index.ts +25 -2
  54. package/src/derivation/recipe-usage.test.ts +78 -0
  55. package/src/derivation/recipe-usage.ts +141 -0
  56. package/src/derivation/reserve-regen.ts +34 -0
  57. package/src/derivation/resources.ts +125 -38
  58. package/src/derivation/rollups.test.ts +55 -0
  59. package/src/derivation/rollups.ts +56 -0
  60. package/src/derivation/stars.test.ts +51 -0
  61. package/src/derivation/stars.ts +15 -0
  62. package/src/derivation/stats.ts +6 -6
  63. package/src/derivation/stratum.ts +17 -20
  64. package/src/derivation/tiers.ts +40 -7
  65. package/src/derivation/wormhole.ts +136 -0
  66. package/src/entities/entity.ts +98 -0
  67. package/src/entities/gamestate.ts +3 -28
  68. package/src/entities/makers.ts +124 -134
  69. package/src/entities/slot-multiplier.ts +43 -0
  70. package/src/errors.ts +12 -16
  71. package/src/format.ts +26 -4
  72. package/src/index-module.ts +267 -47
  73. package/src/managers/actions.ts +528 -95
  74. package/src/managers/base.ts +6 -2
  75. package/src/managers/construction-types.ts +80 -0
  76. package/src/managers/construction.ts +412 -0
  77. package/src/managers/context.ts +20 -1
  78. package/src/managers/coordinates.ts +14 -0
  79. package/src/managers/entities.ts +18 -66
  80. package/src/managers/epochs.ts +40 -0
  81. package/src/managers/index.ts +17 -1
  82. package/src/managers/locations.ts +25 -29
  83. package/src/managers/nft.test.ts +14 -0
  84. package/src/managers/nft.ts +70 -0
  85. package/src/managers/plot.ts +122 -0
  86. package/src/nft/atomicassets.abi.json +1342 -0
  87. package/src/nft/atomicassets.ts +237 -0
  88. package/src/nft/atomicdata.ts +130 -0
  89. package/src/nft/buildImmutableData.ts +338 -0
  90. package/src/nft/description.ts +98 -24
  91. package/src/nft/index.ts +3 -0
  92. package/src/planner/index.ts +127 -0
  93. package/src/planner/planner.test.ts +319 -0
  94. package/src/resolution/describe-module.ts +18 -13
  95. package/src/resolution/display-name.ts +38 -10
  96. package/src/resolution/resolve-item.test.ts +37 -0
  97. package/src/resolution/resolve-item.ts +55 -24
  98. package/src/scan/index.ts +180 -0
  99. package/src/scan/scan-wasm.base64.ts +2 -0
  100. package/src/scheduling/accessor.ts +68 -22
  101. package/src/scheduling/availability.ts +108 -0
  102. package/src/scheduling/cancel.test.ts +348 -0
  103. package/src/scheduling/cancel.ts +209 -0
  104. package/src/scheduling/energy.ts +47 -0
  105. package/src/scheduling/idle-resolve.ts +45 -0
  106. package/src/scheduling/lane-core.ts +128 -0
  107. package/src/scheduling/lanes.test.ts +249 -0
  108. package/src/scheduling/lanes.ts +198 -0
  109. package/src/scheduling/projection.ts +209 -105
  110. package/src/scheduling/schedule.ts +241 -104
  111. package/src/scheduling/task-cargo.ts +46 -0
  112. package/src/shipload.ts +21 -1
  113. package/src/subscriptions/manager.ts +229 -142
  114. package/src/subscriptions/mappers.ts +5 -8
  115. package/src/subscriptions/types.ts +11 -3
  116. package/src/testing/catalog-hash.ts +19 -0
  117. package/src/testing/index.ts +2 -0
  118. package/src/testing/projection-parity.ts +167 -0
  119. package/src/travel/reach.ts +23 -0
  120. package/src/travel/route-planner.ts +196 -0
  121. package/src/travel/travel.ts +200 -112
  122. package/src/types/capabilities.ts +29 -6
  123. package/src/types/entity.ts +3 -3
  124. package/src/types/index.ts +0 -1
  125. package/src/types.ts +28 -13
  126. package/src/utils/cargo.ts +27 -0
  127. package/src/utils/display-name.ts +70 -0
  128. package/src/utils/system.ts +36 -24
  129. package/src/capabilities/loading.ts +0 -8
  130. package/src/entities/container.ts +0 -108
  131. package/src/entities/ship-deploy.ts +0 -259
  132. package/src/entities/ship.ts +0 -204
  133. package/src/entities/warehouse.ts +0 -119
  134. package/src/types/entity-traits.ts +0 -69
@@ -53,25 +53,22 @@ const TEMPLATES: Record<string, TemplateSpec> = {
53
53
  gatherer: {
54
54
  id: 'module.gatherer.description',
55
55
  template:
56
- 'mines resources at {yield} speed to a max depth of {depth} with {speed} gather speed while draining {drain} energy per second',
56
+ 'mines resources at {yield} yield to a max depth of {depth} while draining {drain} energy per second',
57
57
  params: [
58
58
  ['yield', 'Yield'],
59
- ['drain', 'Drain'],
60
59
  ['depth', 'Depth'],
61
- ['speed', 'Speed'],
60
+ ['drain', 'Drain'],
62
61
  ],
63
- highlightKeys: ['yield', 'depth', 'speed', 'drain'],
62
+ highlightKeys: ['yield', 'depth', 'drain'],
64
63
  },
65
64
  loader: {
66
65
  id: 'module.loader.description',
67
- template:
68
- '{quantity} loader that generates {thrust} thrust with a weight of {mass} per unit',
66
+ template: 'generates {thrust} thrust with a weight of {mass} per unit',
69
67
  params: [
70
- ['quantity', 'Quantity'],
71
68
  ['thrust', 'Thrust'],
72
69
  ['mass', 'Mass'],
73
70
  ],
74
- highlightKeys: ['quantity', 'thrust', 'mass'],
71
+ highlightKeys: ['thrust', 'mass'],
75
72
  },
76
73
  crafter: {
77
74
  id: 'module.crafter.description',
@@ -84,9 +81,15 @@ const TEMPLATES: Record<string, TemplateSpec> = {
84
81
  },
85
82
  storage: {
86
83
  id: 'module.storage.description',
87
- template: 'boosts cargo capacity by {bonus}%',
88
- params: [['bonus', 'Capacity Bonus']],
89
- highlightKeys: ['bonus'],
84
+ template: 'adds {capacity} cargo capacity',
85
+ params: [['capacity', 'Cargo Capacity']],
86
+ highlightKeys: ['capacity'],
87
+ },
88
+ energy: {
89
+ id: 'module.energy-capacity.description',
90
+ template: 'adds {capacity} energy capacity',
91
+ params: [['capacity', 'Energy Capacity']],
92
+ highlightKeys: ['capacity'],
90
93
  },
91
94
  hauler: {
92
95
  id: 'module.hauler.description',
@@ -127,8 +130,10 @@ export function describeModuleForItem(resolved: ResolvedItem): ModuleDescription
127
130
  }
128
131
 
129
132
  export function describeModuleForSlot(slot: ResolvedModuleSlot): ModuleDescription | null {
130
- if (!slot.installed || !slot.name || !slot.attributes) return null
131
- return describeModule({capability: slot.name, attributes: slot.attributes})
133
+ if (!slot.installed || !slot.attributes) return null
134
+ const capability = slot.capability ?? slot.name
135
+ if (!capability) return null
136
+ return describeModule({capability, attributes: slot.attributes})
132
137
  }
133
138
 
134
139
  export function renderDescription(
@@ -1,22 +1,50 @@
1
1
  import type {ResolvedItem} from './resolve-item'
2
2
  import type {ResourceCategory} from '../types'
3
- import {CATEGORY_LABELS, TIER_ADJECTIVES} from '../types'
3
+ import {
4
+ CATEGORY_LABELS,
5
+ RESOURCE_TIER_ADJECTIVES,
6
+ COMPONENT_TIER_PREFIXES,
7
+ MODULE_TIER_PREFIXES,
8
+ } from '../types'
4
9
  import {formatMass as defaultFormatMass} from '../format'
5
10
 
6
- export interface DisplayNameInput {
7
- itemType: 'resource' | 'component' | 'module' | 'entity' | string
11
+ interface DisplayNameInputCommon {
8
12
  tier: number
9
13
  category?: ResourceCategory
10
14
  name: string
11
15
  }
12
16
 
13
- export function displayName(resolved: DisplayNameInput): string {
14
- if (resolved.itemType === 'resource') {
15
- const adj = TIER_ADJECTIVES[resolved.tier] ?? 'Unknown'
16
- const cat = resolved.category ? CATEGORY_LABELS[resolved.category] : 'Resource'
17
- return `${adj} ${cat}`
18
- }
19
- return resolved.name
17
+ export type DisplayNameInput =
18
+ | (DisplayNameInputCommon & {itemType: 'resource' | 'component' | 'module' | 'entity' | string})
19
+ | (DisplayNameInputCommon & {type: string})
20
+
21
+ function itemTypeOf(item: DisplayNameInput): string {
22
+ return 'itemType' in item ? item.itemType : item.type
23
+ }
24
+
25
+ function tierPrefix(item: DisplayNameInput): string | null {
26
+ const t = itemTypeOf(item)
27
+ if (t === 'resource') return RESOURCE_TIER_ADJECTIVES[item.tier] ?? null
28
+ if (t === 'component') return COMPONENT_TIER_PREFIXES[item.tier] ?? null
29
+ if (t === 'module') return MODULE_TIER_PREFIXES[item.tier] ?? null
30
+ return null
31
+ }
32
+
33
+ function rootName(item: DisplayNameInput): string {
34
+ if (itemTypeOf(item) !== 'resource') return item.name
35
+ return item.category ? CATEGORY_LABELS[item.category] : 'Resource'
36
+ }
37
+
38
+ // Tier-free display name: includes the resource tier adjective / component-module
39
+ // prefix, but no "(T#)" suffix. Use this when the tier is shown separately.
40
+ export function baseName(item: DisplayNameInput): string {
41
+ const prefix = tierPrefix(item)
42
+ const root = rootName(item)
43
+ return prefix ? `${prefix} ${root}` : root
44
+ }
45
+
46
+ export function displayName(item: DisplayNameInput): string {
47
+ return `${baseName(item)} (T${item.tier})`
20
48
  }
21
49
 
22
50
  export interface DescribeOptions {
@@ -0,0 +1,37 @@
1
+ import {expect, test} from 'bun:test'
2
+ import {UInt16, UInt64} from '@wharfkit/antelope'
3
+ import {resolveItem} from './resolve-item'
4
+ import {encodeStats} from '../derivation/crafting'
5
+ import {computeContainerCapabilities} from '../derivation/capabilities'
6
+ import {
7
+ ITEM_EXTRACTOR_T1_PACKED,
8
+ ITEM_FACTORY_T1_PACKED,
9
+ ITEM_MASS_DRIVER_T1_PACKED,
10
+ ITEM_MASS_CATCHER_T1_PACKED,
11
+ } from '../data/item-ids'
12
+
13
+ function hullStats(strength: number, density: number, hardness: number): UInt64 {
14
+ return UInt64.from(encodeStats([strength, density, hardness]).toString())
15
+ }
16
+
17
+ const CONTAINER_ENTITIES = [
18
+ ['factory', ITEM_FACTORY_T1_PACKED],
19
+ ['extractor', ITEM_EXTRACTOR_T1_PACKED],
20
+ ['mass driver', ITEM_MASS_DRIVER_T1_PACKED],
21
+ ['mass catcher', ITEM_MASS_CATCHER_T1_PACKED],
22
+ ] as const
23
+
24
+ for (const [label, itemId] of CONTAINER_ENTITIES) {
25
+ test(`resolveItem resolves ${label} hull capacity via container formula`, () => {
26
+ const stats = hullStats(300, 100, 400)
27
+ const resolved = resolveItem(UInt16.from(itemId), stats)
28
+ const hull = resolved.attributes?.find((g) => g.capability === 'Hull')
29
+ const capacity = hull?.attributes.find((a) => a.label === 'Capacity')?.value
30
+ const expected = computeContainerCapabilities({
31
+ strength: 300,
32
+ hardness: 400,
33
+ density: 100,
34
+ }).capacity
35
+ expect(capacity).toBe(expected)
36
+ })
37
+ }
@@ -9,6 +9,7 @@ import {
9
9
  isModuleItem,
10
10
  MODULE_CRAFTER,
11
11
  MODULE_ENGINE,
12
+ MODULE_BATTERY,
12
13
  MODULE_GATHERER,
13
14
  MODULE_GENERATOR,
14
15
  MODULE_HAULER,
@@ -19,6 +20,7 @@ import {decodeCraftedItemStats, decodeStat} from '../derivation/crafting'
19
20
  import {getStatDefinitions} from '../derivation/stats'
20
21
  import {
21
22
  computeCrafterCapabilities,
23
+ computeBatteryCapabilities,
22
24
  computeEngineCapabilities,
23
25
  computeGathererCapabilities,
24
26
  computeGeneratorCapabilities,
@@ -26,19 +28,20 @@ import {
26
28
  computeLoaderCapabilities,
27
29
  computeShipHullCapabilities,
28
30
  computeWarehouseHullCapabilities,
29
- } from '../entities/ship-deploy'
30
- import {computeContainerCapabilities, computeContainerT2Capabilities} from '../entities/container'
31
- import {
32
- categoryColors,
33
- categoryIcons,
34
- componentIcon,
35
- itemAbbreviations,
36
- moduleIcon,
37
- } from '../data/colors'
31
+ computeContainerCapabilities,
32
+ computeContainerT2Capabilities,
33
+ computeStorageCapabilities,
34
+ } from '../derivation/capabilities'
35
+ import {applySlotMultiplierUint32} from '../entities/slot-multiplier'
36
+ import {categoryColors, componentIcon, itemAbbreviations, moduleIcon} from '../data/colors'
38
37
  import type {ServerContract} from '../contracts'
39
38
  import {
40
39
  ITEM_CONTAINER_T1_PACKED,
41
40
  ITEM_CONTAINER_T2_PACKED,
41
+ ITEM_EXTRACTOR_T1_PACKED,
42
+ ITEM_FACTORY_T1_PACKED,
43
+ ITEM_MASS_CATCHER_T1_PACKED,
44
+ ITEM_MASS_DRIVER_T1_PACKED,
42
45
  ITEM_SHIP_T1_PACKED,
43
46
  ITEM_WAREHOUSE_T1_PACKED,
44
47
  } from '../data/item-ids'
@@ -62,6 +65,7 @@ export type ResolvedItemType = 'resource' | 'component' | 'module' | 'entity'
62
65
 
63
66
  export interface ResolvedModuleSlot {
64
67
  name?: string
68
+ capability?: string
65
69
  installed: boolean
66
70
  attributes?: {label: string; value: number}[]
67
71
  }
@@ -109,7 +113,7 @@ function resolveResource(id: number, stats?: UInt64Type): ResolvedItem {
109
113
  return {
110
114
  itemId: id,
111
115
  name: item.name,
112
- icon: cat ? categoryIcons[cat] : '',
116
+ icon: '',
113
117
  abbreviation: null,
114
118
  category: cat,
115
119
  tier: item.tier,
@@ -155,7 +159,9 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
155
159
 
156
160
  function computeCapabilityGroup(
157
161
  moduleType: number,
158
- stats: Record<string, number>
162
+ stats: Record<string, number>,
163
+ tier: number,
164
+ outputPct = 100
159
165
  ): ResolvedAttributeGroup | undefined {
160
166
  switch (moduleType) {
161
167
  case MODULE_ENGINE: {
@@ -179,14 +185,13 @@ function computeCapabilityGroup(
179
185
  }
180
186
  }
181
187
  case MODULE_GATHERER: {
182
- const caps = computeGathererCapabilities(stats)
188
+ const caps = computeGathererCapabilities(stats, tier)
183
189
  return {
184
190
  capability: 'Gatherer',
185
191
  attributes: [
186
192
  {label: 'Yield', value: caps.yield},
187
193
  {label: 'Drain', value: caps.drain},
188
194
  {label: 'Depth', value: caps.depth},
189
- {label: 'Speed', value: caps.speed},
190
195
  ],
191
196
  }
192
197
  }
@@ -223,13 +228,28 @@ function computeCapabilityGroup(
223
228
  }
224
229
  }
225
230
  case MODULE_STORAGE: {
226
- const str = stats.strength
227
- const den = stats.density
228
- const hrd = stats.hardness
229
- const sat = stats.saturation
230
- const statSum = str + den + hrd + sat
231
- const pct = 10 + Math.floor((statSum * 10) / 2997)
232
- return {capability: 'Storage', attributes: [{label: 'Capacity Bonus', value: pct}]}
231
+ const caps = computeStorageCapabilities(stats)
232
+ return {
233
+ capability: 'Storage',
234
+ attributes: [
235
+ {
236
+ label: 'Cargo Capacity',
237
+ value: applySlotMultiplierUint32(caps.capacity, outputPct),
238
+ },
239
+ ],
240
+ }
241
+ }
242
+ case MODULE_BATTERY: {
243
+ const caps = computeBatteryCapabilities(stats)
244
+ return {
245
+ capability: 'Energy',
246
+ attributes: [
247
+ {
248
+ label: 'Energy Capacity',
249
+ value: applySlotMultiplierUint32(caps.capacity, outputPct),
250
+ },
251
+ ],
252
+ }
233
253
  }
234
254
  default:
235
255
  return undefined
@@ -242,7 +262,7 @@ function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
242
262
  if (stats !== undefined) {
243
263
  const decoded = decodeCraftedItemStats(id, toBigStats(stats))
244
264
  const modType = getModuleCapabilityType(id)
245
- const group = computeCapabilityGroup(modType, decoded)
265
+ const group = computeCapabilityGroup(modType, decoded, item.tier)
246
266
  if (group) attributes = [group]
247
267
  }
248
268
  return {
@@ -269,6 +289,10 @@ function hullCapsForEntity(
269
289
  return computeShipHullCapabilities(decoded)
270
290
  case ITEM_WAREHOUSE_T1_PACKED:
271
291
  return computeWarehouseHullCapabilities(decoded)
292
+ case ITEM_EXTRACTOR_T1_PACKED:
293
+ case ITEM_FACTORY_T1_PACKED:
294
+ case ITEM_MASS_DRIVER_T1_PACKED:
295
+ case ITEM_MASS_CATCHER_T1_PACKED:
272
296
  case ITEM_CONTAINER_T1_PACKED:
273
297
  return computeContainerCapabilities(decoded)
274
298
  case ITEM_CONTAINER_T2_PACKED:
@@ -289,7 +313,10 @@ function resolveEntity(
289
313
  let moduleSlots: ResolvedModuleSlot[] | undefined
290
314
 
291
315
  if (stats !== undefined) {
292
- const decoded = decodeCraftedItemStats(id, toBigStats(stats))
316
+ const bigStats = toBigStats(stats)
317
+ const decoded = decodeCraftedItemStats(id, bigStats)
318
+ if (decoded.strength === undefined) decoded.strength = decodeStat(bigStats, 0)
319
+ if (decoded.hardness === undefined) decoded.hardness = decodeStat(bigStats, 2)
293
320
  const hullCaps = hullCapsForEntity(id, decoded)
294
321
  attributes = [
295
322
  {
@@ -311,15 +338,19 @@ function resolveEntity(
311
338
  const modStats = BigInt(mod.installed.stats.toString())
312
339
  const decodedStats = decodeCraftedItemStats(modItemId, modStats)
313
340
  const modType = getModuleCapabilityType(modItemId)
314
- const group = computeCapabilityGroup(modType, decodedStats)
315
341
  let modName = 'Module'
342
+ let modTier = 1
316
343
  try {
317
- modName = getItem(modItemId).name
344
+ const modItem = getItem(modItemId)
345
+ modName = modItem.name
346
+ modTier = modItem.tier
318
347
  } catch {
319
348
  modName = itemMetadata[modItemId]?.name ?? 'Module'
320
349
  }
350
+ const group = computeCapabilityGroup(modType, decodedStats, modTier, slot.outputPct)
321
351
  return {
322
352
  name: modName,
353
+ capability: group?.capability,
323
354
  installed: true,
324
355
  attributes: group?.attributes,
325
356
  }
@@ -0,0 +1,180 @@
1
+ import {SCAN_WASM_B64} from './scan-wasm.base64'
2
+
3
+ const stubImports: WebAssembly.Imports = new Proxy(
4
+ {},
5
+ {
6
+ get: () => new Proxy({}, {get: () => () => 0}),
7
+ }
8
+ ) as any
9
+
10
+ let inst: WebAssembly.Instance | null = null
11
+ let readyPromise: Promise<void> | null = null
12
+
13
+ function bytes(): Uint8Array {
14
+ return Uint8Array.from(atob(SCAN_WASM_B64), (c) => c.charCodeAt(0))
15
+ }
16
+
17
+ function finish(i: WebAssembly.Instance) {
18
+ const ex = i.exports as any
19
+ if (typeof ex._initialize === 'function') ex._initialize()
20
+ inst = i
21
+ }
22
+
23
+ export function scanReady(): Promise<void> {
24
+ if (inst) return Promise.resolve()
25
+ if (!readyPromise)
26
+ readyPromise = (
27
+ WebAssembly.instantiate(bytes().buffer as ArrayBuffer, stubImports) as Promise<{
28
+ instance: WebAssembly.Instance
29
+ }>
30
+ ).then((r) => finish(r.instance))
31
+ return readyPromise
32
+ }
33
+
34
+ function ex(): any {
35
+ if (!inst)
36
+ finish(
37
+ new WebAssembly.Instance(
38
+ new WebAssembly.Module(bytes().buffer as ArrayBuffer),
39
+ stubImports
40
+ )
41
+ )
42
+ return inst!.exports
43
+ }
44
+
45
+ const hex = (h: string) => Uint8Array.from(h.match(/../g)!.map((b) => parseInt(b, 16)))
46
+
47
+ export function getLocationType(gameSeed: string, x: number, y: number): number {
48
+ const e = ex()
49
+ const mem = e.memory as WebAssembly.Memory
50
+ const g = e.malloc(32)
51
+ new Uint8Array(mem.buffer, g, 32).set(hex(gameSeed))
52
+ const t = e.get_location_type(g, BigInt(x), BigInt(y))
53
+ e.free(g)
54
+ return t
55
+ }
56
+
57
+ export interface SystemCell {
58
+ x: number
59
+ y: number
60
+ locType: number
61
+ }
62
+
63
+ export interface Coord {
64
+ x: number
65
+ y: number
66
+ }
67
+
68
+ export interface Deposit {
69
+ x: number
70
+ y: number
71
+ depth: number
72
+ itemId: number
73
+ richness: number
74
+ reserve: number
75
+ stats: [number, number, number]
76
+ }
77
+
78
+ export interface DerivedCell {
79
+ location: {x: number; y: number; locType: number; subtype: number; size: number}
80
+ deposits: Deposit[]
81
+ }
82
+
83
+ export function systemsInBox(
84
+ gameSeed: string,
85
+ xMin: number,
86
+ yMin: number,
87
+ xMax: number,
88
+ yMax: number
89
+ ): SystemCell[] {
90
+ const e = ex()
91
+ const mem = e.memory as WebAssembly.Memory
92
+ const g = e.malloc(32)
93
+ new Uint8Array(mem.buffer, g, 32).set(hex(gameSeed))
94
+ let cap = 256
95
+ let out = e.malloc(cap * 12)
96
+ let n = e.systems_in_box(g, xMin, yMin, xMax, yMax, out, cap)
97
+ if (n < 0) {
98
+ e.free(out)
99
+ cap = -n
100
+ out = e.malloc(cap * 12)
101
+ n = e.systems_in_box(g, xMin, yMin, xMax, yMax, out, cap)
102
+ }
103
+ const res: SystemCell[] = []
104
+ const dv = new DataView(mem.buffer.slice(out, out + n * 12))
105
+ for (let i = 0; i < n; i++) {
106
+ const o = i * 12
107
+ res.push({
108
+ x: dv.getInt32(o, true),
109
+ y: dv.getInt32(o + 4, true),
110
+ locType: dv.getUint32(o + 8, true),
111
+ })
112
+ }
113
+ e.free(g)
114
+ e.free(out)
115
+ return res
116
+ }
117
+
118
+ export async function scanCells(
119
+ gameSeed: string,
120
+ epochSeed: string,
121
+ cells: Coord[]
122
+ ): Promise<DerivedCell[]> {
123
+ await scanReady()
124
+ const e = ex()
125
+ const mem = e.memory as WebAssembly.Memory
126
+ const write = (b: Uint8Array) => {
127
+ const p = e.malloc(b.length)
128
+ new Uint8Array(mem.buffer, p, b.length).set(b)
129
+ return p
130
+ }
131
+ const gp = write(hex(gameSeed))
132
+ const ep = write(hex(epochSeed))
133
+ const cellArr = new Int32Array(cells.length * 2)
134
+ cells.forEach((c, i) => {
135
+ cellArr[i * 2] = c.x
136
+ cellArr[i * 2 + 1] = c.y
137
+ })
138
+ const cp = write(new Uint8Array(cellArr.buffer))
139
+ const locOut = e.malloc(cells.length * 8)
140
+ let cap = Math.max(64, cells.length * 8)
141
+ let depOut = e.malloc(cap * 40)
142
+ let n = e.scan_cells(gp, ep, cp, cells.length, locOut, depOut, cap)
143
+ if (n < 0) {
144
+ e.free(depOut)
145
+ cap = -n
146
+ depOut = e.malloc(cap * 40)
147
+ n = e.scan_cells(gp, ep, cp, cells.length, locOut, depOut, cap)
148
+ }
149
+ const locView = new DataView(mem.buffer.slice(locOut, locOut + cells.length * 8))
150
+ const depView = new DataView(mem.buffer.slice(depOut, depOut + n * 40))
151
+ for (const p of [gp, ep, cp, locOut, depOut]) e.free(p)
152
+ const out: DerivedCell[] = cells.map((c, i) => ({
153
+ location: {
154
+ x: c.x,
155
+ y: c.y,
156
+ locType: locView.getUint8(i * 8),
157
+ subtype: locView.getUint8(i * 8 + 1),
158
+ size: locView.getUint32(i * 8 + 4, true),
159
+ },
160
+ deposits: [],
161
+ }))
162
+ for (let i = 0; i < n; i++) {
163
+ const o = i * 40
164
+ const ci = depView.getUint32(o, true)
165
+ out[ci].deposits.push({
166
+ x: cells[ci].x,
167
+ y: cells[ci].y,
168
+ depth: depView.getUint32(o + 4, true),
169
+ itemId: depView.getUint32(o + 8, true),
170
+ richness: depView.getUint32(o + 12, true),
171
+ reserve: depView.getFloat64(o + 32, true),
172
+ stats: [
173
+ depView.getUint32(o + 16, true),
174
+ depView.getUint32(o + 20, true),
175
+ depView.getUint32(o + 24, true),
176
+ ],
177
+ })
178
+ }
179
+ return out
180
+ }