@shipload/sdk 2.0.0-rc20 → 2.0.0-rc22

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,4 +1,4 @@
1
- import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
1
+ import {Name, TimePoint, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
2
2
  import {ServerContract} from '../contracts'
3
3
  import {Coordinates, PRECISION, TaskType} from '../types'
4
4
  import {
@@ -13,16 +13,10 @@ import {
13
13
  RECIPE_INPUTS_EXCESS,
14
14
  RECIPE_INPUTS_INSUFFICIENT,
15
15
  RECIPE_INPUTS_INVALID,
16
- RECIPE_INPUTS_MIXED,
17
16
  RECIPE_NOT_FOUND,
18
17
  SHIP_CARGO_NOT_LOADED,
19
18
  } from '../errors'
20
- import {
21
- getComponentById,
22
- getEntityRecipeByItemId,
23
- getModuleRecipeByItemId,
24
- RecipeInput,
25
- } from '../data/recipes'
19
+ import {getRecipe, RecipeInput} from '../data/recipes-runtime'
26
20
  import {getItem} from '../market/items'
27
21
  import {distanceBetweenCoordinates, lerp} from '../travel/travel'
28
22
  import {
@@ -296,14 +290,41 @@ export function projectEntity(entity: Projectable, options?: ProjectionOptions):
296
290
  return projected
297
291
  }
298
292
 
299
- function getRecipeForOutput(outputItemId: number): RecipeInput[] | undefined {
300
- const component = getComponentById(outputItemId)
301
- if (component) return component.recipe
302
- const moduleRecipe = getModuleRecipeByItemId(outputItemId)
303
- if (moduleRecipe) return moduleRecipe.recipe
304
- const entityRecipe = getEntityRecipeByItemId(outputItemId)
305
- if (entityRecipe) return entityRecipe.recipe
306
- return undefined
293
+ export interface ProjectableSnapshot extends Projectable {
294
+ current_task?: ServerContract.Types.task
295
+ pending_tasks?: ServerContract.Types.task[]
296
+ }
297
+
298
+ function buildRemainingProjectable(snapshot: ProjectableSnapshot): Projectable | null {
299
+ if (!snapshot.schedule) return null
300
+ const remainingTasks: ServerContract.Types.task[] = []
301
+ if (snapshot.current_task) remainingTasks.push(snapshot.current_task)
302
+ if (snapshot.pending_tasks?.length) remainingTasks.push(...snapshot.pending_tasks)
303
+ if (remainingTasks.length === 0) return null
304
+
305
+ const completedCount = snapshot.schedule.tasks.length - remainingTasks.length
306
+ let startedMs = snapshot.schedule.started.toMilliseconds()
307
+ for (let i = 0; i < completedCount; i++) {
308
+ startedMs += snapshot.schedule.tasks[i].duration.toNumber() * 1000
309
+ }
310
+
311
+ return {
312
+ ...snapshot,
313
+ schedule: ServerContract.Types.schedule.from({
314
+ started: TimePoint.fromMilliseconds(startedMs),
315
+ tasks: remainingTasks,
316
+ }),
317
+ }
318
+ }
319
+
320
+ export function projectFromCurrentState(snapshot: ProjectableSnapshot): ProjectedEntity {
321
+ const projectable = buildRemainingProjectable(snapshot)
322
+ return projectable ? projectEntity(projectable) : createProjectedEntity(snapshot)
323
+ }
324
+
325
+ function getRecipeInputsForOutput(outputItemId: number): RecipeInput[] | undefined {
326
+ const recipe = getRecipe(outputItemId)
327
+ return recipe?.inputs
307
328
  }
308
329
 
309
330
  function validateCraftTask(task: ServerContract.Types.task, projected: ProjectedEntity): void {
@@ -313,7 +334,7 @@ function validateCraftTask(task: ServerContract.Types.task, projected: Projected
313
334
  const inputs = task.cargo.slice(0, -1)
314
335
  const craftQuantity = output.quantity.toNumber()
315
336
 
316
- const recipe = getRecipeForOutput(output.item_id.toNumber())
337
+ const recipe = getRecipeInputsForOutput(output.item_id.toNumber())
317
338
  if (!recipe) throw new Error(RECIPE_NOT_FOUND)
318
339
 
319
340
  const groupedInputs: ServerContract.Types.cargo_item[][] = recipe.map(() => [])
@@ -321,15 +342,15 @@ function validateCraftTask(task: ServerContract.Types.task, projected: Projected
321
342
  let matched = false
322
343
  for (let ri = 0; ri < recipe.length; ri++) {
323
344
  const req = recipe[ri]
324
- if (req.itemId && req.itemId > 0) {
345
+ if ('itemId' in req) {
325
346
  if (input.item_id.toNumber() === req.itemId) {
326
347
  groupedInputs[ri].push(input)
327
348
  matched = true
328
349
  break
329
350
  }
330
- } else if (req.category) {
351
+ } else {
331
352
  const item = getItem(input.item_id)
332
- if (item.category === req.category) {
353
+ if (item.category === req.category && item.tier === req.tier) {
333
354
  groupedInputs[ri].push(input)
334
355
  matched = true
335
356
  break
@@ -348,15 +369,6 @@ function validateCraftTask(task: ServerContract.Types.task, projected: Projected
348
369
  const required = recipe[ri].quantity * craftQuantity
349
370
  if (provided < required) throw new Error(RECIPE_INPUTS_INSUFFICIENT)
350
371
  if (provided !== required) throw new Error(RECIPE_INPUTS_EXCESS)
351
-
352
- if (!recipe[ri].itemId && stacks.length > 1) {
353
- const firstItemId = stacks[0].item_id.toNumber()
354
- for (let si = 1; si < stacks.length; si++) {
355
- if (stacks[si].item_id.toNumber() !== firstItemId) {
356
- throw new Error(RECIPE_INPUTS_MIXED)
357
- }
358
- }
359
- }
360
372
  }
361
373
 
362
374
  for (const input of inputs) {
@@ -441,3 +453,11 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
441
453
 
442
454
  return projected
443
455
  }
456
+
457
+ export function projectFromCurrentStateAt(
458
+ snapshot: ProjectableSnapshot,
459
+ now: Date
460
+ ): ProjectedEntity {
461
+ const projectable = buildRemainingProjectable(snapshot)
462
+ return projectable ? projectEntityAt(projectable, now) : createProjectedEntity(snapshot)
463
+ }
@@ -174,7 +174,8 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
174
174
  }
175
175
 
176
176
  for (const cargo of cargos) {
177
- mass.add(getItem(cargo.item_id).mass.multiplying(cargo.quantity))
177
+ const cargoMass = getItem(cargo.item_id).mass * Number(UInt32.from(cargo.quantity))
178
+ mass.add(UInt64.from(cargoMass))
178
179
  }
179
180
 
180
181
  return mass
@@ -195,8 +196,8 @@ export function calculateTransferTime(
195
196
  const qty = quantities?.get(Number(cargo.item_id)) ?? 0
196
197
  if (qty > 0) {
197
198
  const good_mass = getItem(cargo.item_id).mass
198
- const cargo_mass = good_mass.multiplying(qty)
199
- mass = UInt64.from(mass).adding(cargo_mass)
199
+ const cargo_mass = good_mass * qty
200
+ mass = UInt64.from(mass).adding(UInt64.from(cargo_mass))
200
201
  }
201
202
  }
202
203
 
@@ -249,12 +250,12 @@ export function calculateLoadTimeBreakdown(
249
250
  const good = getItem(cargo.item_id)
250
251
 
251
252
  if (loadQty > 0) {
252
- const cargo_mass = good.mass.multiplying(loadQty)
253
- mass_load = UInt64.from(mass_load).adding(cargo_mass)
253
+ const cargo_mass = good.mass * loadQty
254
+ mass_load = UInt64.from(mass_load).adding(UInt64.from(cargo_mass))
254
255
  }
255
256
  if (unloadQty > 0) {
256
- const cargo_mass = good.mass.multiplying(unloadQty)
257
- mass_unload = UInt64.from(mass_unload).adding(cargo_mass)
257
+ const cargo_mass = good.mass * unloadQty
258
+ mass_unload = UInt64.from(mass_unload).adding(UInt64.from(cargo_mass))
258
259
  }
259
260
  }
260
261
  }
package/src/types.ts CHANGED
@@ -1,13 +1,4 @@
1
- import {
2
- Int64Type,
3
- Name,
4
- Struct,
5
- UInt16,
6
- UInt16Type,
7
- UInt32,
8
- UInt32Type,
9
- UInt64,
10
- } from '@wharfkit/antelope'
1
+ import {Int64Type, Name, UInt16, UInt16Type, UInt32, UInt32Type, UInt64} from '@wharfkit/antelope'
11
2
  import {ServerContract} from './contracts'
12
3
 
13
4
  export const PRECISION = 10000
@@ -110,8 +101,20 @@ export interface Distance {
110
101
  distance: UInt16
111
102
  }
112
103
 
104
+ export type ItemType = 'resource' | 'component' | 'module' | 'entity'
113
105
  export type ResourceCategory = 'ore' | 'crystal' | 'gas' | 'regolith' | 'biomass'
114
106
  export type ResourceTier = 't1' | 't2' | 't3' | 't4' | 't5'
107
+ export type ModuleType =
108
+ | 'any'
109
+ | 'engine'
110
+ | 'generator'
111
+ | 'gatherer'
112
+ | 'loader'
113
+ | 'warp'
114
+ | 'crafter'
115
+ | 'launcher'
116
+ | 'storage'
117
+ | 'hauler'
115
118
 
116
119
  export const TIER_ADJECTIVES: Record<number, string> = {
117
120
  1: 'Crude',
@@ -138,27 +141,18 @@ export function tierNumber(tier: string): number {
138
141
  return Number(String(tier).replace(/^t/i, ''))
139
142
  }
140
143
 
141
- @Struct.type('item')
142
- export class Item extends Struct {
143
- @Struct.field(UInt16)
144
- id!: UInt16
145
- @Struct.field('string')
146
- name!: string
147
- @Struct.field('string')
148
- description!: string
149
- @Struct.field(UInt32)
150
- mass!: UInt32
151
- @Struct.field('string')
152
- category!: ResourceCategory
153
- @Struct.field('string')
154
- tier!: ResourceTier
155
- @Struct.field('string')
156
- color!: string
157
-
158
- get displayName(): string {
159
- if (this.name && this.name.length > 0) return this.name
160
- const adj = TIER_ADJECTIVES[tierNumber(this.tier)] ?? 'Unknown'
161
- const cat = CATEGORY_LABELS[this.category] ?? 'Resource'
162
- return `${adj} ${cat}`
163
- }
144
+ export interface Item {
145
+ id: number
146
+ name: string
147
+ description: string
148
+ color: string
149
+ mass: number
150
+ type: ItemType
151
+ tier: number
152
+ category?: ResourceCategory
153
+ moduleType?: ModuleType
154
+ }
155
+
156
+ export function formatTier(tier: number): string {
157
+ return 'T' + tier
164
158
  }