@shipload/sdk 1.0.0-next.6 → 1.0.0-next.60
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.
- package/lib/scan.d.ts +52 -0
- package/lib/scan.js +162 -0
- package/lib/scan.js.map +1 -0
- package/lib/scan.m.js +152 -0
- package/lib/scan.m.js.map +1 -0
- package/lib/shipload.d.ts +3589 -1363
- package/lib/shipload.js +15700 -5454
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +15423 -5402
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1173 -0
- package/lib/testing.js +4947 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +4941 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +20 -2
- package/src/capabilities/craftable.test.ts +82 -0
- package/src/capabilities/craftable.ts +82 -0
- package/src/capabilities/crafting.test.ts +35 -0
- package/src/capabilities/crafting.ts +34 -7
- package/src/capabilities/gathering.test.ts +29 -0
- package/src/capabilities/gathering.ts +37 -19
- package/src/capabilities/hauling.ts +0 -5
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +42 -0
- package/src/capabilities/movement.ts +1 -1
- package/src/capabilities/storage.ts +16 -1
- package/src/contracts/platform.ts +231 -3
- package/src/contracts/server.ts +1518 -501
- package/src/coordinates/address.ts +88 -0
- package/src/coordinates/constants.test.ts +15 -0
- package/src/coordinates/constants.ts +23 -0
- package/src/coordinates/index.ts +15 -0
- package/src/coordinates/memo.test.ts +47 -0
- package/src/coordinates/memo.ts +20 -0
- package/src/coordinates/permutation.ts +77 -0
- package/src/coordinates/regions.ts +48 -0
- package/src/coordinates/sectors.ts +115 -0
- package/src/data/capabilities.ts +49 -18
- package/src/data/capability-formulas.ts +26 -14
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +13 -47
- package/src/data/entities.json +379 -14
- package/src/data/item-ids.ts +48 -12
- package/src/data/items.json +301 -74
- package/src/data/kind-registry.json +195 -0
- package/src/data/kind-registry.ts +182 -0
- package/src/data/metadata.ts +277 -48
- package/src/data/recipes-runtime.ts +6 -23
- package/src/data/recipes.json +2074 -173
- package/src/derivation/build-methods.test.ts +13 -0
- package/src/derivation/build-methods.ts +48 -0
- package/src/derivation/capabilities.test.ts +348 -0
- package/src/derivation/capabilities.ts +692 -0
- package/src/derivation/capability-mappings.ts +60 -16
- package/src/derivation/crafting.test.ts +17 -0
- package/src/derivation/crafting.ts +56 -33
- package/src/derivation/index.ts +27 -2
- package/src/derivation/recipe-usage.test.ts +88 -0
- package/src/derivation/recipe-usage.ts +141 -0
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +9 -1
- package/src/derivation/rollups.test.ts +55 -0
- package/src/derivation/rollups.ts +72 -0
- package/src/derivation/stars.test.ts +67 -0
- package/src/derivation/stars.ts +25 -0
- package/src/derivation/stat-scaling.ts +12 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/stratum.ts +26 -22
- package/src/derivation/tiers.ts +40 -7
- package/src/derivation/upgrades.ts +14 -0
- package/src/derivation/wormhole.ts +154 -0
- package/src/entities/entity.ts +102 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +141 -135
- package/src/entities/slot-multiplier.ts +43 -0
- package/src/errors.ts +12 -16
- package/src/format.ts +26 -4
- package/src/index-module.ts +333 -35
- package/src/managers/actions.ts +668 -103
- package/src/managers/base.ts +6 -2
- package/src/managers/cluster.test.ts +39 -0
- package/src/managers/cluster.ts +53 -0
- package/src/managers/construction-types.ts +80 -0
- package/src/managers/construction.ts +443 -0
- package/src/managers/context.ts +29 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +27 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +20 -1
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.test.ts +14 -0
- package/src/managers/nft.ts +70 -0
- package/src/managers/players.ts +25 -0
- package/src/managers/plot.ts +122 -0
- package/src/nft/atomicassets.abi.json +1342 -0
- package/src/nft/atomicassets.ts +237 -0
- package/src/nft/atomicdata.ts +130 -0
- package/src/nft/buildImmutableData.ts +385 -0
- package/src/nft/description.ts +225 -52
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +242 -0
- package/src/planner/planner.test.ts +334 -0
- package/src/resolution/describe-module.ts +43 -25
- package/src/resolution/display-name.ts +38 -10
- package/src/resolution/resolve-item.test.ts +48 -0
- package/src/resolution/resolve-item.ts +112 -58
- package/src/scan/index.ts +244 -0
- package/src/scan/scan-wasm.base64.ts +2 -0
- package/src/scheduling/accessor.ts +65 -23
- package/src/scheduling/availability.test.ts +204 -0
- package/src/scheduling/availability.ts +211 -0
- package/src/scheduling/cancel.test.ts +542 -0
- package/src/scheduling/cancel.ts +254 -0
- package/src/scheduling/cluster-stock.test.ts +31 -0
- package/src/scheduling/cluster-stock.ts +15 -0
- package/src/scheduling/energy.ts +47 -0
- package/src/scheduling/idle-resolve.ts +45 -0
- package/src/scheduling/jobs.ts +71 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +250 -0
- package/src/scheduling/lanes.ts +227 -0
- package/src/scheduling/projection.ts +257 -133
- package/src/scheduling/schedule.test.ts +119 -0
- package/src/scheduling/schedule.ts +257 -117
- package/src/scheduling/task-cargo.test.ts +44 -0
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/scheduling/unwrap.test.ts +86 -0
- package/src/scheduling/unwrap.ts +190 -0
- package/src/shipload.ts +26 -1
- package/src/subscriptions/manager.cluster.test.ts +51 -0
- package/src/subscriptions/manager.ts +245 -172
- package/src/subscriptions/mappers.ts +5 -8
- package/src/subscriptions/types.ts +28 -3
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +167 -0
- package/src/travel/reach.ts +21 -0
- package/src/travel/route-planner.ts +288 -0
- package/src/travel/route-simulator.ts +170 -0
- package/src/travel/travel.ts +188 -122
- package/src/types/capabilities.ts +37 -8
- package/src/types/entity.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types.ts +51 -16
- package/src/utils/cargo.test.ts +14 -0
- package/src/utils/cargo.ts +29 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/system.ts +15 -16
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -123
- package/src/entities/ship-deploy.ts +0 -295
- package/src/entities/ship.ts +0 -221
- package/src/entities/warehouse.ts +0 -127
- package/src/types/entity-traits.ts +0 -69
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import {UInt16, UInt64} from '@wharfkit/antelope'
|
|
2
2
|
import type {UInt16Type, UInt64Type} from '@wharfkit/antelope'
|
|
3
3
|
import type {ResourceCategory} from '../types'
|
|
4
|
-
import {getItem} from '../data/catalog'
|
|
4
|
+
import {getItem, getModules} from '../data/catalog'
|
|
5
|
+
import {ENTITY_SHIP, getPackedEntityType} from '../data/kind-registry'
|
|
5
6
|
import {getEntityLayout} from '../data/recipes-runtime'
|
|
6
7
|
import {entityMetadata, itemMetadata} from '../data/metadata'
|
|
7
8
|
import {
|
|
8
9
|
getModuleCapabilityType,
|
|
9
10
|
isModuleItem,
|
|
11
|
+
MODULE_BUILDER,
|
|
10
12
|
MODULE_CRAFTER,
|
|
11
13
|
MODULE_ENGINE,
|
|
14
|
+
MODULE_BATTERY,
|
|
12
15
|
MODULE_GATHERER,
|
|
13
16
|
MODULE_GENERATOR,
|
|
14
17
|
MODULE_HAULER,
|
|
@@ -19,29 +22,21 @@ import {decodeCraftedItemStats, decodeStat} from '../derivation/crafting'
|
|
|
19
22
|
import {getStatDefinitions} from '../derivation/stats'
|
|
20
23
|
import {
|
|
21
24
|
computeCrafterCapabilities,
|
|
25
|
+
computeBuilderCapabilities,
|
|
26
|
+
computeBatteryCapabilities,
|
|
22
27
|
computeEngineCapabilities,
|
|
23
28
|
computeGathererCapabilities,
|
|
24
29
|
computeGeneratorCapabilities,
|
|
25
30
|
computeHaulerCapabilities,
|
|
26
31
|
computeLoaderCapabilities,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
componentIcon,
|
|
35
|
-
itemAbbreviations,
|
|
36
|
-
moduleIcon,
|
|
37
|
-
} from '../data/colors'
|
|
32
|
+
computeBaseCapacity,
|
|
33
|
+
computeBaseHullmass,
|
|
34
|
+
computeStorageCapabilities,
|
|
35
|
+
} from '../derivation/capabilities'
|
|
36
|
+
import {applySlotMultiplierUint32} from '../entities/slot-multiplier'
|
|
37
|
+
import {toWholeEnergy} from '../nft/description'
|
|
38
|
+
import {categoryColors, componentIcon, itemAbbreviations, moduleIcon} from '../data/colors'
|
|
38
39
|
import type {ServerContract} from '../contracts'
|
|
39
|
-
import {
|
|
40
|
-
ITEM_CONTAINER_T1_PACKED,
|
|
41
|
-
ITEM_CONTAINER_T2_PACKED,
|
|
42
|
-
ITEM_SHIP_T1_PACKED,
|
|
43
|
-
ITEM_WAREHOUSE_T1_PACKED,
|
|
44
|
-
} from '../data/item-ids'
|
|
45
40
|
|
|
46
41
|
export interface ResolvedItemStat {
|
|
47
42
|
key: string
|
|
@@ -62,8 +57,13 @@ export type ResolvedItemType = 'resource' | 'component' | 'module' | 'entity'
|
|
|
62
57
|
|
|
63
58
|
export interface ResolvedModuleSlot {
|
|
64
59
|
name?: string
|
|
60
|
+
capability?: string
|
|
65
61
|
installed: boolean
|
|
66
62
|
attributes?: {label: string; value: number}[]
|
|
63
|
+
slotLabel?: string
|
|
64
|
+
slotType?: string
|
|
65
|
+
outputPct?: number
|
|
66
|
+
maxTier?: number
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export interface ResolvedItem {
|
|
@@ -109,7 +109,7 @@ function resolveResource(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
109
109
|
return {
|
|
110
110
|
itemId: id,
|
|
111
111
|
name: item.name,
|
|
112
|
-
icon:
|
|
112
|
+
icon: '',
|
|
113
113
|
abbreviation: null,
|
|
114
114
|
category: cat,
|
|
115
115
|
tier: item.tier,
|
|
@@ -156,11 +156,12 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
156
156
|
function computeCapabilityGroup(
|
|
157
157
|
moduleType: number,
|
|
158
158
|
stats: Record<string, number>,
|
|
159
|
-
tier: number
|
|
159
|
+
tier: number,
|
|
160
|
+
outputPct = 100
|
|
160
161
|
): ResolvedAttributeGroup | undefined {
|
|
161
162
|
switch (moduleType) {
|
|
162
163
|
case MODULE_ENGINE: {
|
|
163
|
-
const caps = computeEngineCapabilities(stats)
|
|
164
|
+
const caps = computeEngineCapabilities(stats, tier)
|
|
164
165
|
return {
|
|
165
166
|
capability: 'Engine',
|
|
166
167
|
attributes: [
|
|
@@ -170,12 +171,12 @@ function computeCapabilityGroup(
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
case MODULE_GENERATOR: {
|
|
173
|
-
const caps = computeGeneratorCapabilities(stats)
|
|
174
|
+
const caps = computeGeneratorCapabilities(stats, tier)
|
|
174
175
|
return {
|
|
175
176
|
capability: 'Generator',
|
|
176
177
|
attributes: [
|
|
177
|
-
{label: 'Capacity', value: caps.capacity},
|
|
178
|
-
{label: 'Recharge', value: caps.recharge},
|
|
178
|
+
{label: 'Capacity', value: toWholeEnergy(caps.capacity)},
|
|
179
|
+
{label: 'Recharge', value: toWholeEnergy(caps.recharge)},
|
|
179
180
|
],
|
|
180
181
|
}
|
|
181
182
|
}
|
|
@@ -185,16 +186,15 @@ function computeCapabilityGroup(
|
|
|
185
186
|
capability: 'Gatherer',
|
|
186
187
|
attributes: [
|
|
187
188
|
{label: 'Yield', value: caps.yield},
|
|
188
|
-
{label: 'Drain', value: caps.drain},
|
|
189
|
+
{label: 'Drain', value: toWholeEnergy(caps.drain)},
|
|
189
190
|
{label: 'Depth', value: caps.depth},
|
|
190
|
-
{label: 'Speed', value: caps.speed},
|
|
191
191
|
],
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
case MODULE_LOADER: {
|
|
195
|
-
const caps = computeLoaderCapabilities(stats)
|
|
195
|
+
const caps = computeLoaderCapabilities(stats, tier)
|
|
196
196
|
return {
|
|
197
|
-
capability: '
|
|
197
|
+
capability: 'Loading',
|
|
198
198
|
attributes: [
|
|
199
199
|
{label: 'Mass', value: caps.mass},
|
|
200
200
|
{label: 'Thrust', value: caps.thrust},
|
|
@@ -203,45 +203,82 @@ function computeCapabilityGroup(
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
case MODULE_CRAFTER: {
|
|
206
|
-
const caps = computeCrafterCapabilities(stats)
|
|
206
|
+
const caps = computeCrafterCapabilities(stats, tier)
|
|
207
207
|
return {
|
|
208
|
-
capability: '
|
|
208
|
+
capability: 'Crafting',
|
|
209
209
|
attributes: [
|
|
210
210
|
{label: 'Speed', value: caps.speed},
|
|
211
|
-
{label: 'Drain', value: caps.drain},
|
|
211
|
+
{label: 'Drain', value: toWholeEnergy(caps.drain)},
|
|
212
|
+
],
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
case MODULE_BUILDER: {
|
|
216
|
+
const caps = computeBuilderCapabilities(stats, tier)
|
|
217
|
+
return {
|
|
218
|
+
capability: 'Build',
|
|
219
|
+
attributes: [
|
|
220
|
+
{label: 'Speed', value: caps.speed},
|
|
221
|
+
{label: 'Drain', value: toWholeEnergy(caps.drain)},
|
|
212
222
|
],
|
|
213
223
|
}
|
|
214
224
|
}
|
|
215
225
|
case MODULE_HAULER: {
|
|
216
|
-
const caps = computeHaulerCapabilities(stats)
|
|
226
|
+
const caps = computeHaulerCapabilities(stats, tier)
|
|
217
227
|
return {
|
|
218
|
-
capability: '
|
|
228
|
+
capability: 'Hauling',
|
|
219
229
|
attributes: [
|
|
220
230
|
{label: 'Capacity', value: caps.capacity},
|
|
221
231
|
{label: 'Efficiency', value: caps.efficiency},
|
|
222
|
-
{label: 'Drain', value: caps.drain},
|
|
232
|
+
{label: 'Drain', value: toWholeEnergy(caps.drain)},
|
|
223
233
|
],
|
|
224
234
|
}
|
|
225
235
|
}
|
|
226
236
|
case MODULE_STORAGE: {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
const caps = computeStorageCapabilities(stats, tier)
|
|
238
|
+
return {
|
|
239
|
+
capability: 'Storage',
|
|
240
|
+
attributes: [
|
|
241
|
+
{
|
|
242
|
+
label: 'Cargo Capacity',
|
|
243
|
+
value: applySlotMultiplierUint32(caps.capacity, outputPct),
|
|
244
|
+
},
|
|
245
|
+
{label: 'Drain', value: toWholeEnergy(caps.drain)},
|
|
246
|
+
],
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
case MODULE_BATTERY: {
|
|
250
|
+
const caps = computeBatteryCapabilities(stats)
|
|
251
|
+
return {
|
|
252
|
+
capability: 'Energy',
|
|
253
|
+
attributes: [
|
|
254
|
+
{
|
|
255
|
+
label: 'Energy Capacity',
|
|
256
|
+
value: toWholeEnergy(applySlotMultiplierUint32(caps.capacity, outputPct)),
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
}
|
|
234
260
|
}
|
|
235
261
|
default:
|
|
236
262
|
return undefined
|
|
237
263
|
}
|
|
238
264
|
}
|
|
239
265
|
|
|
266
|
+
// Recipe-less higher-tier modules reuse the T1 stat layout of their module type.
|
|
267
|
+
function decodeModuleStats(id: number, big: bigint): Record<string, number> {
|
|
268
|
+
const decoded = decodeCraftedItemStats(id, big)
|
|
269
|
+
if (Object.keys(decoded).length > 0) return decoded
|
|
270
|
+
const moduleType = getItem(id).moduleType
|
|
271
|
+
if (!moduleType) return decoded
|
|
272
|
+
const t1 = getModules({moduleType, tier: 1})[0]
|
|
273
|
+
if (!t1) return decoded
|
|
274
|
+
return decodeCraftedItemStats(Number(t1.id), big)
|
|
275
|
+
}
|
|
276
|
+
|
|
240
277
|
function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
|
|
241
278
|
const item = getItem(id)
|
|
242
279
|
let attributes: ResolvedAttributeGroup[] | undefined
|
|
243
280
|
if (stats !== undefined) {
|
|
244
|
-
const decoded =
|
|
281
|
+
const decoded = decodeModuleStats(id, toBigStats(stats))
|
|
245
282
|
const modType = getModuleCapabilityType(id)
|
|
246
283
|
const group = computeCapabilityGroup(modType, decoded, item.tier)
|
|
247
284
|
if (group) attributes = [group]
|
|
@@ -260,22 +297,26 @@ function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
260
297
|
|
|
261
298
|
function hullCapsForEntity(
|
|
262
299
|
itemId: number,
|
|
263
|
-
decoded: Record<string, number
|
|
300
|
+
decoded: Record<string, number>,
|
|
301
|
+
packedStats: bigint
|
|
264
302
|
): {
|
|
265
303
|
hullmass: number
|
|
266
304
|
capacity: number
|
|
267
305
|
} {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
306
|
+
// A ship hull consumes all five positional packed channels. This is separate
|
|
307
|
+
// from the recipe-facing stat labels, which remain historical for Ship T1.
|
|
308
|
+
const hullStats = getPackedEntityType(itemId)?.equals(ENTITY_SHIP)
|
|
309
|
+
? {
|
|
310
|
+
strength: decodeStat(packedStats, 0),
|
|
311
|
+
hardness: decodeStat(packedStats, 1),
|
|
312
|
+
plasticity: decodeStat(packedStats, 2),
|
|
313
|
+
volatility: decodeStat(packedStats, 3),
|
|
314
|
+
conductivity: decodeStat(packedStats, 4),
|
|
315
|
+
}
|
|
316
|
+
: decoded
|
|
317
|
+
return {
|
|
318
|
+
hullmass: computeBaseHullmass(itemId, hullStats),
|
|
319
|
+
capacity: computeBaseCapacity(itemId, hullStats),
|
|
279
320
|
}
|
|
280
321
|
}
|
|
281
322
|
|
|
@@ -290,8 +331,12 @@ function resolveEntity(
|
|
|
290
331
|
let moduleSlots: ResolvedModuleSlot[] | undefined
|
|
291
332
|
|
|
292
333
|
if (stats !== undefined) {
|
|
293
|
-
const
|
|
294
|
-
const
|
|
334
|
+
const bigStats = toBigStats(stats)
|
|
335
|
+
const decoded = decodeCraftedItemStats(id, bigStats)
|
|
336
|
+
if (decoded.strength === undefined) decoded.strength = decodeStat(bigStats, 0)
|
|
337
|
+
if (decoded.density === undefined) decoded.density = decodeStat(bigStats, 1)
|
|
338
|
+
if (decoded.hardness === undefined) decoded.hardness = decodeStat(bigStats, 2)
|
|
339
|
+
const hullCaps = hullCapsForEntity(id, decoded, bigStats)
|
|
295
340
|
attributes = [
|
|
296
341
|
{
|
|
297
342
|
capability: 'Hull',
|
|
@@ -306,11 +351,17 @@ function resolveEntity(
|
|
|
306
351
|
if (layout && layout.slots.length > 0) {
|
|
307
352
|
const slotLabels = entityMetadata[id]?.moduleSlotLabels ?? []
|
|
308
353
|
moduleSlots = layout.slots.map((slot, i) => {
|
|
354
|
+
const slotInfo = {
|
|
355
|
+
slotLabel: slotLabels[i] ?? slot.type,
|
|
356
|
+
slotType: slot.type,
|
|
357
|
+
outputPct: slot.outputPct,
|
|
358
|
+
maxTier: slot.maxTier,
|
|
359
|
+
}
|
|
309
360
|
const mod = modules?.[i]
|
|
310
361
|
if (mod?.installed) {
|
|
311
362
|
const modItemId = Number(mod.installed.item_id.value.toString())
|
|
312
363
|
const modStats = BigInt(mod.installed.stats.toString())
|
|
313
|
-
const decodedStats =
|
|
364
|
+
const decodedStats = decodeModuleStats(modItemId, modStats)
|
|
314
365
|
const modType = getModuleCapabilityType(modItemId)
|
|
315
366
|
let modName = 'Module'
|
|
316
367
|
let modTier = 1
|
|
@@ -321,16 +372,19 @@ function resolveEntity(
|
|
|
321
372
|
} catch {
|
|
322
373
|
modName = itemMetadata[modItemId]?.name ?? 'Module'
|
|
323
374
|
}
|
|
324
|
-
const group = computeCapabilityGroup(modType, decodedStats, modTier)
|
|
375
|
+
const group = computeCapabilityGroup(modType, decodedStats, modTier, slot.outputPct)
|
|
325
376
|
return {
|
|
326
377
|
name: modName,
|
|
378
|
+
capability: group?.capability,
|
|
327
379
|
installed: true,
|
|
328
380
|
attributes: group?.attributes,
|
|
381
|
+
...slotInfo,
|
|
329
382
|
}
|
|
330
383
|
}
|
|
331
384
|
return {
|
|
332
385
|
name: slotLabels[i] ?? slot.type,
|
|
333
386
|
installed: false,
|
|
387
|
+
...slotInfo,
|
|
334
388
|
}
|
|
335
389
|
})
|
|
336
390
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
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
|
+
// Shared marshalling for the `*_in_box` exports; grow-and-retry once on overflow (export returns -needed).
|
|
48
|
+
function boxScan<T>(
|
|
49
|
+
exportName: string,
|
|
50
|
+
stride: number,
|
|
51
|
+
gameSeed: string,
|
|
52
|
+
xMin: number,
|
|
53
|
+
yMin: number,
|
|
54
|
+
xMax: number,
|
|
55
|
+
yMax: number,
|
|
56
|
+
decode: (dv: DataView, o: number) => T
|
|
57
|
+
): T[] {
|
|
58
|
+
const e = ex()
|
|
59
|
+
const mem = e.memory as WebAssembly.Memory
|
|
60
|
+
const g = e.malloc(32)
|
|
61
|
+
new Uint8Array(mem.buffer, g, 32).set(hex(gameSeed))
|
|
62
|
+
let cap = 256
|
|
63
|
+
let out = e.malloc(cap * stride)
|
|
64
|
+
let n = e[exportName](g, xMin, yMin, xMax, yMax, out, cap)
|
|
65
|
+
if (n < 0) {
|
|
66
|
+
e.free(out)
|
|
67
|
+
cap = -n
|
|
68
|
+
out = e.malloc(cap * stride)
|
|
69
|
+
n = e[exportName](g, xMin, yMin, xMax, yMax, out, cap)
|
|
70
|
+
}
|
|
71
|
+
const dv = new DataView(mem.buffer, out, n * stride)
|
|
72
|
+
const res: T[] = []
|
|
73
|
+
for (let i = 0; i < n; i++) res.push(decode(dv, i * stride))
|
|
74
|
+
e.free(g)
|
|
75
|
+
e.free(out)
|
|
76
|
+
return res
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function getLocationType(gameSeed: string, x: number, y: number): number {
|
|
80
|
+
const e = ex()
|
|
81
|
+
const mem = e.memory as WebAssembly.Memory
|
|
82
|
+
const g = e.malloc(32)
|
|
83
|
+
new Uint8Array(mem.buffer, g, 32).set(hex(gameSeed))
|
|
84
|
+
const t = e.get_location_type(g, BigInt(x), BigInt(y))
|
|
85
|
+
e.free(g)
|
|
86
|
+
return t
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface SystemCell {
|
|
90
|
+
x: number
|
|
91
|
+
y: number
|
|
92
|
+
locType: number
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface Coord {
|
|
96
|
+
x: number
|
|
97
|
+
y: number
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface Deposit {
|
|
101
|
+
x: number
|
|
102
|
+
y: number
|
|
103
|
+
depth: number
|
|
104
|
+
itemId: number
|
|
105
|
+
richness: number
|
|
106
|
+
reserve: number
|
|
107
|
+
stats: [number, number, number]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface DerivedCell {
|
|
111
|
+
location: {x: number; y: number; locType: number; subtype: number; size: number}
|
|
112
|
+
deposits: Deposit[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function systemsInBox(
|
|
116
|
+
gameSeed: string,
|
|
117
|
+
xMin: number,
|
|
118
|
+
yMin: number,
|
|
119
|
+
xMax: number,
|
|
120
|
+
yMax: number
|
|
121
|
+
): SystemCell[] {
|
|
122
|
+
return boxScan('systems_in_box', 12, gameSeed, xMin, yMin, xMax, yMax, (dv, o) => ({
|
|
123
|
+
x: dv.getInt32(o, true),
|
|
124
|
+
y: dv.getInt32(o + 4, true),
|
|
125
|
+
locType: dv.getUint32(o + 8, true),
|
|
126
|
+
}))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface LocationCell {
|
|
130
|
+
x: number
|
|
131
|
+
y: number
|
|
132
|
+
locType: number
|
|
133
|
+
subtype: number
|
|
134
|
+
size: number
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function locationsInBox(
|
|
138
|
+
gameSeed: string,
|
|
139
|
+
xMin: number,
|
|
140
|
+
yMin: number,
|
|
141
|
+
xMax: number,
|
|
142
|
+
yMax: number
|
|
143
|
+
): LocationCell[] {
|
|
144
|
+
return boxScan('locations_in_box', 16, gameSeed, xMin, yMin, xMax, yMax, (dv, o) => ({
|
|
145
|
+
x: dv.getInt32(o, true),
|
|
146
|
+
y: dv.getInt32(o + 4, true),
|
|
147
|
+
locType: dv.getUint8(o + 8),
|
|
148
|
+
subtype: dv.getUint8(o + 9),
|
|
149
|
+
size: dv.getUint32(o + 12, true),
|
|
150
|
+
}))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface WormholeCell {
|
|
154
|
+
x: number
|
|
155
|
+
y: number
|
|
156
|
+
exit: {x: number; y: number}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function wormholesInBox(
|
|
160
|
+
gameSeed: string,
|
|
161
|
+
xMin: number,
|
|
162
|
+
yMin: number,
|
|
163
|
+
xMax: number,
|
|
164
|
+
yMax: number
|
|
165
|
+
): WormholeCell[] {
|
|
166
|
+
return boxScan('wormholes_in_box', 16, gameSeed, xMin, yMin, xMax, yMax, (dv, o) => ({
|
|
167
|
+
x: dv.getInt32(o, true),
|
|
168
|
+
y: dv.getInt32(o + 4, true),
|
|
169
|
+
exit: {x: dv.getInt32(o + 8, true), y: dv.getInt32(o + 12, true)},
|
|
170
|
+
}))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function scanCells(
|
|
174
|
+
gameSeed: string,
|
|
175
|
+
epochSeed: string,
|
|
176
|
+
cells: Coord[]
|
|
177
|
+
): Promise<DerivedCell[]> {
|
|
178
|
+
await scanReady()
|
|
179
|
+
return scanCellsCore(gameSeed, epochSeed, cells)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Sync sibling of scanCells; caller must warm the instance via scanReady() first.
|
|
183
|
+
export function scanCellsSync(gameSeed: string, epochSeed: string, cells: Coord[]): DerivedCell[] {
|
|
184
|
+
return scanCellsCore(gameSeed, epochSeed, cells)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function scanCellsCore(gameSeed: string, epochSeed: string, cells: Coord[]): DerivedCell[] {
|
|
188
|
+
const e = ex()
|
|
189
|
+
const mem = e.memory as WebAssembly.Memory
|
|
190
|
+
const write = (b: Uint8Array) => {
|
|
191
|
+
const p = e.malloc(b.length)
|
|
192
|
+
new Uint8Array(mem.buffer, p, b.length).set(b)
|
|
193
|
+
return p
|
|
194
|
+
}
|
|
195
|
+
const gp = write(hex(gameSeed))
|
|
196
|
+
const ep = write(hex(epochSeed))
|
|
197
|
+
const cellArr = new Int32Array(cells.length * 2)
|
|
198
|
+
cells.forEach((c, i) => {
|
|
199
|
+
cellArr[i * 2] = c.x
|
|
200
|
+
cellArr[i * 2 + 1] = c.y
|
|
201
|
+
})
|
|
202
|
+
const cp = write(new Uint8Array(cellArr.buffer))
|
|
203
|
+
const locOut = e.malloc(cells.length * 8)
|
|
204
|
+
let cap = Math.max(64, cells.length * 8)
|
|
205
|
+
let depOut = e.malloc(cap * 40)
|
|
206
|
+
let n = e.scan_cells(gp, ep, cp, cells.length, locOut, depOut, cap)
|
|
207
|
+
if (n < 0) {
|
|
208
|
+
e.free(depOut)
|
|
209
|
+
cap = -n
|
|
210
|
+
depOut = e.malloc(cap * 40)
|
|
211
|
+
n = e.scan_cells(gp, ep, cp, cells.length, locOut, depOut, cap)
|
|
212
|
+
}
|
|
213
|
+
const locView = new DataView(mem.buffer, locOut, cells.length * 8)
|
|
214
|
+
const depView = new DataView(mem.buffer, depOut, n * 40)
|
|
215
|
+
const out: DerivedCell[] = cells.map((c, i) => ({
|
|
216
|
+
location: {
|
|
217
|
+
x: c.x,
|
|
218
|
+
y: c.y,
|
|
219
|
+
locType: locView.getUint8(i * 8),
|
|
220
|
+
subtype: locView.getUint8(i * 8 + 1),
|
|
221
|
+
size: locView.getUint32(i * 8 + 4, true),
|
|
222
|
+
},
|
|
223
|
+
deposits: [],
|
|
224
|
+
}))
|
|
225
|
+
for (let i = 0; i < n; i++) {
|
|
226
|
+
const o = i * 40
|
|
227
|
+
const ci = depView.getUint32(o, true)
|
|
228
|
+
out[ci].deposits.push({
|
|
229
|
+
x: cells[ci].x,
|
|
230
|
+
y: cells[ci].y,
|
|
231
|
+
depth: depView.getUint32(o + 4, true),
|
|
232
|
+
itemId: depView.getUint32(o + 8, true),
|
|
233
|
+
richness: depView.getUint32(o + 12, true),
|
|
234
|
+
reserve: depView.getFloat64(o + 32, true),
|
|
235
|
+
stats: [
|
|
236
|
+
depView.getUint32(o + 16, true),
|
|
237
|
+
depView.getUint32(o + 20, true),
|
|
238
|
+
depView.getUint32(o + 24, true),
|
|
239
|
+
],
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
for (const p of [gp, ep, cp, locOut, depOut]) e.free(p)
|
|
243
|
+
return out
|
|
244
|
+
}
|