@shipload/sdk 1.0.0-next.16 → 1.0.0-next.18

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.
Files changed (41) hide show
  1. package/lib/shipload.d.ts +111 -26
  2. package/lib/shipload.js +3443 -2896
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +3416 -2884
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +3 -2
  7. package/lib/testing.js +65 -50
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +66 -51
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/capabilities/gathering.ts +17 -7
  13. package/src/capabilities/modules.ts +6 -0
  14. package/src/contracts/server.ts +7 -4
  15. package/src/data/capabilities.ts +6 -1
  16. package/src/data/capability-formulas.ts +7 -1
  17. package/src/data/colors.ts +12 -12
  18. package/src/data/item-ids.ts +13 -12
  19. package/src/data/items.json +30 -23
  20. package/src/data/metadata.ts +36 -23
  21. package/src/data/recipes.json +111 -46
  22. package/src/derivation/capabilities.ts +18 -7
  23. package/src/derivation/capability-mappings.ts +2 -0
  24. package/src/derivation/index.ts +7 -2
  25. package/src/derivation/reserve-regen.ts +34 -0
  26. package/src/derivation/resources.ts +9 -1
  27. package/src/derivation/stratum.ts +15 -19
  28. package/src/derivation/tiers.ts +28 -7
  29. package/src/index-module.ts +25 -3
  30. package/src/managers/actions.ts +104 -12
  31. package/src/managers/context.ts +9 -0
  32. package/src/managers/index.ts +2 -0
  33. package/src/managers/nft.ts +28 -0
  34. package/src/nft/atomicassets.ts +124 -1
  35. package/src/nft/buildImmutableData.ts +316 -0
  36. package/src/nft/description.ts +1 -3
  37. package/src/nft/index.ts +1 -0
  38. package/src/resolution/describe-module.ts +3 -4
  39. package/src/resolution/resolve-item.ts +0 -1
  40. package/src/shipload.ts +5 -0
  41. package/src/types.ts +1 -0
