@shipload/sdk 2.0.0-rc8 → 2.0.0-rc9

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.
@@ -0,0 +1,173 @@
1
+ import {
2
+ ITEM_ENGINE_T1,
3
+ ITEM_EXTRACTOR_T1,
4
+ ITEM_GENERATOR_T1,
5
+ ITEM_LOADER_T1,
6
+ ITEM_MANUFACTURING_T1,
7
+ ITEM_STORAGE_T1,
8
+ MODULE_CRAFTER,
9
+ MODULE_ENGINE,
10
+ MODULE_EXTRACTOR,
11
+ MODULE_GENERATOR,
12
+ MODULE_LOADER,
13
+ MODULE_STORAGE,
14
+ getModuleCapabilityType,
15
+ } from '../capabilities/modules'
16
+ import {
17
+ ITEM_CONTAINER_T1_PACKED,
18
+ ITEM_CONTAINER_T2_PACKED,
19
+ ITEM_SHIP_T1_PACKED,
20
+ ITEM_WAREHOUSE_T1_PACKED,
21
+ } from '../data/recipes'
22
+ import {decodeStat} from '../derivation/crafting'
23
+
24
+ function idiv(a: number, b: number): number {
25
+ return Math.floor(a / b)
26
+ }
27
+
28
+ export function computeBaseHullmass(seed: bigint): number {
29
+ const density = decodeStat(seed, 1)
30
+ return 25000 + 75 * density
31
+ }
32
+
33
+ export function computeBaseCapacityShip(seed: bigint): number {
34
+ const s = decodeStat(seed, 0) + decodeStat(seed, 2) + decodeStat(seed, 3)
35
+ return Math.floor(1_000_000 * Math.pow(10, s / 2997))
36
+ }
37
+
38
+ export function computeBaseCapacityWarehouse(seed: bigint): number {
39
+ const s = decodeStat(seed, 0) + decodeStat(seed, 2) + decodeStat(seed, 3)
40
+ return Math.floor(20_000_000 * Math.pow(10, s / 2997))
41
+ }
42
+
43
+ export const computeEngineThrust = (vol: number): number => 400 + idiv(vol * 3, 4)
44
+ export const computeEngineDrain = (thm: number): number => Math.max(30, 50 - idiv(thm, 70))
45
+ export const computeGeneratorCap = (res: number): number => 300 + idiv(res, 6)
46
+ export const computeGeneratorRech = (clr: number): number => 5 + idiv(clr * 15, 1000)
47
+ export const computeExtractorRate = (str: number): number => 200 + str
48
+ export const computeExtractorDrain = (con: number): number => Math.max(10, 50 - idiv(con, 20))
49
+ export const computeExtractorDepth = (tol: number): number => 200 + idiv(tol * 3, 2)
50
+ export const computeExtractorDrill = (ref: number): number => 100 + idiv(ref * 4, 5)
51
+ export const computeLoaderMass = (duc: number): number => Math.max(200, 2000 - duc * 2)
52
+ export const computeLoaderThrust = (pla: number): number => 1 + idiv(pla, 500)
53
+ export const computeCrafterSpeed = (rea: number): number => 100 + idiv(rea * 4, 5)
54
+ export const computeCrafterDrain = (clr: number): number => Math.max(5, 30 - idiv(clr, 33))
55
+
56
+ export function entityDisplayName(itemId: number): string {
57
+ switch (itemId) {
58
+ case ITEM_SHIP_T1_PACKED:
59
+ return 'Ship T1'
60
+ case ITEM_WAREHOUSE_T1_PACKED:
61
+ return 'Warehouse T1'
62
+ case ITEM_CONTAINER_T1_PACKED:
63
+ return 'Container T1'
64
+ case ITEM_CONTAINER_T2_PACKED:
65
+ return 'Container T2'
66
+ default:
67
+ return 'Entity'
68
+ }
69
+ }
70
+
71
+ export function moduleDisplayName(itemId: number): string {
72
+ switch (itemId) {
73
+ case ITEM_ENGINE_T1:
74
+ return 'Engine T1'
75
+ case ITEM_GENERATOR_T1:
76
+ return 'Generator T1'
77
+ case ITEM_EXTRACTOR_T1:
78
+ return 'Extractor T1'
79
+ case ITEM_LOADER_T1:
80
+ return 'Loader T1'
81
+ case ITEM_MANUFACTURING_T1:
82
+ return 'Manufacturing T1'
83
+ case ITEM_STORAGE_T1:
84
+ return 'Storage T1'
85
+ default:
86
+ return 'Module'
87
+ }
88
+ }
89
+
90
+ export function formatModuleLine(slot: number, itemId: number, seed: bigint): string {
91
+ let out = `Slot ${slot} - `
92
+ if (itemId === 0) {
93
+ out += '(empty)'
94
+ return out
95
+ }
96
+
97
+ out += moduleDisplayName(itemId)
98
+ const subtype = getModuleCapabilityType(itemId)
99
+
100
+ switch (subtype) {
101
+ case MODULE_ENGINE: {
102
+ const vol = decodeStat(seed, 0)
103
+ const thm = decodeStat(seed, 1)
104
+ out += ` Thrust ${computeEngineThrust(vol)} Drain ${computeEngineDrain(thm)}`
105
+ break
106
+ }
107
+ case MODULE_GENERATOR: {
108
+ const res = decodeStat(seed, 0)
109
+ const clr = decodeStat(seed, 1)
110
+ out += ` Capacity ${computeGeneratorCap(res)} Recharge ${computeGeneratorRech(clr)}`
111
+ break
112
+ }
113
+ case MODULE_EXTRACTOR: {
114
+ const str = decodeStat(seed, 0)
115
+ const tol = decodeStat(seed, 1)
116
+ const con = decodeStat(seed, 3)
117
+ const ref = decodeStat(seed, 4)
118
+ out += ` Rate ${computeExtractorRate(str)} Depth ${computeExtractorDepth(tol)} Drill ${computeExtractorDrill(ref)} Drain ${computeExtractorDrain(con)}`
119
+ break
120
+ }
121
+ case MODULE_LOADER: {
122
+ const duc = decodeStat(seed, 0)
123
+ const pla = decodeStat(seed, 1)
124
+ out += ` Mass ${computeLoaderMass(duc)} Thrust ${computeLoaderThrust(pla)}`
125
+ break
126
+ }
127
+ case MODULE_CRAFTER: {
128
+ const rea = decodeStat(seed, 0)
129
+ const clr = decodeStat(seed, 1)
130
+ out += ` Speed ${computeCrafterSpeed(rea)} Drain ${computeCrafterDrain(clr)}`
131
+ break
132
+ }
133
+ case MODULE_STORAGE: {
134
+ const str = decodeStat(seed, 0)
135
+ const duc = decodeStat(seed, 1)
136
+ const pur = decodeStat(seed, 2)
137
+ const sum = str + duc + pur
138
+ const pct = 10 + idiv(sum * 10, 2997)
139
+ out += ` +${pct}% capacity`
140
+ break
141
+ }
142
+ }
143
+ return out
144
+ }
145
+
146
+ export function buildEntityDescription(
147
+ itemId: number,
148
+ hullSeed: bigint,
149
+ moduleItems: number[],
150
+ moduleSeeds: bigint[]
151
+ ): string {
152
+ const hullMass = computeBaseHullmass(hullSeed)
153
+ let baseCapacity = 0
154
+ if (itemId === ITEM_SHIP_T1_PACKED) {
155
+ baseCapacity = computeBaseCapacityShip(hullSeed)
156
+ } else if (itemId === ITEM_WAREHOUSE_T1_PACKED) {
157
+ baseCapacity = computeBaseCapacityWarehouse(hullSeed)
158
+ }
159
+
160
+ let out = entityDisplayName(itemId)
161
+ out += ` - Hull ${hullMass} mass`
162
+ if (baseCapacity > 0) {
163
+ out += ` * ${baseCapacity} capacity`
164
+ }
165
+ out += '\n\n'
166
+
167
+ for (let i = 0; i < moduleItems.length; i++) {
168
+ out += formatModuleLine(i, moduleItems[i], moduleSeeds[i] ?? 0n)
169
+ out += '\n'
170
+ }
171
+
172
+ return out
173
+ }
@@ -0,0 +1,81 @@
1
+ import {getEntitySlotLayout} from '../data/recipes'
2
+ import {
3
+ ITEM_TYPE_COMPONENT,
4
+ ITEM_TYPE_ENTITY,
5
+ ITEM_TYPE_MODULE,
6
+ ITEM_TYPE_RESOURCE,
7
+ itemTypeCode,
8
+ } from '../data/tiers'
9
+
10
+ export interface NFTInstalledModule {
11
+ item_id: number
12
+ seed: string
13
+ }
14
+
15
+ export interface NFTModuleSlot {
16
+ type: number
17
+ installed?: NFTInstalledModule
18
+ }
19
+
20
+ export interface NFTCargoItem {
21
+ item_id: number
22
+ quantity: number
23
+ seed: string
24
+ modules?: NFTModuleSlot[]
25
+ }
26
+
27
+ export interface NFTCommonBase {
28
+ quantity: number
29
+ seed: string
30
+ origin_x: string
31
+ origin_y: string
32
+ }
33
+
34
+ export function readCommonBase(data: Record<string, any>): NFTCommonBase {
35
+ return {
36
+ quantity: Number(data.quantity),
37
+ seed: String(data.seed),
38
+ origin_x: String(data.origin_x),
39
+ origin_y: String(data.origin_y),
40
+ }
41
+ }
42
+
43
+ export function deserializeScalar(data: Record<string, any>, itemId: number): NFTCargoItem {
44
+ const base = readCommonBase(data)
45
+ return {item_id: itemId, quantity: base.quantity, seed: base.seed}
46
+ }
47
+
48
+ export const deserializeResource = deserializeScalar
49
+ export const deserializeComponent = deserializeScalar
50
+ export const deserializeModule = deserializeScalar
51
+
52
+ export function deserializeEntity(data: Record<string, any>, itemId: number): NFTCargoItem {
53
+ const base = readCommonBase(data)
54
+ const moduleItems: number[] = (data.module_items ?? []).map((v: any) => Number(v))
55
+ const moduleSeeds: string[] = (data.module_seeds ?? []).map((v: any) => String(v))
56
+ const layout = getEntitySlotLayout(itemId)
57
+
58
+ const modules: NFTModuleSlot[] = layout.map((slot, i) => ({
59
+ type: slot.type,
60
+ installed:
61
+ moduleItems[i] && moduleItems[i] !== 0
62
+ ? {item_id: moduleItems[i], seed: moduleSeeds[i]}
63
+ : undefined,
64
+ }))
65
+
66
+ return {item_id: itemId, quantity: base.quantity, seed: base.seed, modules}
67
+ }
68
+
69
+ export function deserializeAsset(data: Record<string, any>, itemId: number): NFTCargoItem {
70
+ const type = itemTypeCode(itemId)
71
+ switch (type) {
72
+ case ITEM_TYPE_RESOURCE:
73
+ case ITEM_TYPE_COMPONENT:
74
+ case ITEM_TYPE_MODULE:
75
+ return deserializeScalar(data, itemId)
76
+ case ITEM_TYPE_ENTITY:
77
+ return deserializeEntity(data, itemId)
78
+ default:
79
+ throw new Error(`unknown item type ${type} for item ${itemId}`)
80
+ }
81
+ }
@@ -0,0 +1,2 @@
1
+ export * from './deserializers'
2
+ export * from './description'
@@ -3,7 +3,7 @@ import type {UInt16Type, UInt64Type} from '@wharfkit/antelope'
3
3
  import type {ResourceCategory, ResourceTier} from '../types'
