@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.
- package/lib/scan.d.ts +34 -0
- package/lib/scan.js +136 -0
- package/lib/scan.js.map +1 -0
- package/lib/scan.m.js +129 -0
- package/lib/scan.m.js.map +1 -0
- package/lib/shipload.d.ts +2473 -973
- package/lib/shipload.js +11529 -5211
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +11338 -5162
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +970 -0
- package/lib/testing.js +4013 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +4007 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +20 -2
- package/src/capabilities/craftable.ts +51 -0
- package/src/capabilities/crafting.test.ts +7 -0
- package/src/capabilities/crafting.ts +5 -6
- package/src/capabilities/gathering.test.ts +16 -0
- package/src/capabilities/gathering.ts +35 -18
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +9 -0
- package/src/capabilities/storage.ts +16 -1
- package/src/contracts/platform.ts +231 -3
- package/src/contracts/server.ts +1021 -481
- 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 +12 -5
- package/src/data/capability-formulas.ts +14 -7
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +14 -47
- package/src/data/entities.json +76 -10
- package/src/data/item-ids.ts +18 -12
- package/src/data/items.json +321 -38
- package/src/data/kind-registry.json +109 -0
- package/src/data/kind-registry.ts +165 -0
- package/src/data/metadata.ts +119 -33
- package/src/data/recipes-runtime.ts +3 -23
- package/src/data/recipes.json +238 -117
- package/src/derivation/build-methods.ts +45 -0
- package/src/derivation/capabilities.test.ts +151 -0
- package/src/derivation/capabilities.ts +512 -0
- package/src/derivation/capability-mappings.ts +9 -12
- package/src/derivation/crafting.ts +23 -24
- package/src/derivation/index.ts +25 -2
- package/src/derivation/recipe-usage.test.ts +78 -0
- package/src/derivation/recipe-usage.ts +141 -0
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +125 -38
- package/src/derivation/rollups.test.ts +55 -0
- package/src/derivation/rollups.ts +56 -0
- package/src/derivation/stars.test.ts +51 -0
- package/src/derivation/stars.ts +15 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/stratum.ts +17 -20
- package/src/derivation/tiers.ts +40 -7
- package/src/derivation/wormhole.ts +136 -0
- package/src/entities/entity.ts +98 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +124 -134
- 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 +267 -47
- package/src/managers/actions.ts +528 -95
- package/src/managers/base.ts +6 -2
- package/src/managers/construction-types.ts +80 -0
- package/src/managers/construction.ts +412 -0
- package/src/managers/context.ts +20 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +18 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +17 -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/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 +338 -0
- package/src/nft/description.ts +98 -24
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +127 -0
- package/src/planner/planner.test.ts +319 -0
- package/src/resolution/describe-module.ts +18 -13
- package/src/resolution/display-name.ts +38 -10
- package/src/resolution/resolve-item.test.ts +37 -0
- package/src/resolution/resolve-item.ts +55 -24
- package/src/scan/index.ts +180 -0
- package/src/scan/scan-wasm.base64.ts +2 -0
- package/src/scheduling/accessor.ts +68 -22
- package/src/scheduling/availability.ts +108 -0
- package/src/scheduling/cancel.test.ts +348 -0
- package/src/scheduling/cancel.ts +209 -0
- package/src/scheduling/energy.ts +47 -0
- package/src/scheduling/idle-resolve.ts +45 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +249 -0
- package/src/scheduling/lanes.ts +198 -0
- package/src/scheduling/projection.ts +209 -105
- package/src/scheduling/schedule.ts +241 -104
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/shipload.ts +21 -1
- package/src/subscriptions/manager.ts +229 -142
- package/src/subscriptions/mappers.ts +5 -8
- package/src/subscriptions/types.ts +11 -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 +23 -0
- package/src/travel/route-planner.ts +196 -0
- package/src/travel/travel.ts +200 -112
- package/src/types/capabilities.ts +29 -6
- package/src/types/entity.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types.ts +28 -13
- package/src/utils/cargo.ts +27 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/system.ts +36 -24
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -108
- package/src/entities/ship-deploy.ts +0 -259
- package/src/entities/ship.ts +0 -204
- package/src/entities/warehouse.ts +0 -119
- 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}
|
|
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
|
-
['
|
|
60
|
+
['drain', 'Drain'],
|
|
62
61
|
],
|
|
63
|
-
highlightKeys: ['yield', 'depth', '
|
|
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: ['
|
|
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: '
|
|
88
|
-
params: [['
|
|
89
|
-
highlightKeys: ['
|
|
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.
|
|
131
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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:
|
|
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
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|