@@ -0,0 +1,316 @@
1
+ import {Serializer} from '@wharfkit/antelope'
2
+ import {getItem} from '../data/catalog'
3
+ import {
4
+ getModuleCapabilityType,
5
+ MODULE_CRAFTER,
6
+ MODULE_ENGINE,
7
+ MODULE_GATHERER,
8
+ MODULE_GENERATOR,
9
+ MODULE_HAULER,
10
+ MODULE_LOADER,
11
+ MODULE_STORAGE,
12
+ MODULE_WARP,
13
+ } from '../capabilities/modules'
14
+ import {decodeStat, decodeCraftedItemStats} from '../derivation/crafting'
15
+ import {getStatDefinitions} from '../derivation/stats'
16
+ import type {ResourceCategory} from '../types'
17
+ import {Types as ServerTypes} from '../contracts/server'
18
+ import {
19
+ buildEntityDescription,
20
+ computeCrafterDrain,
21
+ computeCrafterSpeed,
22
+ computeEngineDrain,
23
+ computeEngineThrust,
24
+ computeGathererDepth,
25
+ computeGathererDrain,
26
+ computeGathererYield,
27
+ computeGeneratorCap,
28
+ computeGeneratorRech,
29
+ computeHaulerCapacity,
30
+ computeHaulerDrain,
31
+ computeHaulerEfficiency,
32
+ computeLoaderMass,
33
+ computeLoaderThrust,
34
+ computeWarpRange,
35
+ } from './description'
36
+
37
+ export type AtomicAttributeType =
38
+ | 'string'
39
+ | 'uint8'
40
+ | 'uint16'
41
+ | 'uint32'
42
+ | 'uint64'
43
+ | 'int32'
44
+ | 'image'
45
+ | 'ipfs'
46
+ | 'UINT16_VEC'
47
+ | 'UINT64_VEC'
48
+
49
+ export interface ImmutableEntry {
50
+ first: string
51
+ second: [AtomicAttributeType, unknown]
52
+ }
53
+
54
+ export interface ImmutableModuleSlot {
55
+ type?: number | string | bigint
56
+ installed?: {item_id: number | string | bigint; stats: number | string | bigint}
57
+ }
58
+
59
+ export function moduleSlotsForImmutable(
60
+ modules: ServerTypes.module_entry[]
61
+ ): ImmutableModuleSlot[] {
62
+ return modules.map((m) => ({
63
+ type: Number(m.type.toString()),
64
+ installed: m.installed
65
+ ? {
66
+ item_id: Number(m.installed.item_id.toString()),
67
+ stats: BigInt(m.installed.stats.toString()),
68
+ }
69
+ : undefined,
70
+ }))
71
+ }
72
+
73
+ const IMAGE_HOST_URL = 'https://item.shiploadgame.com/item'
74
+
75
+ function bytesToBase64Url(bytes: Uint8Array): string {
76
+ let binary = ''
77
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]!)
78
+ const b64 = btoa(binary)
79
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
80
+ }
81
+
82
+ export function computeNftImageUrl(
83
+ item: {item_id: number; stats: bigint; modules: ImmutableModuleSlot[]; quantity: number},
84
+ originX: number,
85
+ originY: number
86
+ ): string {
87
+ const payload = ServerTypes.nft_item_payload.from({
88
+ item: {
89
+ item_id: item.item_id,
90
+ stats: String(item.stats),
91
+ modules: item.modules,
92
+ quantity: item.quantity,
93
+ },
94
+ location: {x: String(originX), y: String(originY)},
95
+ })
96
+ const bytes = Serializer.encode({object: payload}).array
97
+ return `${IMAGE_HOST_URL}/${bytesToBase64Url(bytes)}.png`
98
+ }
99
+
100
+ function commonBaseImmutable(
101
+ quantity: number,
102
+ stats: bigint,
103
+ originX: number,
104
+ originY: number,
105
+ img: string
106
+ ): ImmutableEntry[] {
107
+ return [
108
+ {first: 'quantity', second: ['uint32', quantity]},
109
+ {first: 'stats', second: ['uint64', String(stats)]},
110
+ {first: 'origin_x', second: ['int32', originX]},
111
+ {first: 'origin_y', second: ['int32', originY]},
112
+ {first: 'img', second: ['string', img]},
113
+ ]
114
+ }
115
+
116
+ export function buildResourceImmutable(
117
+ itemId: number,
118
+ quantity: number,
119
+ stats: bigint,
120
+ originX: number,
121
+ originY: number
122
+ ): ImmutableEntry[] {
123
+ const item = getItem(itemId)
124
+ const cat = item.category
125
+ if (!cat) throw new Error(`Resource item ${itemId} has no category`)
126
+ const definitions = getStatDefinitions(cat as ResourceCategory)
127
+ const img = computeNftImageUrl(
128
+ {item_id: itemId, stats, modules: [], quantity},
129
+ originX,
130
+ originY
131
+ )
132
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
133
+ base.push({first: definitions[0].key, second: ['uint16', decodeStat(stats, 0)]})
134
+ base.push({first: definitions[1].key, second: ['uint16', decodeStat(stats, 1)]})
135
+ base.push({first: definitions[2].key, second: ['uint16', decodeStat(stats, 2)]})
136
+ return base
137
+ }
138
+
139
+ export function buildComponentImmutable(
140
+ itemId: number,
141
+ quantity: number,
142
+ stats: bigint,
143
+ originX: number,
144
+ originY: number
145
+ ): ImmutableEntry[] {
146
+ const img = computeNftImageUrl(
147
+ {item_id: itemId, stats, modules: [], quantity},
148
+ originX,
149
+ originY
150
+ )
151
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
152
+ const decoded = decodeCraftedItemStats(itemId, stats)
153
+ for (const [key, value] of Object.entries(decoded)) {
154
+ base.push({first: key, second: ['uint16', value]})
155
+ }
156
+ return base
157
+ }
158
+
159
+ export function buildModuleImmutable(
160
+ itemId: number,
161
+ quantity: number,
162
+ stats: bigint,
163
+ originX: number,
164
+ originY: number
165
+ ): ImmutableEntry[] {
166
+ const img = computeNftImageUrl(
167
+ {item_id: itemId, stats, modules: [], quantity},
168
+ originX,
169
+ originY
170
+ )
171
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
172
+ const subtype = getModuleCapabilityType(itemId)
173
+ const item = getItem(itemId)
174
+ switch (subtype) {
175
+ case MODULE_ENGINE: {
176
+ const vol = decodeStat(stats, 0)
177
+ const thm = decodeStat(stats, 1)
178
+ base.push({first: 'volatility', second: ['uint16', vol]})
179
+ base.push({first: 'thermal', second: ['uint16', thm]})
180
+ base.push({first: 'thrust', second: ['uint32', computeEngineThrust(vol)]})
181
+ base.push({first: 'drain', second: ['uint16', computeEngineDrain(thm)]})
182
+ break
183
+ }
184
+ case MODULE_GENERATOR: {
185
+ const res = decodeStat(stats, 0)
186
+ const ref = decodeStat(stats, 1)
187
+ base.push({first: 'resonance', second: ['uint16', res]})
188
+ base.push({first: 'reflectivity', second: ['uint16', ref]})
189
+ base.push({first: 'capacity', second: ['uint16', computeGeneratorCap(res)]})
190
+ base.push({first: 'recharge', second: ['uint16', computeGeneratorRech(ref)]})
191
+ break
192
+ }
193
+ case MODULE_GATHERER: {
194
+ const str = decodeStat(stats, 0)
195
+ const tol = decodeStat(stats, 1)
196
+ const con = decodeStat(stats, 3)
197
+ base.push({first: 'strength', second: ['uint16', str]})
198
+ base.push({first: 'tolerance', second: ['uint16', tol]})
199
+ base.push({first: 'conductivity', second: ['uint16', con]})
200
+ base.push({first: 'yield', second: ['uint16', computeGathererYield(str)]})
201
+ base.push({first: 'drain', second: ['uint16', computeGathererDrain(con)]})
202
+ base.push({first: 'depth', second: ['uint16', computeGathererDepth(tol, item.tier)]})
203
+ break
204
+ }
205
+ case MODULE_LOADER: {
206
+ const fin = decodeStat(stats, 0)
207
+ const pla = decodeStat(stats, 1)
208
+ base.push({first: 'fineness', second: ['uint16', fin]})
209
+ base.push({first: 'plasticity', second: ['uint16', pla]})
210
+ base.push({first: 'mass', second: ['uint32', computeLoaderMass(fin)]})
211
+ base.push({first: 'thrust', second: ['uint16', computeLoaderThrust(pla)]})
212
+ break
213
+ }
214
+ case MODULE_WARP: {
215
+ const res = decodeStat(stats, 0)
216
+ base.push({first: 'resonance', second: ['uint16', res]})
217
+ base.push({first: 'range', second: ['uint32', computeWarpRange(res)]})
218
+ break
219
+ }
220
+ case MODULE_CRAFTER: {
221
+ const rea = decodeStat(stats, 0)
222
+ const com = decodeStat(stats, 1)
223
+ base.push({first: 'reactivity', second: ['uint16', rea]})
224
+ base.push({first: 'composition', second: ['uint16', com]})
225
+ base.push({first: 'speed', second: ['uint16', computeCrafterSpeed(rea)]})
226
+ base.push({first: 'drain', second: ['uint16', computeCrafterDrain(com)]})
227
+ break
228
+ }
229
+ case MODULE_STORAGE: {
230
+ const str = decodeStat(stats, 0)
231
+ const fin = decodeStat(stats, 1)
232
+ const sat = decodeStat(stats, 2)
233
+ const sum = str + fin + sat
234
+ base.push({first: 'strength', second: ['uint16', str]})
235
+ base.push({first: 'fineness', second: ['uint16', fin]})
236
+ base.push({first: 'saturation', second: ['uint16', sat]})
237
+ base.push({
238
+ first: 'capacity_bonus_pct',
239
+ second: ['uint16', 10 + Math.floor((sum * 10) / 2997)],
240
+ })
241
+ break
242
+ }
243
+ case MODULE_HAULER: {
244
+ const com = decodeStat(stats, 0)
245
+ const con = decodeStat(stats, 1)
246
+ const fin = decodeStat(stats, 2)
247
+ const res = decodeStat(stats, 3)
248
+ base.push({first: 'composition', second: ['uint16', com]})
249
+ base.push({first: 'conductivity', second: ['uint16', con]})
250
+ base.push({first: 'fineness', second: ['uint16', fin]})
251
+ base.push({first: 'resonance', second: ['uint16', res]})
252
+ base.push({first: 'capacity', second: ['uint8', computeHaulerCapacity(com)]})
253
+ base.push({first: 'efficiency', second: ['uint16', computeHaulerEfficiency(con)]})
254
+ base.push({first: 'drain', second: ['uint16', computeHaulerDrain(fin)]})
255
+ break
256
+ }
257
+ }
258
+ return base
259
+ }
260
+
261
+ export function buildEntityImmutable(
262
+ itemId: number,
263
+ quantity: number,
264
+ stats: bigint,
265
+ originX: number,
266
+ originY: number,
267
+ modules: ImmutableModuleSlot[]
268
+ ): ImmutableEntry[] {
269
+ const moduleItems: number[] = []
270
+ const moduleStats: string[] = []
271
+ for (const m of modules) {
272
+ if (m.installed) {
273
+ moduleItems.push(Number(m.installed.item_id))
274
+ moduleStats.push(String(m.installed.stats))
275
+ } else {
276
+ moduleItems.push(0)
277
+ moduleStats.push('0')
278
+ }
279
+ }
280
+ const img = computeNftImageUrl({item_id: itemId, stats, modules, quantity}, originX, originY)
281
+ const base = commonBaseImmutable(quantity, stats, originX, originY, img)
282
+ base.push({first: 'module_items', second: ['UINT16_VEC', moduleItems]})
283
+ base.push({first: 'module_stats', second: ['UINT64_VEC', moduleStats]})
284
+ const description = buildEntityDescription(
285
+ itemId,
286
+ stats,
287
+ moduleItems,
288
+ moduleStats.map((s) => BigInt(s))
289
+ )
290
+ base.push({first: 'description', second: ['string', description]})
291
+ return base
292
+ }
293
+
294
+ export function buildImmutableData(
295
+ itemId: number,
296
+ quantity: number,
297
+ stats: bigint,
298
+ originX: number,
299
+ originY: number,
300
+ modules: ImmutableModuleSlot[] = []
301
+ ): ImmutableEntry[] {
302
+ const item = getItem(itemId)
303
+ if (item.type === 'resource') {
304
+ return buildResourceImmutable(itemId, quantity, stats, originX, originY)
305
+ }
306
+ if (item.type === 'component') {
307
+ return buildComponentImmutable(itemId, quantity, stats, originX, originY)
308
+ }
309
+ if (item.type === 'module') {
310
+ return buildModuleImmutable(itemId, quantity, stats, originX, originY)
311
+ }
312
+ if (item.type === 'entity') {
313
+ return buildEntityImmutable(itemId, quantity, stats, originX, originY, modules)
314
+ }
315
+ throw new Error(`Unsupported item type for wrap: ${item.type}`)
316
+ }
@@ -56,7 +56,6 @@ export const computeGathererDrain = (con: number): number =>
56
56
  Math.max(250, 1250 - idiv(con * 25, 20))