4
4
  import {getItem} from '../market/items'
5
5
  import {getComponentById, getModuleRecipeByItemId, getEntityRecipeByItemId} from '../data/recipes'
6
- import {isModuleItem, getModuleCapabilityType, MODULE_ENGINE, MODULE_GENERATOR, MODULE_EXTRACTOR, MODULE_LOADER, MODULE_CRAFTER} from '../capabilities/modules'
6
+ import {isModuleItem, getModuleCapabilityType, MODULE_ENGINE, MODULE_GENERATOR, MODULE_EXTRACTOR, MODULE_LOADER, MODULE_CRAFTER, MODULE_STORAGE} from '../capabilities/modules'
7
7
  import {decodeCraftedItemStats} from '../derivation/crafting'
8
8
  import {deriveResourceStats} from '../derivation/stratum'
9
9
  import {getStatDefinitions} from '../derivation/stats'
@@ -162,6 +162,16 @@ function computeCapabilityGroup(moduleType: number, stats: Record<string, number
162
162
  {label: 'Drain', value: caps.drain},
163
163
  ]}
164
164
  }
165
+ case MODULE_STORAGE: {
166
+ const str = stats.strength ?? 500
167
+ const duc = stats.ductility ?? 500
168
+ const pur = stats.purity ?? 500
169
+ const statSum = str + duc + pur
170
+ const pct = 10 + Math.floor(statSum * 10 / 2997)
171
+ return {capability: 'Storage', attributes: [
172
+ {label: 'Capacity Bonus', value: pct},
173
+ ]}
174
+ }
165
175
  default:
