@shipload/sdk 1.0.0-next.3 → 1.0.0-next.5

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.
@@ -117,30 +117,35 @@ export {
117
117
  distanceBetweenCoordinates,
118
118
  distanceBetweenPoints,
119
119
  findNearbyPlanets,
120
- lerp,
121
- rotation,
122
- calc_ship_mass,
123
120
  calc_acceleration,
121
+ calc_energyusage,
124
122
  calc_flighttime,
125
- calc_ship_flighttime,
126
- calc_ship_acceleration,
127
- calc_rechargetime,
128
- calc_ship_rechargetime,
129
- calc_loader_flighttime,
130
123
  calc_loader_acceleration,
131
- calc_energyusage,
124
+ calc_loader_flighttime,
132
125
  calc_orbital_altitude,
126
+ calc_rechargetime,
127
+ calc_ship_acceleration,
128
+ calc_ship_flighttime,
129
+ calc_ship_mass,
130
+ calc_ship_rechargetime,
133
131
  calc_transfer_duration,
134
- calculateTransferTime,
132
+ calculateFlightTime,
135
133
  calculateLoadTimeBreakdown,
136
134
  calculateRefuelingTime,
137
- calculateFlightTime,
138
- estimateTravelTime,
135
+ calculateTransferTime,
136
+ easeFlightProgress,
139
137
  estimateDealTravelTime,
140
- hasEnergyForDistance,
141
- getFlightOrigin,
138
+ estimateTravelTime,
139
+ flightSpeedFactor,
140
+ type FloatPosition,
142
141
  getDestinationLocation,
142
+ getFlightOrigin,
143
+ getInterpolatedPosition,
143
144
  getPositionAt,
145
+ hasEnergyForDistance,
146
+ interpolateFlightPosition,
147
+ lerp,
148
+ rotation,
144
149
  } from './travel/travel'
145
150
  export type {
146
151
  LoadTimeBreakdown,
@@ -202,14 +207,19 @@ export type {PlanetSubtypeInfo} from './data/locations'
202
207
  export {
203
208
  capabilityNames,
204
209
  capabilityAttributes,
205
- statMappings,
206
210
  isInvertedAttribute,
207
211
  getCapabilityAttributes,
212
+ } from './data/capabilities'
213
+ export type {CapabilityAttribute, StatMapping} from './data/capabilities'
214
+
215
+ export {
216
+ deriveStatMappings,
208
217
  getStatMappings,
209
218
  getStatMappingsForStat,
210
219
  getStatMappingsForCapability,
211
- } from './data/capabilities'
212
- export type {CapabilityAttribute, StatMapping} from './data/capabilities'
220
+ } from './derivation/capability-mappings'
221
+ export {SLOT_FORMULAS} from './data/capability-formulas'
222
+ export type {SlotConsumer, SlotConsumerKind} from './data/capability-formulas'
213
223
 