57
57
  export const computeGathererDepth = (tol: number, tier: number): number =>
58
58
  gathererDepthForTier(tol, tier)
59
- export const computeGathererSpeed = (ref: number): number => 100 + idiv(ref * 4, 5)
60
59
  export const computeLoaderMass = (ins: number): number => Math.max(200, 2000 - ins * 2)
61
60
  export const computeLoaderThrust = (pla: number): number => 1 + idiv(pla, 500)
62
61
  export const computeCrafterSpeed = (rea: number): number => 100 + idiv(rea * 4, 5)
@@ -133,12 +132,11 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
133
132
  const str = decodeStat(stats, 0)
134
133
  const tol = decodeStat(stats, 1)
135
134
  const con = decodeStat(stats, 3)
136
- const ref = decodeStat(stats, 4)
137
135
  const tier = getItem(itemId).tier
138
136
  out += ` Yield ${computeGathererYield(str)} Depth ${computeGathererDepth(
139
137
  tol,
140
138
  tier
141
- )} Speed ${computeGathererSpeed(ref)} Drain ${computeGathererDrain(con)}`
139
+ )} Drain ${computeGathererDrain(con)}`
142
140
  break
143
141
  }
144
142
  case MODULE_LOADER: {
package/src/nft/index.ts CHANGED
@@ -2,3 +2,4 @@ export * from './deserializers'
2
2
  export * from './description'
3
3
  export * from './atomicdata'
4
4
  export * from './atomicassets'
5
+ export * from './buildImmutableData'
@@ -53,14 +53,13 @@ const TEMPLATES: Record<string, TemplateSpec> = {
53
53
  gatherer: {
54
54
  id: 'module.gatherer.description',
55
55
  template:
56
- 'mines resources at {yield} speed to a max depth of {depth} with {speed} gather speed while draining {drain} energy per second',
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
- ['speed', 'Speed'],
60
+ ['drain', 'Drain'],
62
61
  ],
63
- highlightKeys: ['yield', 'depth', 'speed', 'drain'],
62
+ highlightKeys: ['yield', 'depth', 'drain'],
64
63
  },
65
64
  loader: {
66
65
  id: 'module.loader.description',
@@ -189,7 +189,6 @@ function computeCapabilityGroup(
189
189
  {label: 'Yield', value: caps.yield},
190
190
  {label: 'Drain', value: caps.drain},
191
191
  {label: 'Depth', value: caps.depth},
192
- {label: 'Speed', value: caps.speed},
193
192
  ],
194
193
  }
195
194
  }
package/src/shipload.ts CHANGED
@@ -9,6 +9,7 @@ import type {PlayersManager} from './managers/players'
9
9
  import type {LocationsManager} from './managers/locations'
10
10
  import type {EpochsManager} from './managers/epochs'
11
11
  import type {ActionsManager} from './managers/actions'
12
+ import type {NftManager} from './managers/nft'
12
13
  import type {SubscriptionsManager} from './subscriptions/manager'
13
14
  import type {GameState} from './entities/gamestate'
14
15
 
@@ -107,6 +108,10 @@ export class Shipload {
107
108
  return this._context.actions
108
109
  }
109
110
 
111
+ get nft(): NftManager {
112
+ return this._context.nft
113
+ }
114
+
110
115
  get subscriptions(): SubscriptionsManager {
111
116
  return this._context.subscriptions
112
117
  }
package/src/types.ts CHANGED
@@ -117,6 +117,7 @@ export type ModuleType =
117
117
  | 'launcher'
118
118
  | 'storage'
119
119
  | 'hauler'
120
+ | 'battery'
120
121
 
121
122
  export const RESOURCE_TIER_ADJECTIVES: Record<number, string> = {
122
123
  1: 'Crude',