166
176
  return undefined
167
177
  }
@@ -14,6 +14,7 @@ import {
14
14
  Checksum256,
15
15
  Int64,
16
16
  Int64Type,
17
+ UInt16,
17
18
  UInt32,
18
19
  UInt32Type,
19
20
  UInt64,
@@ -126,7 +127,8 @@ export function calc_rechargetime(
126
127
  }
127
128
 
128
129
  export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
129
- return calc_rechargetime(ship.generator.capacity, ship.energy, ship.generator.recharge)
130
+ if (!ship.generator) return UInt32.from(0)
131
+ return calc_rechargetime(ship.generator.capacity, ship.energy ?? UInt16.from(0), ship.generator.recharge)
130
132
  }
131
133
 
132
134
  export function calc_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
@@ -139,7 +141,9 @@ export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?:
139
141
  }
140
142
 
141
143
  export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
142
- return calc_acceleration(Number(ship.loaders.thrust), Number(mass) + Number(ship.loaders.mass))
144
+ const thrust = ship.loaders ? Number(ship.loaders.thrust) : 0
145
+ const loaderMass = ship.loaders ? Number(ship.loaders.mass) : 0
146
+ return calc_acceleration(thrust, Number(mass) + loaderMass)
143
147
  }
144
148
 
145
149
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -148,7 +152,8 @@ export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UIn
148
152
  }