214
224
  export {
215
225
  encodeStats,
@@ -241,8 +251,11 @@ export {
241
251
  computeWarehouseHullCapabilities,
242
252
  computeStorageCapabilities,
243
253
  computeShipCapabilities,
254
+ GATHERER_DEPTH_TABLE,
255
+ GATHERER_DEPTH_MAX_TIER,
256
+ gathererDepthForTier,
244
257
  } from './entities/ship-deploy'
245
- export type {ShipCapabilities} from './entities/ship-deploy'
258
+ export type {ShipCapabilities, GathererDepthParams} from './entities/ship-deploy'
246
259
 
247
260
  export {resolveItem} from './resolution/resolve-item'
248
261
  export type {
@@ -302,6 +315,7 @@ export {
302
315
  computeLoaderThrust,
303
316
  computeCrafterSpeed,
304
317
  computeCrafterDrain,
318
+ computeWarpRange,
305
319
  } from './nft/description'
306
320
 
307
321
  export {
@@ -15,7 +15,7 @@ import {type CoordinatesType, EntityType, type EntityTypeName} from '../types'
15
15
  import {ServerContract} from '../contracts'
16
16
 
17
17
  export type EntityRefInput = {
18
- entityType: EntityTypeName
18
+ entityType: NameType
19
19
  entityId: UInt64Type
20
20
  }
21
21
 
@@ -244,6 +244,29 @@ export class ActionsManager extends BaseManager {
244
244
  })
245
245
  }
246
246
 
247
+ undeploy(host: EntityRefInput, target: EntityRefInput): Action {
248
+ return this.server.action('undeploy', {
249
+ host_type: Name.from(host.entityType),
250
+ host_id: UInt64.from(host.entityId),
251
+ target_type: Name.from(target.entityType),
252
+ target_id: UInt64.from(target.entityId),
253
+ })
254
+ }
255
+
256
+ wrapEntity(entity: EntityRefInput): Action {
257
+ return this.server.action('wrapentity', {
258
+ entity_type: Name.from(entity.entityType),
259
+ entity_id: UInt64.from(entity.entityId),
260
+ })
261
+ }
262
+
263
+ demolish(entity: EntityRefInput): Action {
264
+ return this.server.action('demolish', {
265
+ entity_type: Name.from(entity.entityType),
266
+ entity_id: UInt64.from(entity.entityId),
267
+ })
268
+ }
269
+
247
270
  joinGame(account: NameType, companyName: string): Action[] {
248
271
  return [this.foundCompany(account, companyName), this.join(account)]
249
272
  }
@@ -4,6 +4,7 @@ import {
4
4
  MODULE_ENGINE,
5
5
  MODULE_GATHERER,
6
6
  MODULE_GENERATOR,
7
+ MODULE_HAULER,
7
8
  MODULE_LOADER,
8
9
  MODULE_STORAGE,
9
10
  MODULE_WARP,
@@ -15,6 +16,7 @@ import {
15
16
  ITEM_ENGINE_T1,
16
17
  ITEM_GATHERER_T1,
17
18
  ITEM_GENERATOR_T1,
19
+ ITEM_HAULER_T1,
18
20
  ITEM_LOADER_T1,
19
21
  ITEM_SHIP_T1_PACKED,
20
22
  ITEM_STORAGE_T1,
@@ -22,6 +24,8 @@ import {
22
24
  ITEM_WARP_T1,
23
25
  } from '../data/item-ids'
24
26
  import {decodeStat} from '../derivation/crafting'
27
+ import {gathererDepthForTier} from '../entities/ship-deploy'
28
+ import {getItem} from '../data/catalog'
25
29
 
26
30
  function idiv(a: number, b: number): number {
27
31
  return Math.floor(a / b)
@@ -44,17 +48,21 @@ export function computeBaseCapacityWarehouse(stats: bigint): number {
44
48
 
45
49
  export const computeEngineThrust = (vol: number): number => 400 + idiv(vol * 3, 4)
46
50
  export const computeEngineDrain = (thm: number): number => Math.max(30, 50 - idiv(thm, 70))
47
- export const computeGeneratorCap = (res: number): number => 300 + idiv(res, 6)
48
- export const computeGeneratorRech = (ref: number): number => 1 + idiv(ref * 3, 1000)
51
+ export const computeGeneratorCap = (com: number): number => 300 + idiv(com, 6)
52
+ export const computeGeneratorRech = (fin: number): number => 1 + idiv(fin * 3, 1000)
49
53
  export const computeGathererYield = (str: number): number => 200 + str
50
54
  export const computeGathererDrain = (con: number): number =>
51
55
  Math.max(250, 1250 - idiv(con * 25, 20))
52
- export const computeGathererDepth = (tol: number): number => 200 + idiv(tol * 3, 2)
56
+ export const computeGathererDepth = (tol: number, tier: number): number =>
57
+ gathererDepthForTier(tol, tier)
53
58
  export const computeGathererSpeed = (ref: number): number => 100 + idiv(ref * 4, 5)
54
- export const computeLoaderMass = (fin: number): number => Math.max(200, 2000 - fin * 2)
59
+ export const computeLoaderMass = (ins: number): number => Math.max(200, 2000 - ins * 2)
55
60
  export const computeLoaderThrust = (pla: number): number => 1 + idiv(pla, 500)
56
61
  export const computeCrafterSpeed = (rea: number): number => 100 + idiv(rea * 4, 5)
57
- export const computeCrafterDrain = (com: number): number => Math.max(5, 30 - idiv(com, 33))
62
+ export const computeCrafterDrain = (fin: number): number => Math.max(5, 30 - idiv(fin, 33))
63
+ export const computeHaulerCapacity = (fin: number): number => Math.max(1, 1 + idiv(fin, 400))
64
+ export const computeHaulerEfficiency = (con: number): number => 2000 + con * 6
65
+ export const computeHaulerDrain = (com: number): number => Math.max(3, 15 - idiv(com, 80))
58
66
  export const computeWarpRange = (stat: number): number => 100 + stat * 3
59
67
 
60
68
  export function entityDisplayName(itemId: number): string {
@@ -86,6 +94,8 @@ export function moduleDisplayName(itemId: number): string {
86
94
  return 'Crafter'
87
95
  case ITEM_STORAGE_T1:
88
96
  return 'Storage'
97
+ case ITEM_HAULER_T1:
98
+ return 'Hauler'
89
99
  case ITEM_WARP_T1:
90
100
  return 'Warp'
91
101
  default:
@@ -121,8 +131,10 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
121
131
  const tol = decodeStat(stats, 1)
122
132
  const con = decodeStat(stats, 3)
123
133
  const ref = decodeStat(stats, 4)
134
+ const tier = getItem(itemId).tier
124
135
  out += ` Yield ${computeGathererYield(str)} Depth ${computeGathererDepth(
125
- tol
136
+ tol,
137
+ tier
126
138
  )} Speed ${computeGathererSpeed(ref)} Drain ${computeGathererDrain(con)}`
127
139
  break
128
140
  }
@@ -147,6 +159,13 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
147
159
  out += ` +${pct}% capacity`
148
160
  break
149
161
  }
162
+ case MODULE_HAULER: {
163
+ const fin = decodeStat(stats, 0)
164
+ const con = decodeStat(stats, 1)
165
+ const com = decodeStat(stats, 2)
166
+ out += ` Capacity ${computeHaulerCapacity(fin)} Efficiency ${computeHaulerEfficiency(con)} Drain ${computeHaulerDrain(com)}`
167
+ break
168
+ }
150
169
  case MODULE_WARP: {
151
170
  const stat = decodeStat(stats, 0)
152
171
  out += ` Range ${computeWarpRange(stat)}`
@@ -155,7 +155,8 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
155
155
 
156
156
  function computeCapabilityGroup(
157
157
  moduleType: number,
158
- stats: Record<string, number>
158
+ stats: Record<string, number>,
159
+ tier: number
159
160
  ): ResolvedAttributeGroup | undefined {
160
161
  switch (moduleType) {
161
162
  case MODULE_ENGINE: {
@@ -179,7 +180,7 @@ function computeCapabilityGroup(
179
180
  }
180
181
  }
181
182
  case MODULE_GATHERER: {
182
- const caps = computeGathererCapabilities(stats)
183
+ const caps = computeGathererCapabilities(stats, tier)
183
184
  return {
184
185
  capability: 'Gatherer',
185
186
  attributes: [
@@ -223,10 +224,11 @@ function computeCapabilityGroup(
223
224
  }
224
225
  }
225
226
  case MODULE_STORAGE: {
226
- const str = stats.strength ?? 500
227
- const hrd = stats.hardness ?? 500
228
- const sat = stats.saturation ?? 500
229
- const statSum = str + hrd + sat
227
+ const str = stats.strength
228
+ const den = stats.density
229
+ const hrd = stats.hardness
230
+ const sat = stats.saturation
231
+ const statSum = str + den + hrd + sat
230
232
  const pct = 10 + Math.floor((statSum * 10) / 2997)
231
233
  return {capability: 'Storage', attributes: [{label: 'Capacity Bonus', value: pct}]}
232
234
  }
@@ -241,7 +243,7 @@ function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
241
243
  if (stats !== undefined) {
242
244
  const decoded = decodeCraftedItemStats(id, toBigStats(stats))
243
245
  const modType = getModuleCapabilityType(id)
244
- const group = computeCapabilityGroup(modType, decoded)
246
+ const group = computeCapabilityGroup(modType, decoded, item.tier)
245
247
  if (group) attributes = [group]
246
248
  }
247
249
  return {
@@ -310,13 +312,16 @@ function resolveEntity(
310
312
  const modStats = BigInt(mod.installed.stats.toString())
311
313
  const decodedStats = decodeCraftedItemStats(modItemId, modStats)
312
314
  const modType = getModuleCapabilityType(modItemId)
313
- const group = computeCapabilityGroup(modType, decodedStats)
314
315
  let modName = 'Module'
316
+ let modTier = 1
315
317
  try {
316
- modName = getItem(modItemId).name
318
+ const modItem = getItem(modItemId)
319
+ modName = modItem.name
320
+ modTier = modItem.tier
317
321
  } catch {
318
322
  modName = itemMetadata[modItemId]?.name ?? 'Module'
319
323
  }
324
+ const group = computeCapabilityGroup(modType, decodedStats, modTier)
320
325
  return {
321
326
  name: modName,
322
327
  installed: true,
@@ -72,6 +72,10 @@ export class ScheduleAccessor {
72
72
  return schedule.currentTaskProgress(this.entity, now)
73
73
  }
74
74
 
75
+ currentTaskProgressFloat(now: Date): number {
76
+ return schedule.currentTaskProgressFloat(this.entity, now)
77
+ }
78
+
75
79
  progress(now: Date): number {
76
80
  return schedule.scheduleProgress(this.entity, now)
77
81
  }
@@ -267,6 +267,10 @@ function applyTask(projected: ProjectedEntity, task: ServerContract.Types.task):
267
267
  case TaskType.DEPLOY:
268
268
  applyDeployTask(projected, task)
269
269
  break
270
+ case TaskType.UNDEPLOY:
271
+ case TaskType.WRAP_ENTITY:
272
+ case TaskType.DEMOLISH:
273
+ break
270
274
  }
271
275
  }
272
276
 
@@ -448,6 +452,10 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
448
452
  case TaskType.DEPLOY:
449
453
  if (taskComplete) applyDeployTask(projected, task)
450
454
  break
455
+ case TaskType.UNDEPLOY:
456
+ case TaskType.WRAP_ENTITY:
457
+ case TaskType.DEMOLISH:
458
+ break
451
459
  }
452
460
  }
453
461
 
@@ -77,7 +77,7 @@ export function currentTaskIndex(entity: ScheduleData, now: Date): number {
77
77
  timeAccum += taskDuration
78
78
  }
79
79
 
80
- return entity.schedule.tasks.length - 1
80
+ return -1
81
81
  }
82
82
 
83
83
  export function currentTask(entity: ScheduleData, now: Date): Task | undefined {
@@ -147,6 +147,20 @@ export function currentTaskProgress(entity: ScheduleData, now: Date): number {
147
147
  return Math.min(1, elapsed / duration)
148
148
  }
149
149
 
150
+ export function currentTaskProgressFloat(entity: ScheduleData, now: Date): number {
151
+ if (!entity.schedule || entity.schedule.tasks.length === 0) return 0
152
+ const index = currentTaskIndex(entity, now)
153
+ if (index < 0) return 0
154
+ const task = entity.schedule.tasks[index]
155
+ const durationMs = task.duration.toNumber() * 1000
156
+ if (durationMs === 0) return 1
157
+ const startedMs = entity.schedule.started.toDate().getTime()
158
+ const taskStartMs = startedMs + getTaskStartTime(entity, index) * 1000
159
+ const elapsedMs = now.getTime() - taskStartMs
160
+ if (elapsedMs <= 0) return 0
161
+ return Math.min(1, elapsedMs / durationMs)
162
+ }
163
+
150
164
  export function scheduleProgress(entity: ScheduleData, now: Date): number {
151
165
  const duration = scheduleDuration(entity)
152
166
  if (duration === 0) return hasSchedule(entity) ? 1 : 0
@@ -34,6 +34,12 @@ export interface BoundsSubscriptionHandle {
34
34
  current: Map<number, EntityInstance>
35
35
  }
36
36
 
37
+ export interface OwnerSubscriptionHandle {
38
+ readonly subId: string
39
+ unsubscribe(): void
40
+ current: Map<number, EntityInstance>
41
+ }
42
+
37
43
  export interface EntitySubscriptionHandle {
38
44
  readonly subId: string
39
45
  readonly entityType: SubscriptionEntityType
@@ -62,7 +68,7 @@ export class SubscriptionsManager {
62
68
  onSnapshot?: (entities: EntityInstance[]) => void
63
69
  onUpdate?: (entity: EntityInstance) => void
64
70
  onBoundsDelta?: (entered: EntityInstance[], exited: number[]) => void
65
- handle: BoundsSubscriptionHandle
71
+ handle: BoundsSubscriptionHandle | OwnerSubscriptionHandle
66
72
  }
67
73
  >()
68
74
  private subCounter = 0
@@ -162,6 +168,36 @@ export class SubscriptionsManager {
162
168
  return handle
163
169
  }
164
170
 
171
+ subscribeOwner(
172
+ owner: string,
173
+ handlers: {
174
+ onSnapshot?: (entities: EntityInstance[]) => void
175
+ onUpdate?: (entity: EntityInstance) => void
176
+ } = {}
177
+ ): OwnerSubscriptionHandle {
178
+ const subId = this.generateSubID('own')
179
+ const msg: SubscribeMessage = {
180
+ type: 'subscribe',
181
+ sub_id: subId,
182
+ owner,
183
+ }
184
+ const handle: OwnerSubscriptionHandle = {
185
+ subId,
186
+ unsubscribe: () => this.unsubscribeBounds(subId),
187
+ current: new Map(),
188
+ }
189
+ this.boundsSubs.set(subId, {
190
+ bounds: undefined,
191
+ owner,
192
+ prioritizeOwner: undefined,
193
+ onSnapshot: handlers.onSnapshot,
194
+ onUpdate: handlers.onUpdate,
195
+ handle,
196
+ })
197
+ this.sendMessage(msg)
198
+ return handle
199
+ }
200
+
165
201
  private unsubscribeBounds(subId: string) {
166
202
  this.boundsSubs.delete(subId)
167
203
  this.sendMessage({type: 'unsubscribe', sub_id: subId})
@@ -77,6 +77,59 @@ export function lerp(
77
77
  }
78
78
  }
79
79
 
80
+ export interface FloatPosition {
81
+ x: number
82
+ y: number
83
+ }
84
+
85
+ export function easeFlightProgress(t: number): number {
86
+ if (t <= 0) return 0
87
+ if (t >= 1) return 1
88
+ return t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)
89
+ }
90
+
91
+ export function flightSpeedFactor(t: number): number {
92
+ if (t <= 0 || t >= 1) return 0
93
+ return t < 0.5 ? 4 * t : 4 * (1 - t)
94
+ }
95
+
96
+ export function interpolateFlightPosition(
97
+ origin: {x: Int64Type | number; y: Int64Type | number},
98
+ destination: {x: Int64Type | number; y: Int64Type | number},
99
+ taskProgress: number,
100
+ options?: {easing?: 'physics' | 'linear'}
101
+ ): FloatPosition {
102
+ const t = options?.easing === 'linear' ? taskProgress : easeFlightProgress(taskProgress)
103
+ return {
104
+ x: (1 - t) * Number(origin.x) + t * Number(destination.x),
105
+ y: (1 - t) * Number(origin.y) + t * Number(destination.y),
106
+ }
107
+ }
108
+
109
+ export function getInterpolatedPosition(
110
+ entity: HasScheduleAndLocation,
111
+ taskIndex: number,
112
+ taskProgress: number
113
+ ): FloatPosition {
114
+ if (!entity.schedule || entity.schedule.tasks.length === 0) {
115
+ return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
116
+ }
117
+ if (taskIndex < 0) {
118
+ const settled = getFlightOrigin(entity, entity.schedule.tasks.length)
119
+ return {x: Number(settled.x), y: Number(settled.y)}
120
+ }
121
+ const task = entity.schedule.tasks[taskIndex]
122
+ if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
123
+ const origin = getFlightOrigin(entity, taskIndex)
124
+ return {x: Number(origin.x), y: Number(origin.y)}
125
+ }
126
+ return interpolateFlightPosition(
127
+ getFlightOrigin(entity, taskIndex),
128
+ task.coordinates,
129
+ taskProgress
130
+ )
131
+ }
132
+
80
133
  export function rotation(
81
134
  origin: ServerContract.ActionParams.Type.coordinates,
82
135
  destination: ServerContract.ActionParams.Type.coordinates
@@ -408,14 +461,18 @@ export function getDestinationLocation(
408
461
  return undefined
409
462
  }
410
463
 
464
+ /** Returns chain-tile coordinates (rounded). For visual position use getInterpolatedPosition. */
411
465
  export function getPositionAt(
412
466
  entity: HasScheduleAndLocation,
413
467
  taskIndex: number,
414
468
  taskProgress: number
415
469
  ): ServerContract.ActionParams.Type.coordinates {
416
- if (!entity.schedule || entity.schedule.tasks.length === 0 || taskIndex < 0) {
470
+ if (!entity.schedule || entity.schedule.tasks.length === 0) {
417
471
  return entity.coordinates
418
472
  }
473
+ if (taskIndex < 0) {
474
+ return getFlightOrigin(entity, entity.schedule.tasks.length)
475
+ }
419
476
 
420
477
  const task = entity.schedule.tasks[taskIndex]
421
478
 
package/src/types.ts CHANGED
@@ -51,6 +51,9 @@ export enum TaskType {
51
51
  DEPLOY = 8,
52
52
  WRAP = 9,
53
53
  UNWRAP = 10,
54
+ UNDEPLOY = 11,
55
+ WRAP_ENTITY = 12,
56
+ DEMOLISH = 13,
54
57
  }
55
58
 
56
59
  export enum LocationType {