@shipload/sdk 2.0.0-rc11 → 2.0.0-rc12
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/shipload.d.ts +66 -22
- package/lib/shipload.js +2361 -2117
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2344 -2117
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/storage.ts +92 -2
- package/src/data/categories.ts +1 -1
- package/src/derivation/crafting.ts +76 -0
- package/src/derivation/index.ts +3 -1
- package/src/derivation/resources.ts +1 -7
- package/src/derivation/stratum.ts +9 -11
- package/src/derivation/tiers.ts +54 -0
- package/src/errors.ts +5 -0
- package/src/index-module.ts +11 -3
- package/src/market/items.ts +69 -10
- package/src/scheduling/projection.ts +84 -75
- package/src/types.ts +2 -1
- package/src/utils/system.ts +8 -4
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {UInt32, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
1
|
+
import {UInt16, UInt32, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
3
|
import {StorageCapability} from '../types/capabilities'
|
|
4
4
|
import {getItem} from '../market/items'
|
|
5
|
+
import {INSUFFICIENT_ITEM_QUANTITY} from '../errors'
|
|
5
6
|
|
|
6
7
|
export interface HasCargo {
|
|
7
8
|
cargo: ServerContract.Types.cargo_item[]
|
|
@@ -15,7 +16,13 @@ export interface HasCargomass {
|
|
|
15
16
|
cargomass: UInt32
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
interface MassInput {
|
|
20
|
+
item_id: UInt16
|
|
21
|
+
quantity: UInt32
|
|
22
|
+
modules: ServerContract.Types.module_entry[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function calcCargoItemMass(item: MassInput): UInt64 {
|
|
19
26
|
const itemDef = getItem(item.item_id)
|
|
20
27
|
let mass = UInt64.from(itemDef.mass).multiplying(item.quantity)
|
|
21
28
|
|
|
@@ -37,6 +44,14 @@ export function calcCargoMass(entity: HasCargo): UInt64 {
|
|
|
37
44
|
return mass
|
|
38
45
|
}
|
|
39
46
|
|
|
47
|
+
export function calcStacksMass(stacks: CargoStack[]): UInt64 {
|
|
48
|
+
let mass = UInt64.from(0)
|
|
49
|
+
for (const s of stacks) {
|
|
50
|
+
mass = mass.adding(calcCargoItemMass(s))
|
|
51
|
+
}
|
|
52
|
+
return mass
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
export function availableCapacity(entity: StorageCapability): UInt64 {
|
|
41
56
|
const cargoMass = calcCargoMass(entity)
|
|
42
57
|
return entity.capacity.gt(cargoMass)
|
|
@@ -70,3 +85,78 @@ export function isFull(entity: HasCapacity & HasCargomass): boolean {
|
|
|
70
85
|
export function isFullFromMass(capacity: UInt64Type, cargoMass: UInt64Type): boolean {
|
|
71
86
|
return UInt64.from(cargoMass).gte(capacity)
|
|
72
87
|
}
|
|
88
|
+
|
|
89
|
+
export interface CargoStack {
|
|
90
|
+
item_id: UInt16
|
|
91
|
+
quantity: UInt32
|
|
92
|
+
seed?: UInt64
|
|
93
|
+
modules: ServerContract.Types.module_entry[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function cargoItemToStack(item: ServerContract.Types.cargo_item): CargoStack {
|
|
97
|
+
return {
|
|
98
|
+
item_id: UInt16.from(item.item_id),
|
|
99
|
+
quantity: UInt32.from(item.quantity),
|
|
100
|
+
seed: item.seed,
|
|
101
|
+
modules: item.modules ?? [],
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function stackToCargoItem(stack: CargoStack): ServerContract.Types.cargo_item {
|
|
106
|
+
return ServerContract.Types.cargo_item.from({
|
|
107
|
+
item_id: stack.item_id,
|
|
108
|
+
quantity: stack.quantity,
|
|
109
|
+
seed: stack.seed,
|
|
110
|
+
modules: stack.modules,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function seedEquals(a?: UInt64, b?: UInt64): boolean {
|
|
115
|
+
if (!a && !b) return true
|
|
116
|
+
if (!a || !b) return false
|
|
117
|
+
return a.equals(b)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function stackIdentityEqual(a: CargoStack, b: CargoStack): boolean {
|
|
121
|
+
return a.item_id.equals(b.item_id) && seedEquals(a.seed, b.seed)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function stackKey(s: CargoStack): string {
|
|
125
|
+
const seedVal = s.seed ? s.seed.toString() : '0'
|
|
126
|
+
return `${s.item_id.toNumber()}:${seedVal}`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function stacksEqual(a: CargoStack, b: CargoStack): boolean {
|
|
130
|
+
return stackIdentityEqual(a, b) && a.quantity.equals(b.quantity)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function mergeStacks(stacks: CargoStack[], add: CargoStack): CargoStack[] {
|
|
134
|
+
const idx = stacks.findIndex((s) => stackIdentityEqual(s, add))
|
|
135
|
+
if (idx === -1) {
|
|
136
|
+
return [...stacks, {...add}]
|
|
137
|
+
}
|
|
138
|
+
const result = stacks.slice()
|
|
139
|
+
result[idx] = {
|
|
140
|
+
...result[idx],
|
|
141
|
+
quantity: UInt32.from(result[idx].quantity.adding(add.quantity)),
|
|
142
|
+
}
|
|
143
|
+
return result
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function removeFromStacks(stacks: CargoStack[], remove: CargoStack): CargoStack[] {
|
|
147
|
+
const idx = stacks.findIndex((s) => stackIdentityEqual(s, remove))
|
|
148
|
+
if (idx === -1) {
|
|
149
|
+
throw new Error(INSUFFICIENT_ITEM_QUANTITY)
|
|
150
|
+
}
|
|
151
|
+
const target = stacks[idx]
|
|
152
|
+
if (target.quantity.lt(remove.quantity)) {
|
|
153
|
+
throw new Error(INSUFFICIENT_ITEM_QUANTITY)
|
|
154
|
+
}
|
|
155
|
+
const remaining = UInt32.from(target.quantity.subtracting(remove.quantity))
|
|
156
|
+
if (remaining.equals(UInt32.from(0))) {
|
|
157
|
+
return [...stacks.slice(0, idx), ...stacks.slice(idx + 1)]
|
|
158
|
+
}
|
|
159
|
+
const result = stacks.slice()
|
|
160
|
+
result[idx] = {...target, quantity: remaining}
|
|
161
|
+
return result
|
|
162
|
+
}
|
package/src/data/categories.ts
CHANGED
|
@@ -20,7 +20,7 @@ const categories: CategoryInfo[] = [
|
|
|
20
20
|
{
|
|
21
21
|
id: 'precious',
|
|
22
22
|
name: 'Precious Metals',
|
|
23
|
-
label: 'Precious',
|
|
23
|
+
label: 'Precious Metal',
|
|
24
24
|
description:
|
|
25
25
|
'Conductive, corrosion-resistant — electronics, energy systems, precision components',
|
|
26
26
|
color: categoryColors.precious,
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
entityRecipes,
|
|
5
5
|
getComponentById,
|
|
6
6
|
getEntityRecipe,
|
|
7
|
+
getEntityRecipeByItemId,
|
|
7
8
|
getModuleRecipe,
|
|
8
9
|
moduleRecipes,
|
|
9
10
|
} from '../data/recipes'
|
|
11
|
+
import {getStatDefinitions} from './stats'
|
|
10
12
|
import {deriveResourceStats} from './stratum'
|
|
11
13
|
|
|
12
14
|
export interface StackInput {
|
|
@@ -195,3 +197,77 @@ export function blendCargoStacks(
|
|
|
195
197
|
const blended = allKeys.map((key) => Math.max(1, Math.min(999, blendStacks(decoded, key))))
|
|
196
198
|
return UInt64.from(encodeStats(blended))
|
|
197
199
|
}
|
|
200
|
+
|
|
201
|
+
export interface RecipeSlotInput {
|
|
202
|
+
itemId: number
|
|
203
|
+
category: ResourceCategory | undefined
|
|
204
|
+
stacks: {quantity: number; seed: bigint}[]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function decodeRawStackToCategoryStats(
|
|
208
|
+
seed: bigint,
|
|
209
|
+
category: ResourceCategory
|
|
210
|
+
): Record<string, number> {
|
|
211
|
+
const raw = deriveResourceStats(seed)
|
|
212
|
+
const defs = getStatDefinitions(category)
|
|
213
|
+
const result: Record<string, number> = {}
|
|
214
|
+
if (defs[0]) result[defs[0].key] = raw.stat1
|
|
215
|
+
if (defs[1]) result[defs[1].key] = raw.stat2
|
|
216
|
+
if (defs[2]) result[defs[2].key] = raw.stat3
|
|
217
|
+
return result
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function computeCraftedOutputSeed(
|
|
221
|
+
outputItemId: number,
|
|
222
|
+
slotInputs: RecipeSlotInput[]
|
|
223
|
+
): UInt64 {
|
|
224
|
+
const component = getComponentById(outputItemId)
|
|
225
|
+
if (component) {
|
|
226
|
+
const categoryStacks: CategoryStacks[] = []
|
|
227
|
+
for (const slot of slotInputs) {
|
|
228
|
+
if (!slot.category) continue
|
|
229
|
+
const slotIsComponent = getComponentById(slot.itemId) !== undefined
|
|
230
|
+
const stacks: StackInput[] = slot.stacks.map((s) => ({
|
|
231
|
+
quantity: s.quantity,
|
|
232
|
+
stats: slotIsComponent
|
|
233
|
+
? decodeCraftedItemStats(slot.itemId, s.seed)
|
|
234
|
+
: decodeRawStackToCategoryStats(s.seed, slot.category!),
|
|
235
|
+
}))
|
|
236
|
+
categoryStacks.push({category: slot.category, stacks})
|
|
237
|
+
}
|
|
238
|
+
const stats = computeComponentStats(outputItemId, categoryStacks)
|
|
239
|
+
const ordered = component.stats.map((statDef) => {
|
|
240
|
+
const found = stats.find((s) => s.key === statDef.key)
|
|
241
|
+
return found ? found.value : 0
|
|
242
|
+
})
|
|
243
|
+
return UInt64.from(encodeStats(ordered))
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const entityRecipe = getEntityRecipeByItemId(outputItemId)
|
|
247
|
+
if (entityRecipe) {
|
|
248
|
+
const componentStacks: Record<number, {quantity: number; stats: Record<string, number>}[]> =
|
|
249
|
+
{}
|
|
250
|
+
for (const slot of slotInputs) {
|
|
251
|
+
if (slot.category !== undefined) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
`entity recipe ${entityRecipe.id} expects component inputs but slot itemId=${slot.itemId} has category=${slot.category}`
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
const list = (componentStacks[slot.itemId] ??= [])
|
|
257
|
+
for (const s of slot.stacks) {
|
|
258
|
+
list.push({
|
|
259
|
+
quantity: s.quantity,
|
|
260
|
+
stats: decodeCraftedItemStats(slot.itemId, s.seed),
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const stats = computeEntityStats(entityRecipe.id, componentStacks)
|
|
265
|
+
const ordered = entityRecipe.stats.map((statDef) => {
|
|
266
|
+
const found = stats.find((s) => s.key === statDef.key)
|
|
267
|
+
return found ? found.value : 0
|
|
268
|
+
})
|
|
269
|
+
return UInt64.from(encodeStats(ordered))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
throw new Error(`computeCraftedOutputSeed: no recipe found for outputItemId=${outputItemId}`)
|
|
273
|
+
}
|
package/src/derivation/index.ts
CHANGED
|
@@ -7,7 +7,6 @@ export {
|
|
|
7
7
|
getLocationCandidates,
|
|
8
8
|
getDepthThreshold,
|
|
9
9
|
getResourceTier,
|
|
10
|
-
depthScaleFactor,
|
|
11
10
|
DEPTH_THRESHOLD_T1,
|
|
12
11
|
DEPTH_THRESHOLD_T2,
|
|
13
12
|
DEPTH_THRESHOLD_T3,
|
|
@@ -24,5 +23,8 @@ export {
|
|
|
24
23
|
PLANET_SUBTYPE_INDUSTRIAL,
|
|
25
24
|
} from './resources'
|
|
26
25
|
|
|
26
|
+
export {RESERVE_TIERS, TIER_ROLL_MAX, rollTier, rollWithinTier} from './tiers'
|
|
27
|
+
export type {ReserveTier, TierRange} from './tiers'
|
|
28
|
+
|
|
27
29
|
export * from './stats'
|
|
28
30
|
export * from './crafting'
|
|
@@ -9,7 +9,7 @@ export const DEPTH_THRESHOLD_T5 = 55000
|
|
|
9
9
|
export const LOCATION_MIN_DEPTH = 500
|
|
10
10
|
export const LOCATION_MAX_DEPTH = 65535
|
|
11
11
|
|
|
12
|
-
export const YIELD_THRESHOLD = Math.floor(0.
|
|
12
|
+
export const YIELD_THRESHOLD = Math.floor(0.001 * 0xffffffff)
|
|
13
13
|
|
|
14
14
|
export const PLANET_SUBTYPE_GAS_GIANT = 0
|
|
15
15
|
export const PLANET_SUBTYPE_ROCKY = 1
|
|
@@ -134,9 +134,3 @@ export function getEligibleResources(
|
|
|
134
134
|
return stratum >= threshold
|
|
135
135
|
})
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
export function depthScaleFactor(stratum: number): number {
|
|
139
|
-
if (stratum <= 1) return 1.0
|
|
140
|
-
const logScale = Math.log(stratum) / Math.log(65535)
|
|
141
|
-
return 1.0 + logScale * 2.0
|
|
142
|
-
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import {Bytes, Checksum256, Checksum256Type} from '@wharfkit/antelope'
|
|
2
2
|
import {hash512} from '../utils/hash'
|
|
3
3
|
import {Coordinates, CoordinatesType} from '../types'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
getEligibleResources,
|
|
7
|
-
getResourceWeight,
|
|
8
|
-
YIELD_THRESHOLD,
|
|
9
|
-
} from './resources'
|
|
4
|
+
import {getEligibleResources, getResourceWeight, YIELD_THRESHOLD} from './resources'
|
|
5
|
+
import {RESERVE_TIERS, rollTier, rollWithinTier} from './tiers'
|
|
10
6
|
|
|
11
7
|
export interface StratumInfo {
|
|
12
8
|
itemId: number
|
|
@@ -39,9 +35,10 @@ export function deriveStratum(
|
|
|
39
35
|
|
|
40
36
|
let reserve = 0
|
|
41
37
|
if (rawReserve <= YIELD_THRESHOLD) {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
38
|
+
const tierRoll = ((bytes[18] << 8) | bytes[19]) >>> 0
|
|
39
|
+
const withinRoll = ((bytes[20] << 8) | bytes[21]) >>> 0
|
|
40
|
+
const tier = rollTier(tierRoll, stratum)
|
|
41
|
+
reserve = rollWithinTier(withinRoll, RESERVE_TIERS[tier])
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
if (reserve === 0) return {itemId: 0, seed: 0n, richness: 0, reserve: 0}
|
|
@@ -105,11 +102,12 @@ export function deriveResourceStats(seed: bigint): ResourceStats {
|
|
|
105
102
|
(hashBytes[offset] * 0x1000000 +
|
|
106
103
|
(hashBytes[offset + 1] << 16) +
|
|
107
104
|
(hashBytes[offset + 2] << 8) +
|
|
108
|
-
hashBytes[offset + 3]) >>>
|
|
105
|
+
hashBytes[offset + 3]) >>>
|
|
106
|
+
0
|
|
109
107
|
|
|
110
108
|
const weibull = (raw: number): number => {
|
|
111
109
|
const u = raw / 4294967296
|
|
112
|
-
let x = 0.
|
|
110
|
+
let x = 0.24 * Math.sqrt(-Math.log(1 - u))
|
|
113
111
|
if (x > 1) x = 1
|
|
114
112
|
let val = Math.floor(x * 999) + 1
|
|
115
113
|
if (val > 999) val = 999
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type ReserveTier = 'small' | 'medium' | 'large' | 'massive' | 'motherlode'
|
|
2
|
+
|
|
3
|
+
export interface TierRange {
|
|
4
|
+
min: number
|
|
5
|
+
max: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const RESERVE_TIERS: Record<ReserveTier, TierRange> = {
|
|
9
|
+
small: {min: 15, max: 60},
|
|
10
|
+
medium: {min: 100, max: 200},
|
|
11
|
+
large: {min: 400, max: 700},
|
|
12
|
+
massive: {min: 1000, max: 2500},
|
|
13
|
+
motherlode: {min: 4000, max: 10000},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SHALLOW_THRESHOLDS = {
|
|
17
|
+
small: 0.8,
|
|
18
|
+
medium: 0.991946,
|
|
19
|
+
large: 0.999946,
|
|
20
|
+
massive: 0.999996,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const DEEP_THRESHOLDS = {
|
|
24
|
+
small: 0.5,
|
|
25
|
+
medium: 0.95892,
|
|
26
|
+
large: 0.99892,
|
|
27
|
+
massive: 0.99992,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const TIER_ROLL_MAX = 0x10000 // 65536
|
|
31
|
+
|
|
32
|
+
function lerp(a: number, b: number, t: number): number {
|
|
33
|
+
return a + (b - a) * t
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function rollTier(tierRoll: number, stratum: number): ReserveTier {
|
|
37
|
+
const d = Math.min(stratum, 65535) / 65535
|
|
38
|
+
const smallMax = lerp(SHALLOW_THRESHOLDS.small, DEEP_THRESHOLDS.small, d) * TIER_ROLL_MAX
|
|
39
|
+
const mediumMax = lerp(SHALLOW_THRESHOLDS.medium, DEEP_THRESHOLDS.medium, d) * TIER_ROLL_MAX
|
|
40
|
+
const largeMax = lerp(SHALLOW_THRESHOLDS.large, DEEP_THRESHOLDS.large, d) * TIER_ROLL_MAX
|
|
41
|
+
const massiveMax = lerp(SHALLOW_THRESHOLDS.massive, DEEP_THRESHOLDS.massive, d) * TIER_ROLL_MAX
|
|
42
|
+
|
|
43
|
+
if (tierRoll < smallMax) return 'small'
|
|
44
|
+
if (tierRoll < mediumMax) return 'medium'
|
|
45
|
+
if (tierRoll < largeMax) return 'large'
|
|
46
|
+
if (tierRoll < massiveMax) return 'massive'
|
|
47
|
+
return 'motherlode'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function rollWithinTier(withinRoll: number, range: TierRange): number {
|
|
51
|
+
const u = withinRoll / 65535
|
|
52
|
+
const skewed = u * u
|
|
53
|
+
return Math.floor(range.min + skewed * (range.max - range.min))
|
|
54
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -44,3 +44,8 @@ export const SHIP_CARGO_NOT_LOADED = 'Cannot unload cargo that is not loaded.'
|
|
|
44
44
|
export const WAREHOUSE_NOT_FOUND = 'Cannot find warehouse for given id.'
|
|
45
45
|
export const WAREHOUSE_ALREADY_AT_LOCATION = 'Warehouse already exists at this location.'
|
|
46
46
|
export const WAREHOUSE_CAPACITY_EXCEEDED = 'Warehouse capacity would be exceeded.'
|
|
47
|
+
export const ENTITY_CAPACITY_EXCEEDED = 'Entity cargo capacity would be exceeded.'
|
|
48
|
+
export const RECIPE_INPUTS_INSUFFICIENT = 'Insufficient inputs for recipe.'
|
|
49
|
+
export const RECIPE_INPUTS_INVALID = 'Input cargo does not match recipe requirements.'
|
|
50
|
+
export const RECIPE_INPUTS_EXCESS = 'Provided inputs exceed recipe requirements.'
|
|
51
|
+
export const RECIPE_INPUTS_MIXED = 'All stacks for a recipe input must be the same resource.'
|
package/src/index-module.ts
CHANGED
|
@@ -66,7 +66,6 @@ export {
|
|
|
66
66
|
getLocationCandidates,
|
|
67
67
|
getDepthThreshold,
|
|
68
68
|
getResourceTier,
|
|
69
|
-
depthScaleFactor,
|
|
70
69
|
DEPTH_THRESHOLD_T1,
|
|
71
70
|
DEPTH_THRESHOLD_T2,
|
|
72
71
|
DEPTH_THRESHOLD_T3,
|
|
@@ -84,6 +83,9 @@ export {
|
|
|
84
83
|
|
|
85
84
|
export type {StratumInfo, ResourceStats} from './derivation'
|
|
86
85
|
|
|
86
|
+
export {RESERVE_TIERS, TIER_ROLL_MAX, rollTier, rollWithinTier} from './derivation'
|
|
87
|
+
export type {ReserveTier, TierRange} from './derivation'
|
|
88
|
+
|
|
87
89
|
export {getStatDefinitions, getStatName, resolveStats} from './derivation'
|
|
88
90
|
export type {StatDefinition, NamedStats} from './derivation'
|
|
89
91
|
|
|
@@ -135,7 +137,12 @@ export type {HasCargo} from './entities/inventory-accessor'
|
|
|
135
137
|
export * as cargoUtils from './entities/cargo-utils'
|
|
136
138
|
export type {CargoData} from './entities/cargo-utils'
|
|
137
139
|
|
|
138
|
-
export {
|
|
140
|
+
export {
|
|
141
|
+
createProjectedEntity,
|
|
142
|
+
projectEntity,
|
|
143
|
+
projectEntityAt,
|
|
144
|
+
validateSchedule,
|
|
145
|
+
} from './scheduling/projection'
|
|
139
146
|
export type {Projectable, ProjectedEntity} from './scheduling/projection'
|
|
140
147
|
|
|
141
148
|
export * from './types/capabilities'
|
|
@@ -230,8 +237,9 @@ export {
|
|
|
230
237
|
blendCrossGroup,
|
|
231
238
|
categoryItemMass,
|
|
232
239
|
computeInputMass,
|
|
240
|
+
computeCraftedOutputSeed,
|
|
233
241
|
} from './derivation/crafting'
|
|
234
|
-
export type {StackInput, CategoryStacks} from './derivation/crafting'
|
|
242
|
+
export type {StackInput, CategoryStacks, RecipeSlotInput} from './derivation/crafting'
|
|
235
243
|
|
|
236
244
|
export {computeContainerCapabilities, computeContainerT2Capabilities} from './entities/container'
|
|
237
245
|
|
package/src/market/items.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {UInt16, UInt16Type} from '@wharfkit/antelope'
|
|
2
2
|
import {Item} from '../types'
|
|
3
3
|
import itemsData from '../data/items.json'
|
|
4
|
+
import {computeInputMass} from '../derivation/crafting'
|
|
5
|
+
import {getComponentById, getEntityRecipeByItemId, getModuleRecipeByItemId} from '../data/recipes'
|
|
4
6
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
+
const itemsById: Map<number, Item> = new Map()
|
|
8
|
+
const synthesizedCache: Map<number, Item> = new Map()
|
|
9
|
+
|
|
10
|
+
for (const g of itemsData) {
|
|
11
|
+
const item = Item.from({
|
|
7
12
|
id: g.id,
|
|
8
13
|
name: g.name,
|
|
9
14
|
description: g.description,
|
|
@@ -12,19 +17,73 @@ const items: Item[] = itemsData.map((g) =>
|
|
|
12
17
|
tier: g.tier,
|
|
13
18
|
color: g.color,
|
|
14
19
|
})
|
|
15
|
-
)
|
|
20
|
+
itemsById.set(item.id.toNumber(), item)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const itemIds = Array.from(itemsById.values(), (i) => i.id)
|
|
24
|
+
|
|
25
|
+
interface RecipeSource {
|
|
26
|
+
name: string
|
|
27
|
+
description: string
|
|
28
|
+
mass: number
|
|
29
|
+
color: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function synthesizeItem(id: number, source: RecipeSource): Item {
|
|
33
|
+
return Item.from({
|
|
34
|
+
id,
|
|
35
|
+
name: source.name,
|
|
36
|
+
description: source.description,
|
|
37
|
+
mass: source.mass,
|
|
38
|
+
category: 'metal',
|
|
39
|
+
tier: 't1',
|
|
40
|
+
color: source.color,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function synthesizeFromRecipes(id: number): Item | undefined {
|
|
45
|
+
const component = getComponentById(id)
|
|
46
|
+
if (component) return synthesizeItem(id, component)
|
|
16
47
|
|
|
17
|
-
|
|
48
|
+
const entityRecipe = getEntityRecipeByItemId(id)
|
|
49
|
+
if (entityRecipe) {
|
|
50
|
+
return synthesizeItem(id, {
|
|
51
|
+
...entityRecipe,
|
|
52
|
+
mass: computeInputMass(entityRecipe.id, 'entity'),
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const moduleRecipe = getModuleRecipeByItemId(id)
|
|
57
|
+
if (moduleRecipe) {
|
|
58
|
+
return synthesizeItem(id, {
|
|
59
|
+
...moduleRecipe,
|
|
60
|
+
mass: computeInputMass(moduleRecipe.id, 'module'),
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return undefined
|
|
65
|
+
}
|
|
18
66
|
|
|
19
67
|
export function getItem(itemId: UInt16Type): Item {
|
|
20
|
-
const id = UInt16.from(itemId)
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
|
|
68
|
+
const id = UInt16.from(itemId).toNumber()
|
|
69
|
+
const existing = itemsById.get(id) ?? synthesizedCache.get(id)
|
|
70
|
+
if (existing) return existing
|
|
71
|
+
|
|
72
|
+
const synthesized = synthesizeFromRecipes(id)
|
|
73
|
+
if (synthesized) {
|
|
74
|
+
synthesizedCache.set(id, synthesized)
|
|
75
|
+
return synthesized
|
|
24
76
|
}
|
|
25
|
-
|
|
77
|
+
|
|
78
|
+
throw new Error(`Item with id ${id} not found`)
|
|
26
79
|
}
|
|
27
80
|
|
|
28
81
|
export function getItems(): Item[] {
|
|
29
|
-
return
|
|
82
|
+
return Array.from(itemsById.values())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function registerItem(item: Item): void {
|
|
86
|
+
const id = item.id.toNumber()
|
|
87
|
+
itemsById.set(id, item)
|
|
88
|
+
synthesizedCache.delete(id)
|
|
30
89
|
}
|