149
153
 
150
154
  export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
151
- return calc_acceleration(Number(ship.engines.thrust), Number(mass))
155
+ const thrust = ship.engines ? Number(ship.engines.thrust) : 0
156
+ return calc_acceleration(thrust, Number(mass))
152
157
  }
153
158
 
154
159
  export function calc_acceleration(thrust: number, mass: number): number {
@@ -160,7 +165,7 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
160
165
 
161
166
  mass.add(ship.hullmass)
162
167
 
163
- if (ship.loaders.quantity.gt(UInt32.zero)) {
168
+ if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
164
169
  mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
165
170
  }
166
171
 
@@ -195,6 +200,7 @@ export function calculateTransferTime(
195
200
  return UInt32.from(0)
196
201
  }
197
202
 
203
+ if (!ship.loaders) return UInt32.from(0)
198
204
  mass = UInt64.from(mass).adding(ship.loaders.mass)
199
205
  const transfer_time = calc_loader_flighttime(ship, mass)
200
206
  return transfer_time.dividing(ship.loaders.quantity)
@@ -252,17 +258,17 @@ export function calculateLoadTimeBreakdown(
252
258
  let unloadTime = 0
253
259
  let loadTime = 0
254
260
 
255
- if (mass_unload.gt(UInt64.zero)) {
261
+ if (mass_unload.gt(UInt64.zero) && ship.loaders) {
256
262
  const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
257
263
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
258
264
  }
259
265
 
260
- if (mass_load.gt(UInt64.zero)) {
266
+ if (mass_load.gt(UInt64.zero) && ship.loaders) {
261
267
  const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
262
268
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
263
269
  }
264
270
 
265
- const numLoaders = Number(ship.loaders.quantity)
271
+ const numLoaders = ship.loaders ? Number(ship.loaders.quantity) : 0
266
272
  const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
267
273
  const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
268
274
  const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
@@ -307,6 +313,7 @@ export function estimateTravelTime(
307
313
  if (
308
314
  loadMass &&
309
315
  UInt32.from(loadMass).gt(UInt32.zero) &&
316
+ ship.loaders &&
310
317
  ship.loaders.quantity.gt(UInt32.zero)
311
318
  ) {
312
319
  const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
@@ -316,6 +323,7 @@ export function estimateTravelTime(
316
323
  if (
317
324
  unloadMass &&
318
325
  UInt32.from(unloadMass).gt(UInt32.zero) &&
326
+ ship.loaders &&
319
327
  ship.loaders.quantity.gt(UInt32.zero)
320
328
  ) {
321
329
  const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
@@ -346,8 +354,9 @@ export function estimateDealTravelTime(
346
354
  }
347
355
 
348
356
  export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): boolean {
357
+ if (!ship.engines) return false
349
358
  const energyNeeded = UInt64.from(distance).dividing(PRECISION).multiplying(ship.engines.drain)
350
- return UInt64.from(ship.energy).gte(energyNeeded)
359
+ return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
351
360
  }
352
361
 
353
362
  export interface TransferEntity {
@@ -28,7 +28,7 @@ export type ShipEntity = Entity &
28
28
  extractor?: ServerContract.Types.extractor_stats
29
29
  }
30
30
 
31
- export type WarehouseEntity = Entity & StorageCapability & LoaderCapability & ScheduleCapability
31
+ export type WarehouseEntity = Entity & StorageCapability & Partial<LoaderCapability> & MassCapability & ScheduleCapability
32
32
 
33
33
  export type ContainerEntity = Entity & StorageCapability & MassCapability & ScheduleCapability
34
34
 
package/src/types.ts CHANGED
@@ -28,12 +28,12 @@ export const BASE_ORBITAL_MASS = 100000
28
28
 
29
29
  export interface ShipLike {
30
30
  coordinates: ServerContract.Types.coordinates
31
- hullmass: UInt32
32
- energy: UInt16
33
- engines: ServerContract.Types.movement_stats
34
- generator: ServerContract.Types.energy_stats
35
- loaders: ServerContract.Types.loader_stats
36
- capacity: UInt32
31
+ hullmass?: UInt32
32
+ energy?: UInt16
33
+ engines?: ServerContract.Types.movement_stats
34
+ generator?: ServerContract.Types.energy_stats
35
+ loaders?: ServerContract.Types.loader_stats
36
+ capacity?: UInt32
37
37
  }
38
38
 
39
39
  export interface CargoMassInfo {