@shipload/sdk 2.0.0-rc20 → 2.0.0-rc21

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.
@@ -1,13 +1,7 @@
1
1
  import {UInt64} from '@wharfkit/antelope'
2
2
  import type {ResourceCategory} from '../types'
3
- import {
4
- entityRecipes,
5
- getComponentById,
6
- getEntityRecipe,
7
- getEntityRecipeByItemId,
8
- getModuleRecipe,
9
- moduleRecipes,
10
- } from '../data/recipes'
3
+ import {findItemByCategoryAndTier, getRecipe, Recipe} from '../data/recipes-runtime'
4
+ import {getItem} from '../market/items'
11
5
  import {getStatDefinitions} from './stats'
12
6
  import {deriveResourceStats} from './stratum'
13
7
 
@@ -41,26 +35,45 @@ export function decodeStats(stats: bigint, count: number): number[] {
41
35
  return result
42
36
  }
43
37
 
44
- function mapStatsToKeys(stats: bigint, statDefs: {key: string}[]): Record<string, number> {
45
- const values = decodeStats(stats, statDefs.length)
46
- const result: Record<string, number> = {}
47
- for (let i = 0; i < statDefs.length; i++) {
48
- result[statDefs[i].key] = values[i]
38
+ function getItemStatKeys(itemId: number): string[] {
39
+ const item = getItem(itemId)
40
+ if (item.type === 'resource') {
41
+ if (!item.category) return []
42
+ return getStatDefinitions(item.category).map((d) => d.key)
49
43
  }
50
- return result
44
+ const recipe = getRecipe(itemId)
45
+ if (!recipe) return []
46
+ return recipe.statSlots.map((slot) => keyForStatSlot(recipe, slot))
51
47
  }
52
48
 
53
- export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
54
- const comp = getComponentById(itemId)
55
- if (comp) return mapStatsToKeys(stats, comp.stats)
56
-
57
- const entityRecipe = entityRecipes.find((r) => r.packedItemId === itemId)
58
- if (entityRecipe) return mapStatsToKeys(stats, entityRecipe.stats)
49
+ function keyForStatSlot(
50
+ recipe: Recipe,
51
+ slot: {sources: {inputIndex: number; statIndex: number}[]}
52
+ ): string {
53
+ const src = slot.sources[0]
54
+ if (!src) return ''
55
+ return keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
56
+ }
59
57
 
60
- const moduleRecipe = moduleRecipes.find((r) => r.itemId === itemId)
61
- if (moduleRecipe) return mapStatsToKeys(stats, moduleRecipe.stats)
58
+ function keyForRecipeInputStat(recipe: Recipe, inputIndex: number, statIndex: number): string {
59
+ const input = recipe.inputs[inputIndex]
60
+ if (!input) return ''
61
+ if ('category' in input) {
62
+ const defs = getStatDefinitions(input.category)
63
+ return defs[statIndex]?.key ?? ''
64
+ }
65
+ // itemId-typed input — its stats follow that item's own statSlots layout.
66
+ const innerKeys = getItemStatKeys(input.itemId)
67
+ return innerKeys[statIndex] ?? ''
68
+ }
62
69
 
63
- return {}
70
+ export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
71
+ const keys = getItemStatKeys(itemId)
72
+ const result: Record<string, number> = {}
73
+ for (let i = 0; i < keys.length; i++) {
74
+ if (keys[i]) result[keys[i]] = decodeStat(stats, i)
75
+ }
76
+ return result
64
77
  }
65
78
 
66
79
  export function blendStacks(stacks: StackInput[], statKey: string): number {
@@ -75,20 +88,6 @@ export function blendStacks(stacks: StackInput[], statKey: string): number {
75
88
  return Math.floor(weightedSum / totalQty)
76
89
  }
77
90
 
78
- export function computeComponentStats(
79
- componentId: number,
80
- categoryStacks: CategoryStacks[]
81
- ): {key: string; value: number}[] {
82
- const comp = getComponentById(componentId)
83
- if (!comp) return []
84
-
85
- return comp.stats.map((statDef) => {
86
- const matching = categoryStacks.find((cs) => cs.category === statDef.source)
87
- const value = matching ? blendStacks(matching.stacks, statDef.key) : 0
88
- return {key: statDef.key, value: Math.max(1, Math.min(999, value))}
89
- })
90
- }
91
-
92
91
  export function blendComponentStacks(
93
92
  stacks: {quantity: number; stats: Record<string, number>}[]
94
93
  ): Record<string, number> {
@@ -107,11 +106,35 @@ export function blendComponentStacks(
107
106
  return result
108
107
  }
109
108
 
109
+ export function computeComponentStats(
110
+ componentId: number,
111
+ categoryStacks: CategoryStacks[]
112
+ ): {key: string; value: number}[] {
113
+ const recipe = getRecipe(componentId)
114
+ if (!recipe) return []
115
+
116
+ return recipe.statSlots.map((slot) => {
117
+ const src = slot.sources[0]
118
+ const key = keyForStatSlot(recipe, slot)
119
+ const input = src ? recipe.inputs[src.inputIndex] : undefined
120
+ if (!input || !('category' in input)) {
121
+ return {key, value: Math.max(1, Math.min(999, 0))}
122
+ }
123
+ const matching = categoryStacks.find((cs) => cs.category === input.category)
124
+ const value = matching ? blendStacks(matching.stacks, key) : 0
125
+ return {key, value: Math.max(1, Math.min(999, value))}
126
+ })
127
+ }
128
+
110
129
  export function computeEntityStats(
111
- entityRecipeId: string,
130
+ entityItemIdOrLegacyId: number | string,
112
131
  componentStacks: Record<number, {quantity: number; stats: Record<string, number>}[]>
113
132
  ): {key: string; value: number}[] {
114
- const recipe = getEntityRecipe(entityRecipeId) ?? getModuleRecipe(entityRecipeId)
133
+ const itemId =
134
+ typeof entityItemIdOrLegacyId === 'number'
135
+ ? entityItemIdOrLegacyId
136
+ : legacyEntityIdToItemId(entityItemIdOrLegacyId)
137
+ const recipe = getRecipe(itemId)
115
138
  if (!recipe) return []
116
139
 
117
140
  const blendedByComponent: Record<number, Record<string, number>> = {}
@@ -119,13 +142,35 @@ export function computeEntityStats(
119
142
  blendedByComponent[Number(compId)] = blendComponentStacks(stacks)
120
143
  }
121
144
 
122
- return recipe.stats.map((stat) => {
123
- const blended = blendedByComponent[stat.sourceComponentId] ?? {}
124
- const value = blended[stat.sourceStatKey] ?? 0
125
- return {key: stat.key, value: Math.max(1, Math.min(999, value))}
145
+ return recipe.statSlots.map((slot) => {
146
+ const src = slot.sources[0]
147
+ const key = keyForStatSlot(recipe, slot)
148
+ if (!src) return {key, value: 1}
149
+ const input = recipe.inputs[src.inputIndex]
150
+ if (!input || 'category' in input) {
151
+ return {key, value: 1}
152
+ }
153
+ const blended = blendedByComponent[input.itemId] ?? {}
154
+ const value = blended[key] ?? 0
155
+ return {key, value: Math.max(1, Math.min(999, value))}
126
156
  })
127
157
  }
128
158
 
159
+ function legacyEntityIdToItemId(id: string): number {
160
+ switch (id) {
161
+ case 'container':
162
+ return 10200
163
+ case 'ship-t1':
164
+ return 10201
165
+ case 'warehouse-t1':
166
+ return 10202
167
+ case 'container-t2':
168
+ return 20200
169
+ default:
170
+ return 0
171
+ }
172
+ }
173
+
129
174
  function decodeStackStats(itemId: number, stats: UInt64): Record<string, number> {
130
175
  if (itemId >= 10000) {
131
176
  return decodeCraftedItemStats(itemId, BigInt(stats.toString()))
@@ -134,43 +179,20 @@ function decodeStackStats(itemId: number, stats: UInt64): Record<string, number>
134
179
  return {stat1: decodeStat(s, 0), stat2: decodeStat(s, 1), stat3: decodeStat(s, 2)}
135
180
  }
136
181
 
137
- export const categoryItemMass: Record<string, number> = {
138
- ore: 30000,
139
- crystal: 40000,
140
- gas: 15000,
141
- regolith: 22000,
142
- biomass: 15000,
143
- }
182
+ export function computeInputMass(itemId: number): number {
183
+ const recipe = getRecipe(itemId)
184
+ if (!recipe) throw new Error(`computeInputMass: no recipe found for itemId=${itemId}`)
144
185
 
145
- export function computeInputMass(
146
- itemId: string | number,
147
- itemType: 'component' | 'module' | 'entity'
148
- ): number {
149
- if (itemType === 'component') {
150
- const comp = getComponentById(itemId as number)
151
- if (!comp) return 0
152
- return comp.recipe.reduce((sum, input) => {
153
- const mass = input.category ? categoryItemMass[input.category] ?? 0 : 0
154
- return sum + mass * input.quantity
155
- }, 0)
156
- }
157
- if (itemType === 'module') {
158
- const mod = getModuleRecipe(itemId as string)
159
- if (!mod) return 0
160
- return mod.recipe.reduce((sum, input) => {
161
- const comp = input.itemId ? getComponentById(input.itemId) : undefined
162
- return sum + (comp?.mass ?? 0) * input.quantity
163
- }, 0)
164
- }
165
- if (itemType === 'entity') {
166
- const ent = getEntityRecipe(itemId as string)
167
- if (!ent) return 0
168
- return ent.recipe.reduce((sum, input) => {
169
- const comp = input.itemId ? getComponentById(input.itemId) : undefined
170
- return sum + (comp?.mass ?? 0) * input.quantity
171
- }, 0)
186
+ let total = 0
187
+ for (const input of recipe.inputs) {
188
+ if ('itemId' in input) {
189
+ total += getItem(input.itemId).mass * input.quantity
190
+ } else {
191
+ const item = findItemByCategoryAndTier(input.category, input.tier)
192
+ total += item.mass * input.quantity
193
+ }
172
194
  }
173
- return 0
195
+ return total
174
196
  }
175
197
 
176
198
  export function blendCrossGroup(sources: {value: number; weight: number}[]): number {
@@ -220,39 +242,41 @@ export function computeCraftedOutputStats(
220
242
  outputItemId: number,
221
243
  slotInputs: RecipeSlotInput[]
222
244
  ): UInt64 {
223
- const component = getComponentById(outputItemId)
224
- if (component) {
225
- const categoryStacks: CategoryStacks[] = []
226
- for (const slot of slotInputs) {
227
- if (!slot.category) continue
228
- const slotIsComponent = getComponentById(slot.itemId) !== undefined
229
- const stacks: StackInput[] = slot.stacks.map((s) => ({
230
- quantity: s.quantity,
231
- stats: slotIsComponent
232
- ? decodeCraftedItemStats(slot.itemId, s.stats)
233
- : decodeRawStackToCategoryStats(s.stats, slot.category!),
234
- }))
235
- categoryStacks.push({category: slot.category, stacks})
236
- }
237
- const stats = computeComponentStats(outputItemId, categoryStacks)
238
- const ordered = component.stats.map((statDef) => {
239
- const found = stats.find((s) => s.key === statDef.key)
240
- return found ? found.value : 0
241
- })
242
- return UInt64.from(encodeStats(ordered))
245
+ const recipe = getRecipe(outputItemId)
246
+ if (!recipe) {
247
+ throw new Error(
248
+ `computeCraftedOutputStats: no recipe found for outputItemId=${outputItemId}`
249
+ )
243
250
  }
244
251
 
245
- const entityRecipe = getEntityRecipeByItemId(outputItemId)
246
- if (entityRecipe) {
247
- const componentStacks: Record<number, {quantity: number; stats: Record<string, number>}[]> =
248
- {}
252
+ const outputItem = getItem(outputItemId)
253
+
254
+ if (outputItem.type === 'entity') {
249
255
  for (const slot of slotInputs) {
250
256
  if (slot.category !== undefined) {
251
257
  throw new Error(
252
- `entity recipe ${entityRecipe.id} expects component inputs but slot itemId=${slot.itemId} has category=${slot.category}`
258
+ `entity recipe ${outputItemId} expects component inputs but slot itemId=${slot.itemId} has category=${slot.category}`
253
259
  )
254
260
  }
255
- const list = (componentStacks[slot.itemId] ??= [])
261
+ }
262
+ }
263
+
264
+ // Decode each slot's stacks into key→value maps using the slot item's
265
+ // own stat layout, so blending works regardless of recipe shape.
266
+ const decodedByItem: Record<number, {quantity: number; stats: Record<string, number>}[]> = {}
267
+ const decodedByCategory: Partial<Record<ResourceCategory, StackInput[]>> = {}
268
+
269
+ for (const slot of slotInputs) {
270
+ if (slot.category !== undefined) {
271
+ const list = (decodedByCategory[slot.category] ??= [])
272
+ for (const s of slot.stacks) {
273
+ list.push({
274
+ quantity: s.quantity,
275
+ stats: decodeRawStackToCategoryStats(s.stats, slot.category),
276
+ })
277
+ }
278
+ } else {
279
+ const list = (decodedByItem[slot.itemId] ??= [])
256
280
  for (const s of slot.stacks) {
257
281
  list.push({
258
282
  quantity: s.quantity,
@@ -260,15 +284,52 @@ export function computeCraftedOutputStats(
260
284
  })
261
285
  }
262
286
  }
263
- const stats = computeEntityStats(entityRecipe.id, componentStacks)
264
- const ordered = entityRecipe.stats.map((statDef) => {
265
- const found = stats.find((s) => s.key === statDef.key)
266
- return found ? found.value : 0
267
- })
268
- return UInt64.from(encodeStats(ordered))
269
287
  }
270
288
 
271
- throw new Error(`computeCraftedOutputStats: no recipe found for outputItemId=${outputItemId}`)
289
+ // Pre-blend itemId inputs once per item id.
290
+ const blendedByItem: Record<number, Record<string, number>> = {}
291
+ for (const [id, stacks] of Object.entries(decodedByItem)) {
292
+ blendedByItem[Number(id)] = blendComponentStacks(stacks)
293
+ }
294
+
295
+ const out: number[] = []
296
+ for (const slot of recipe.statSlots) {
297
+ if (slot.sources.length === 0) {
298
+ out.push(0)
299
+ continue
300
+ }
301
+ if (slot.sources.length === 1 || recipe.blendWeights.length === 0) {
302
+ const src = slot.sources[0]
303
+ const key = keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
304
+ const input = recipe.inputs[src.inputIndex]
305
+ let value = 0
306
+ if (input && 'category' in input) {
307
+ value = blendStacks(decodedByCategory[input.category] ?? [], key)
308
+ } else if (input) {
309
+ value = blendedByItem[input.itemId]?.[key] ?? 0
310
+ }
311
+ out.push(Math.max(1, Math.min(999, value)))
312
+ } else {
313
+ let weightedSum = 0
314
+ let totalWeight = 0
315
+ for (const src of slot.sources) {
316
+ const key = keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
317
+ const input = recipe.inputs[src.inputIndex]
318
+ const weight = recipe.blendWeights[src.inputIndex] ?? 1
319
+ let value = 0
320
+ if (input && 'category' in input) {
321
+ value = blendStacks(decodedByCategory[input.category] ?? [], key)
322
+ } else if (input) {
323
+ value = blendedByItem[input.itemId]?.[key] ?? 0
324
+ }
325
+ weightedSum += value * weight
326
+ totalWeight += weight
327
+ }
328
+ const blended = totalWeight > 0 ? Math.floor(weightedSum / totalWeight) : 0
329
+ out.push(Math.max(1, Math.min(999, blended)))
330
+ }
331
+ }
332
+ return UInt64.from(encodeStats(out))
272
333
  }
273
334
 
274
335
  /**
@@ -1,4 +1,4 @@
1
- import {ResourceTier} from '../types'
1
+ import {getItem} from '../market/items'
2
2
 
3
3
  export const DEPTH_THRESHOLD_T1 = 0
4
4
  export const DEPTH_THRESHOLD_T2 = 2000
@@ -18,47 +18,23 @@ export const PLANET_SUBTYPE_ICY = 3
18
18
  export const PLANET_SUBTYPE_OCEAN = 4
19
19
  export const PLANET_SUBTYPE_INDUSTRIAL = 5
20
20
 
21
- interface ResourceEntry {
22
- id: number
23
- tier: ResourceTier
24
- }
25
-
26
- const RESOURCE_CATALOG: ResourceEntry[] = [
27
- {id: 101, tier: 't1'},
28
- {id: 102, tier: 't2'},
29
- {id: 103, tier: 't3'},
30
- {id: 201, tier: 't1'},
31
- {id: 202, tier: 't2'},
32
- {id: 203, tier: 't3'},
33
- {id: 301, tier: 't1'},
34
- {id: 302, tier: 't2'},
35
- {id: 303, tier: 't3'},
36
- {id: 401, tier: 't1'},
37
- {id: 402, tier: 't2'},
38
- {id: 403, tier: 't3'},
39
- {id: 501, tier: 't1'},
40
- {id: 502, tier: 't2'},
41
- {id: 503, tier: 't3'},
42
- ]
43
-
44
- export function getDepthThreshold(tier: ResourceTier): number {
21
+ export function getDepthThreshold(tier: number): number {
45
22
  switch (tier) {
46
- case 't1':
23
+ case 1:
47
24
  return DEPTH_THRESHOLD_T1
48
- case 't2':
25
+ case 2:
49
26
  return DEPTH_THRESHOLD_T2
50
- case 't3':
27
+ case 3:
51
28
  return DEPTH_THRESHOLD_T3
52
- case 't4':
29
+ case 4:
53
30
  return DEPTH_THRESHOLD_T4
54
- case 't5':
31
+ default:
55
32
  return DEPTH_THRESHOLD_T5
56
33
  }
57
34
  }
58
35
 
59
- export function getResourceTier(itemId: number): ResourceTier {
60
- const entry = RESOURCE_CATALOG.find((r) => r.id === itemId)
61
- return entry ? entry.tier : 't5'
36
+ export function getResourceTier(itemId: number): number {
37
+ return getItem(itemId).tier
62
38
  }
63
39
 
64
40
  export function getResourceWeight(itemId: number, stratum: number): number {
@@ -69,24 +45,24 @@ export function getResourceWeight(itemId: number, stratum: number): number {
69
45
  const depthAbove = stratum - threshold
70
46
 
71
47
  switch (tier) {
72
- case 't1':
48
+ case 1:
73
49
  if (stratum < 2000) return 100
74
50
  if (stratum < 10000) return 80
75
51
  if (stratum < 30000) return 50
76
52
  return 30
77
- case 't2':
53
+ case 2:
78
54
  if (depthAbove < 3000) return 40
79
55
  if (depthAbove < 8000) return 60
80
56
  return 50
81
- case 't3':
57
+ case 3:
82
58
  if (depthAbove < 5000) return 20
83
59
  if (depthAbove < 15000) return 35
84
60
  return 40
85
- case 't4':
61
+ case 4:
86
62
  if (depthAbove < 10000) return 10
87
63
  if (depthAbove < 25000) return 20
88
64
  return 30
89
- case 't5':
65
+ default:
90
66
  return 10
91
67
  }
92
68
  }
@@ -76,12 +76,12 @@ export function computeContainerCapabilities(stats: Record<string, number>): {
76
76
  } {
77
77
  const density = stats['density'] ?? 500
78
78
  const strength = stats['strength'] ?? 500
79
- const fineness = stats['fineness'] ?? 500
79
+ const hardness = stats['hardness'] ?? 500
80
80
  const saturation = stats['saturation'] ?? 500
81
81
 
82
82
  const hullmass = 25000 + 75 * density
83
83
 
84
- const statSum = strength + fineness + saturation
84
+ const statSum = strength + hardness + saturation
85
85
  const exponent = statSum / 2997
86
86
  const capacity = Math.floor(1000000 * Math.pow(10, exponent))
87
87
 
@@ -94,12 +94,12 @@ export function computeContainerT2Capabilities(stats: Record<string, number>): {
94
94
  } {
95
95
  const strength = stats['strength'] ?? 0
96
96
  const density = stats['density'] ?? 0
97
- const fineness = stats['fineness'] ?? 0
97
+ const hardness = stats['hardness'] ?? 0
98
98
  const saturation = stats['saturation'] ?? 0
99
99
 
100
100
  const hullmass = 20000 + 50 * density
101
101
 
102
- const statSum = strength + fineness + saturation
102
+ const statSum = strength + hardness + saturation
103
103
  const exponent = statSum / 2500
104
104
  const capacity = Math.floor(1500000 * Math.pow(10, exponent))
105
105
 
@@ -18,11 +18,11 @@ export class EntityInventory extends ServerContract.Types.cargo_item {
18
18
  }
19
19
 
20
20
  get name(): string {
21
- return this.item.displayName
21
+ return this.item.name
22
22
  }
23
23
 
24
24
  get unitMass(): UInt32 {
25
- return this.item.mass
25
+ return UInt32.from(this.item.mass)
26
26
  }
27
27
 
28
28
  get totalMass(): UInt64 {
@@ -3,13 +3,16 @@ import {ServerContract} from '../contracts'
3
3
  import {PackedModuleInput, Ship, ShipStateInput} from './ship'
4
4
  import {computeWarehouseCapabilities, Warehouse, WarehouseStateInput} from './warehouse'
5
5
  import {Container, ContainerStateInput} from './container'
6
+ import {ITEM_SHIP_T1_PACKED, ITEM_WAREHOUSE_T1_PACKED} from '../data/item-ids'
7
+ import {getEntityLayout} from '../data/recipes-runtime'
8
+ import {itemMetadata} from '../data/metadata'
9
+ import {getItem} from '../market/items'
6
10
  import {
7
- getEntitySlotLayout,
8
- getModuleRecipeByItemId,
9
- ITEM_SHIP_T1_PACKED,
10
- ITEM_WAREHOUSE_T1_PACKED,
11
- } from '../data/recipes'
12
- import {getModuleCapabilityType, MODULE_STORAGE, moduleAccepts} from '../capabilities/modules'
11
+ getModuleCapabilityType,
12
+ MODULE_STORAGE,
13
+ moduleAccepts,
14
+ moduleSlotTypeToCode,
15
+ } from '../capabilities/modules'
13
16
  import {computeShipCapabilities, computeStorageCapabilities} from './ship-deploy'
14
17
  import {decodeCraftedItemStats} from '../derivation/crafting'
15
18
 
@@ -18,9 +21,10 @@ function assignModulesToSlots(
18
21
  modules: PackedModuleInput[],
19
22
  entityLabel: string
20
23
  ): ServerContract.Types.module_entry[] {
21
- const slots = getEntitySlotLayout(packedEntityItemId)
24
+ const layout = getEntityLayout(packedEntityItemId)
25
+ const slots = layout?.slots ?? []
22
26
  const result: Array<{type: number; installed?: ServerContract.Types.packed_module}> = slots.map(
23
- (s) => ({type: s.type, installed: undefined})
27
+ (s) => ({type: moduleSlotTypeToCode(s.type), installed: undefined})
24
28
  )
25
29
 
26
30
  for (const mod of modules) {
@@ -28,8 +32,12 @@ function assignModulesToSlots(
28
32
  const modType = getModuleCapabilityType(itemId)
29
33
  const slotIdx = result.findIndex((r) => !r.installed && moduleAccepts(r.type, modType))
30
34
  if (slotIdx === -1) {
31
- const recipe = getModuleRecipeByItemId(itemId)
32
- const modName = recipe?.name ?? `item ${itemId}`
35
+ let modName: string
36
+ try {
37
+ modName = getItem(itemId).name
38
+ } catch {
39
+ modName = itemMetadata[itemId]?.name ?? `item ${itemId}`
40
+ }
33
41
  throw new Error(
34
42
  `No compatible slot for module ${modName} (type ${modType}) on ${entityLabel}`
35
43
  )
@@ -15,11 +15,11 @@ export function computeShipHullCapabilities(stats: Record<string, number>): {
15
15
  } {
16
16
  const density = stats.density ?? 500
17
17
  const strength = stats.strength ?? 500
18
- const fineness = stats.fineness ?? 500
18
+ const hardness = stats.hardness ?? 500
19
19
  const saturation = stats.saturation ?? 500
20
20
 
21
21
  const hullmass = 25000 + 75 * density
22
- const statSum = strength + fineness + saturation
22
+ const statSum = strength + hardness + saturation
23
23
  const exponent = statSum / 2997.0
24
24
  const capacity = Math.floor(1000000 * Math.pow(10, exponent))
25
25
 
@@ -76,11 +76,11 @@ export function computeLoaderCapabilities(stats: Record<string, number>): {
76
76
  thrust: number
77
77
  quantity: number
78
78
  } {
79
- const fin = stats.fineness ?? 500
79
+ const hrd = stats.hardness ?? 500
80
80
  const pla = stats.plasticity ?? 500
81
81
 
82
82
  return {
83
- mass: Math.max(200, 2000 - Math.floor(fin * 2)),
83
+ mass: Math.max(200, 2000 - Math.floor(hrd * 2)),
84
84
  thrust: 1 + Math.floor(pla / 500),
85
85
  quantity: 1,
86
86
  }
@@ -122,10 +122,10 @@ export function computeStorageCapabilities(
122
122
  capacityBonus: number
123
123
  } {
124
124
  const strength = stats.strength ?? 500
125
- const fineness = stats.fineness ?? 500
125
+ const hardness = stats.hardness ?? 500
126
126
  const saturation = stats.saturation ?? 500
127
127
 
128
- const statSum = strength + fineness + saturation
128
+ const statSum = strength + hardness + saturation
129
129
  const capacityBonus = Math.floor(
130
130
  (baseCapacity * (10 + Math.floor((statSum * 10) / 2997))) / 100
131
131
  )
@@ -139,11 +139,11 @@ export function computeWarehouseHullCapabilities(stats: Record<string, number>):
139
139
  } {
140
140
  const density = stats.density ?? 500
141
141
  const strength = stats.strength ?? 500
142
- const fineness = stats.fineness ?? 500
142
+ const hardness = stats.hardness ?? 500
143
143
  const saturation = stats.saturation ?? 500
144
144
 
145
145
  const hullmass = 25000 + 75 * density
146
- const statSum = strength + fineness + saturation
146
+ const statSum = strength + hardness + saturation
147
147
  const exponent = statSum / 2997.0
148
148
  const capacity = Math.floor(20000000 * Math.pow(10, exponent))
149
149
 
@@ -1,6 +1,8 @@
1
1
  export * from './contracts'
2
2
  export * from './errors'
3
3
  export * from './types'
4
+ export * from './data/item-ids'
5
+ export * from './data/recipes-runtime'
4
6
 
5
7
  import {ServerContract} from './contracts'
6
8
 
@@ -182,51 +184,6 @@ export {
182
184
  } from './data/capabilities'
183
185
  export type {CapabilityAttribute, StatMapping} from './data/capabilities'
184
186
 
185
- export {
186
- components,
187
- entityRecipes,
188
- moduleRecipes,
189
- getComponentById,
190
- getEntityRecipe,
191
- getEntityRecipeByItemId,
192
- getModuleRecipe,
193
- getModuleRecipeByItemId,
194
- getAllCraftableItems,
195
- getComponentsForCategory,
196
- getComponentsForStat,
197
- ITEM_HULL_PLATES,
198
- ITEM_CARGO_LINING,
199
- ITEM_CONTAINER_T1_PACKED,
200
- ITEM_THRUSTER_CORE,
201
- ITEM_POWER_CELL,
202
- ITEM_ENGINE_T1,
203
- ITEM_GENERATOR_T1,
204
- ITEM_SHIP_T1_PACKED,
205
- ITEM_WAREHOUSE_T1_PACKED,
206
- ITEM_MATTER_CONDUIT,
207
- ITEM_SURVEY_PROBE,
208
- ITEM_CARGO_ARM,
209
- ITEM_TOOL_BIT,
210
- ITEM_REACTION_CHAMBER,
211
- ITEM_GATHERER_T1,
212
- ITEM_LOADER_T1,
213
- ITEM_CRAFTER_T1,
214
- ITEM_STORAGE_T1,
215
- ITEM_HULL_PLATES_T2,
216
- ITEM_CARGO_LINING_T2,
217
- ITEM_CONTAINER_T2_PACKED,
218
- ITEM_FOCUSING_ARRAY,
219
- } from './data/recipes'
220
- export type {
221
- ComponentDefinition,
222
- ComponentStat,
223
- RecipeInput,
224
- EntityRecipe,
225
- ModuleRecipe,
226
- ModuleSlot,
227
- CraftableItem,
228
- } from './data/recipes'
229
-
230
187
  export {
231
188
  encodeStats,
232
189
  encodeGatheredCargoStats,
@@ -239,7 +196,6 @@ export {
239
196
  computeEntityStats,
240
197
  blendCargoStacks,
241
198
  blendCrossGroup,
242
- categoryItemMass,
243
199
  computeInputMass,
244
200
  computeCraftedOutputStats,
245
201
  } from './derivation/crafting'
@@ -321,7 +277,6 @@ export {
321
277
  computeCrafterDrain,
322
278
  } from './nft/description'
323
279
 
324
- export {getEntitySlotLayout} from './data/recipes'
325
280
  export {
326
281
  ITEM_TYPE_RESOURCE,
327
282
  ITEM_TYPE_COMPONENT,