@shipload/sdk 2.0.0-rc2 → 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.
Files changed (84) hide show
  1. package/README.md +1 -349
  2. package/lib/shipload.d.ts +1729 -1127
  3. package/lib/shipload.js +7944 -3165
  4. package/lib/shipload.js.map +1 -1
  5. package/lib/shipload.m.js +7487 -2840
  6. package/lib/shipload.m.js.map +1 -1
  7. package/package.json +6 -4
  8. package/src/capabilities/crafting.ts +22 -0
  9. package/src/capabilities/gathering.ts +36 -0
  10. package/src/capabilities/guards.ts +3 -8
  11. package/src/capabilities/hauling.ts +22 -0
  12. package/src/capabilities/index.ts +4 -1
  13. package/src/capabilities/modules.ts +86 -0
  14. package/src/capabilities/storage.ts +101 -9
  15. package/src/contracts/server.ts +785 -293
  16. package/src/data/capabilities.ts +408 -0
  17. package/src/data/categories.ts +55 -0
  18. package/src/data/colors.ts +71 -0
  19. package/src/data/entities.json +50 -0
  20. package/src/data/item-ids.ts +75 -0
  21. package/src/data/items.json +252 -0
  22. package/src/data/locations.ts +53 -0
  23. package/src/data/metadata.ts +208 -0
  24. package/src/data/nebula-adjectives.json +211 -0
  25. package/src/data/nebula-nouns.json +151 -0
  26. package/src/data/recipes-runtime.ts +65 -0
  27. package/src/data/recipes.json +878 -0
  28. package/src/data/syllables.json +1386 -780
  29. package/src/data/tiers.ts +45 -0
  30. package/src/derivation/crafting.ts +348 -0
  31. package/src/derivation/index.ts +30 -0
  32. package/src/derivation/location-size.ts +15 -0
  33. package/src/derivation/resources.ts +112 -0
  34. package/src/derivation/stats.ts +146 -0
  35. package/src/derivation/stratum.ts +134 -0
  36. package/src/derivation/tiers.ts +54 -0
  37. package/src/entities/cargo-utils.ts +10 -68
  38. package/src/entities/container.ts +37 -0
  39. package/src/entities/entity-inventory.ts +13 -13
  40. package/src/entities/inventory-accessor.ts +2 -6
  41. package/src/entities/location.ts +5 -200
  42. package/src/entities/makers.ts +144 -17
  43. package/src/entities/player.ts +1 -274
  44. package/src/entities/ship-deploy.ts +258 -0
  45. package/src/entities/ship.ts +28 -34
  46. package/src/entities/warehouse.ts +35 -7
  47. package/src/errors.ts +59 -5
  48. package/src/format.ts +12 -0
  49. package/src/index-module.ts +188 -50
  50. package/src/managers/actions.ts +138 -88
  51. package/src/managers/context.ts +19 -9
  52. package/src/managers/index.ts +0 -1
  53. package/src/managers/locations.ts +2 -85
  54. package/src/market/items.ts +41 -0
  55. package/src/nft/description.ts +176 -0
  56. package/src/nft/deserializers.ts +83 -0
  57. package/src/nft/index.ts +2 -0
  58. package/src/resolution/describe-module.ts +165 -0
  59. package/src/resolution/display-name.ts +43 -0
  60. package/src/resolution/resolve-item.ts +358 -0
  61. package/src/scheduling/projection.ts +200 -67
  62. package/src/scheduling/schedule.ts +2 -2
  63. package/src/shipload.ts +10 -5
  64. package/src/subscriptions/connection.ts +154 -0
  65. package/src/subscriptions/debug.ts +17 -0
  66. package/src/subscriptions/index.ts +5 -0
  67. package/src/subscriptions/manager.ts +240 -0
  68. package/src/subscriptions/mappers.ts +28 -0
  69. package/src/subscriptions/types.ts +143 -0
  70. package/src/travel/travel.ts +37 -23
  71. package/src/types/capabilities.ts +11 -14
  72. package/src/types/entity-traits.ts +3 -4
  73. package/src/types/entity.ts +9 -6
  74. package/src/types.ts +72 -72
  75. package/src/utils/system.ts +66 -53
  76. package/src/capabilities/extraction.ts +0 -37
  77. package/src/data/goods.json +0 -23
  78. package/src/managers/trades.ts +0 -119
  79. package/src/market/goods.ts +0 -31
  80. package/src/market/market.ts +0 -208
  81. package/src/market/rolls.ts +0 -8
  82. package/src/trading/collect.ts +0 -938
  83. package/src/trading/deal.ts +0 -207
  84. package/src/trading/trade.ts +0 -203
@@ -0,0 +1,240 @@
1
+ import {WebSocketConnection} from './connection'
2
+ import type {
3
+ BoundingBox,
4
+ BoundsDeltaMessage,
5
+ ClientMessage,
6
+ ServerMessage,
7
+ SnapshotMessage,
8
+ SubscribeEntityMessage,
9
+ SubscribeMessage,
10
+ UnsubscribeEntityMessage,
11
+ UpdateBoundsMessage,
12
+ UpdateMessage,
13
+ WireEntity,
14
+ } from './types'
15
+ import {mapEntity, parseWireEntity} from './mappers'
16
+ import type {Ship} from '../entities/ship'
17
+ import type {Warehouse} from '../entities/warehouse'
18
+ import type {Container} from '../entities/container'
19
+
20
+ export type SubscriptionEntityType = 'ship' | 'warehouse' | 'container'
21
+ export type EntityInstance = Ship | Warehouse | Container
22
+
23
+ export interface SubscriptionsOptions {
24
+ url: string
25
+ }
26
+
27
+ export interface BoundsSubscriptionHandle {
28
+ readonly subId: string
29
+ unsubscribe(): void
30
+ updateBounds(bounds: BoundingBox): void
31
+ current: Map<number, EntityInstance>
32
+ }
33
+
34
+ export interface EntitySubscriptionHandle {
35
+ readonly subId: string
36
+ readonly entityType: SubscriptionEntityType
37
+ readonly entityId: string
38
+ unsubscribe(): void
39
+ current: EntityInstance | null
40
+ }
41
+
42
+ export class SubscriptionsManager {
43
+ private readonly conn: WebSocketConnection
44
+ private readonly entitySubs = new Map<
45
+ string,
46
+ {
47
+ type: SubscriptionEntityType
48
+ id: string
49
+ onUpdate: (e: EntityInstance) => void
50
+ handle: EntitySubscriptionHandle
51
+ }
52
+ >()
53
+ private readonly boundsSubs = new Map<
54
+ string,
55
+ {
56
+ onSnapshot?: (entities: EntityInstance[]) => void
57
+ onUpdate?: (entity: EntityInstance) => void
58
+ onBoundsDelta?: (entered: EntityInstance[], exited: number[]) => void
59
+ handle: BoundsSubscriptionHandle
60
+ }
61
+ >()
62
+ private subCounter = 0
63
+
64
+ constructor(opts: SubscriptionsOptions) {
65
+ this.conn = new WebSocketConnection({
66
+ url: opts.url,
67
+ onMessage: (m) => this.onMessage(m),
68
+ })
69
+ this.conn.connect()
70
+ }
71
+
72
+ close() {
73
+ this.conn.close()
74
+ }
75
+
76
+ private generateSubID(prefix: string): string {
77
+ this.subCounter += 1
78
+ return `${prefix}-${this.subCounter}-${Math.random().toString(36).slice(2, 8)}`
79
+ }
80
+
81
+ private sendMessage(msg: ClientMessage) {
82
+ this.conn.send(msg)
83
+ }
84
+
85
+ subscribeEntity(
86
+ type: SubscriptionEntityType,
87
+ id: string,
88
+ onUpdate: (e: EntityInstance) => void
89
+ ): EntitySubscriptionHandle {
90
+ const subId = this.generateSubID('ent')
91
+ const msg: SubscribeEntityMessage = {
92
+ type: 'subscribe_entity',
93
+ sub_id: subId,
94
+ entity_type: type,
95
+ entity_id: id,
96
+ }
97
+ const handle: EntitySubscriptionHandle = {
98
+ subId,
99
+ entityType: type,
100
+ entityId: id,
101
+ unsubscribe: () => this.unsubscribeEntity(subId),
102
+ current: null,
103
+ }
104
+ this.entitySubs.set(subId, {type, id, onUpdate, handle})
105
+ this.sendMessage(msg)
106
+ return handle
107
+ }
108
+
109
+ private unsubscribeEntity(subId: string) {
110
+ const entry = this.entitySubs.get(subId)
111
+ if (!entry) return
112
+ this.entitySubs.delete(subId)
113
+ const msg: UnsubscribeEntityMessage = {type: 'unsubscribe_entity', sub_id: subId}
114
+ this.sendMessage(msg)
115
+ }
116
+
117
+ subscribeBounds(
118
+ bounds: BoundingBox,
119
+ handlers: {
120
+ onSnapshot?: (entities: EntityInstance[]) => void
121
+ onUpdate?: (entity: EntityInstance) => void
122
+ onBoundsDelta?: (entered: EntityInstance[], exited: number[]) => void
123
+ owner?: string
124
+ prioritizeOwner?: string
125
+ }
126
+ ): BoundsSubscriptionHandle {
127
+ const subId = this.generateSubID('bnd')
128
+ const msg: SubscribeMessage = {
129
+ type: 'subscribe',
130
+ sub_id: subId,
131
+ bounds,
132
+ owner: handlers.owner,
133
+ prioritize_owner: handlers.prioritizeOwner,
134
+ }
135
+ const handle: BoundsSubscriptionHandle = {
136
+ subId,
137
+ unsubscribe: () => this.unsubscribeBounds(subId),
138
+ updateBounds: (b) => this.updateBounds(subId, b),
139
+ current: new Map(),
140
+ }
141
+ this.boundsSubs.set(subId, {
142
+ onSnapshot: handlers.onSnapshot,
143
+ onUpdate: handlers.onUpdate,
144
+ onBoundsDelta: handlers.onBoundsDelta,
145
+ handle,
146
+ })
147
+ this.sendMessage(msg)
148
+ return handle
149
+ }
150
+
151
+ private unsubscribeBounds(subId: string) {
152
+ this.boundsSubs.delete(subId)
153
+ this.sendMessage({type: 'unsubscribe', sub_id: subId})
154
+ }
155
+
156
+ private updateBounds(subId: string, bounds: BoundingBox) {
157
+ const msg: UpdateBoundsMessage = {type: 'update_bounds', sub_id: subId, bounds}
158
+ this.sendMessage(msg)
159
+ }
160
+
161
+ private onMessage(msg: ServerMessage) {
162
+ switch (msg.type) {
163
+ case 'snapshot':
164
+ this.handleSnapshot(msg)
165
+ break
166
+ case 'update':
167
+ this.handleUpdate(msg)
168
+ break
169
+ case 'bounds_delta':
170
+ this.handleBoundsDelta(msg)
171
+ break
172
+ case 'error':
173
+ this.handleError(msg)
174
+ break
175
+ }
176
+ }
177
+
178
+ private parseEntity(raw: WireEntity): EntityInstance {
179
+ const ei = parseWireEntity(raw)
180
+ return mapEntity(ei)
181
+ }
182
+
183
+ private handleSnapshot(msg: SnapshotMessage) {
184
+ const entSub = this.entitySubs.get(msg.sub_id)
185
+ if (entSub) {
186
+ if (msg.entities.length > 0) {
187
+ const ent = this.parseEntity(msg.entities[0])
188
+ entSub.handle.current = ent
189
+ entSub.onUpdate(ent)
190
+ }
191
+ return
192
+ }
193
+ const boundsSub = this.boundsSubs.get(msg.sub_id)
194
+ if (boundsSub) {
195
+ const ents = msg.entities.map((e) => this.parseEntity(e))
196
+ boundsSub.handle.current.clear()
197
+ for (const e of ents) boundsSub.handle.current.set(Number(e.id), e)
198
+ boundsSub.onSnapshot?.(ents)
199
+ }
200
+ }
201
+
202
+ private handleUpdate(msg: UpdateMessage) {
203
+ const ent = this.parseEntity(msg.entity)
204
+ for (const subId of msg.sub_ids) {
205
+ const entSub = this.entitySubs.get(subId)
206
+ if (entSub) {
207
+ entSub.handle.current = ent
208
+ entSub.onUpdate(ent)
209
+ continue
210
+ }
211
+ const boundsSub = this.boundsSubs.get(subId)
212
+ if (boundsSub) {
213
+ boundsSub.handle.current.set(msg.entity_id, ent)
214
+ boundsSub.onUpdate?.(ent)
215
+ }
216
+ }
217
+ }
218
+
219
+ private handleBoundsDelta(msg: BoundsDeltaMessage) {
220
+ const sub = this.boundsSubs.get(msg.sub_id)
221
+ if (!sub) return
222
+ const entered = msg.entered.map((e) => this.parseEntity(e))
223
+ for (const e of entered) sub.handle.current.set(Number(e.id), e)
224
+ for (const id of msg.exited) sub.handle.current.delete(id)
225
+ sub.onBoundsDelta?.(entered, msg.exited)
226
+ }
227
+
228
+ private handleError(msg: {sub_id?: string; error: string}) {
229
+ if (!msg.sub_id) return
230
+ const entSub = this.entitySubs.get(msg.sub_id)
231
+ if (entSub) {
232
+ this.entitySubs.delete(msg.sub_id)
233
+ return
234
+ }
235
+ const boundsSub = this.boundsSubs.get(msg.sub_id)
236
+ if (boundsSub) {
237
+ this.boundsSubs.delete(msg.sub_id)
238
+ }
239
+ }
240
+ }
@@ -0,0 +1,28 @@
1
+ import {ServerContract} from '../contracts'
2
+ import {Ship} from '../entities/ship'
3
+ import {Warehouse} from '../entities/warehouse'
4
+ import {Container} from '../entities/container'
5
+ import type {WireEntity} from './types'
6
+
7
+ export function mapEntity(ei: ServerContract.Types.entity_info): Ship | Warehouse | Container {
8
+ if (ei.type.equals('ship')) return new Ship(ei)
9
+ if (ei.type.equals('warehouse')) return new Warehouse(ei)
10
+ if (ei.type.equals('container')) return new Container(ei)
11
+ throw new Error(`mapEntity: unknown entity type ${ei.type.toString()}`)
12
+ }
13
+
14
+ export function parseWireEntity(raw: WireEntity): ServerContract.Types.entity_info {
15
+ const shaped: Record<string, unknown> = {...raw}
16
+
17
+ if (typeof shaped.type === 'number' && typeof shaped.type_name === 'string') {
18
+ shaped.type = shaped.type_name
19
+ }
20
+ delete shaped.type_name
21
+
22
+ if (shaped.entity_name === undefined && typeof shaped.name === 'string') {
23
+ shaped.entity_name = shaped.name
24
+ }
25
+ delete shaped.name
26
+
27
+ return ServerContract.Types.entity_info.from(shaped)
28
+ }
@@ -0,0 +1,143 @@
1
+ import type {ServerContract} from '../contracts'
2
+
3
+ export type EntityInfo = ServerContract.Types.entity_info
4
+
5
+ export interface BoundingBox {
6
+ min_x: number
7
+ min_y: number
8
+ max_x: number
9
+ max_y: number
10
+ }
11
+
12
+ export interface WireCoordinates {
13
+ x: number
14
+ y: number
15
+ z?: number
16
+ }
17
+
18
+ // --- Client → Server ---
19
+
20
+ export type SubscribeMessage = {
21
+ type: 'subscribe'
22
+ sub_id: string
23
+ bounds?: BoundingBox
24
+ owner?: string
25
+ prioritize_owner?: string
26
+ }
27
+
28
+ export type UpdateBoundsMessage = {
29
+ type: 'update_bounds'
30
+ sub_id: string
31
+ bounds: BoundingBox
32
+ }
33
+
34
+ export type UnsubscribeMessage = {
35
+ type: 'unsubscribe'
36
+ sub_id: string
37
+ }
38
+
39
+ export type SubscribeEntityMessage = {
40
+ type: 'subscribe_entity'
41
+ sub_id: string
42
+ entity_type: 'ship' | 'warehouse' | 'container'
43
+ entity_id: string
44
+ }
45
+
46
+ export type UnsubscribeEntityMessage = {
47
+ type: 'unsubscribe_entity'
48
+ sub_id: string
49
+ }
50
+
51
+ export type SubscribeEventsMessage = {
52
+ type: 'subscribe_events'
53
+ sub_id: string
54
+ event_filter?: Record<string, unknown>
55
+ }
56
+
57
+ export type UnsubscribeEventsMessage = {
58
+ type: 'unsubscribe_events'
59
+ sub_id: string
60
+ }
61
+
62
+ export type PingMessage = {type: 'ping'}
63
+
64
+ export type ClientMessage =
65
+ | SubscribeMessage
66
+ | UpdateBoundsMessage
67
+ | UnsubscribeMessage
68
+ | SubscribeEntityMessage
69
+ | UnsubscribeEntityMessage
70
+ | SubscribeEventsMessage
71
+ | UnsubscribeEventsMessage
72
+ | PingMessage
73
+
74
+ // --- Server → Client ---
75
+
76
+ export type AckMessage = {
77
+ type: 'subscribed' | 'unsubscribed' | 'bounds_updated'
78
+ sub_id: string
79
+ }
80
+
81
+ export type WireEntity = Record<string, unknown> & {
82
+ type: number
83
+ type_name: 'ship' | 'warehouse' | 'container'
84
+ id: string | number
85
+ owner: string
86
+ coordinates: WireCoordinates
87
+ }
88
+
89
+ export type SnapshotMessage = {
90
+ type: 'snapshot'
91
+ sub_id: string
92
+ seq: number
93
+ entities: WireEntity[]
94
+ truncated?: boolean
95
+ }
96
+
97
+ export type UpdateMessage = {
98
+ type: 'update'
99
+ sub_ids: string[]
100
+ entity_id: number
101
+ entity: WireEntity
102
+ seq: number
103
+ }
104
+
105
+ export type BoundsDeltaMessage = {
106
+ type: 'bounds_delta'
107
+ sub_id: string
108
+ entered: WireEntity[]
109
+ exited: number[]
110
+ seq: number
111
+ truncated?: boolean
112
+ }
113
+
114
+ export type EventMessage = {
115
+ type: 'event'
116
+ sub_id: string
117
+ catchup: boolean
118
+ events: Array<Record<string, unknown>>
119
+ seq?: number
120
+ }
121
+
122
+ export type EventCatchupCompleteMessage = {
123
+ type: 'event_catchup_complete'
124
+ sub_id: string
125
+ }
126
+
127
+ export type PongMessage = {type: 'pong'}
128
+
129
+ export type ErrorMessage = {
130
+ type: 'error'
131
+ error: string
132
+ sub_id?: string
133
+ }
134
+
135
+ export type ServerMessage =
136
+ | AckMessage
137
+ | SnapshotMessage
138
+ | UpdateMessage
139
+ | BoundsDeltaMessage
140
+ | EventMessage
141
+ | EventCatchupCompleteMessage
142
+ | PongMessage
143
+ | ErrorMessage
@@ -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,
@@ -22,24 +23,24 @@ import {
22
23
 
23
24
  import {ServerContract} from '../contracts'
24
25
  import {
26
+ BASE_ORBITAL_MASS,
25
27
  CargoMassInfo,
26
28
  Distance,
27
- INITIAL_SHIP_MASS,
28
29
  MAX_ORBITAL_ALTITUDE,
29
30
  MIN_ORBITAL_ALTITUDE,
30
31
  PRECISION,
31
32
  ShipLike,
32
33
  TaskType,
33
34
  } from '../types'
34
- import {getGood} from '../market/goods'
35
+ import {getItem} from '../market/items'
35
36
  import {hasSystem} from '../utils/system'
36
37
 
37
38
  export function calc_orbital_altitude(mass: number): number {
38
- if (mass <= INITIAL_SHIP_MASS) {
39
+ if (mass <= BASE_ORBITAL_MASS) {
39
40
  return MIN_ORBITAL_ALTITUDE
40
41
  }
41
42
 
42
- const ratio = mass / INITIAL_SHIP_MASS
43
+ const ratio = mass / BASE_ORBITAL_MASS
43
44
  const capRatio = 10.0
44
45
  let scale = Math.log(ratio) / Math.log(capRatio)
45
46
  scale = Math.min(scale, 1.0)
@@ -126,7 +127,12 @@ 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(
132
+ ship.generator.capacity,
133
+ ship.energy ?? UInt16.from(0),
134
+ ship.generator.recharge
135
+ )
130
136
  }
131
137
 
132
138
  export function calc_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
@@ -139,7 +145,9 @@ export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?:
139
145
  }
140
146
 
141
147
  export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
142
- return calc_acceleration(Number(ship.loaders.thrust), Number(mass) + Number(ship.loaders.mass))
148
+ const thrust = ship.loaders ? Number(ship.loaders.thrust) : 0
149
+ const loaderMass = ship.loaders ? Number(ship.loaders.mass) : 0
150
+ return calc_acceleration(thrust, Number(mass) + loaderMass)
143
151
  }
144
152
 
145
153
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -148,7 +156,8 @@ export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UIn
148
156
  }
149
157
 
150
158
  export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
151
- return calc_acceleration(Number(ship.engines.thrust), Number(mass))
159
+ const thrust = ship.engines ? Number(ship.engines.thrust) : 0
160
+ return calc_acceleration(thrust, Number(mass))
152
161
  }
153
162
 
154
163
  export function calc_acceleration(thrust: number, mass: number): number {
@@ -160,12 +169,13 @@ export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64
160
169
 
161
170
  mass.add(ship.hullmass)
162
171
 
163
- if (ship.loaders.quantity.gt(UInt32.zero)) {
172
+ if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
164
173
  mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
165
174
  }
166
175
 
167
176
  for (const cargo of cargos) {
168
- mass.add(getGood(cargo.good_id).mass.multiplying(cargo.quantity))
177
+ const cargoMass = getItem(cargo.item_id).mass * Number(UInt32.from(cargo.quantity))
178
+ mass.add(UInt64.from(cargoMass))
169
179
  }
170
180
 
171
181
  return mass
@@ -183,11 +193,11 @@ export function calculateTransferTime(
183
193
  let mass = UInt64.from(0)
184
194
 
185
195
  for (const cargo of cargos) {
186
- const qty = quantities?.get(Number(cargo.good_id)) ?? 0
196
+ const qty = quantities?.get(Number(cargo.item_id)) ?? 0
187
197
  if (qty > 0) {
188
- const good_mass = getGood(cargo.good_id).mass
189
- const cargo_mass = good_mass.multiplying(qty)
190
- mass = UInt64.from(mass).adding(cargo_mass)
198
+ const good_mass = getItem(cargo.item_id).mass
199
+ const cargo_mass = good_mass * qty
200
+ mass = UInt64.from(mass).adding(UInt64.from(cargo_mass))
191
201
  }
192
202
  }
193
203
 
@@ -195,6 +205,7 @@ export function calculateTransferTime(
195
205
  return UInt32.from(0)
196
206
  }
197
207
 
208
+ if (!ship.loaders) return UInt32.from(0)
198
209
  mass = UInt64.from(mass).adding(ship.loaders.mass)
199
210
  const transfer_time = calc_loader_flighttime(ship, mass)
200
211
  return transfer_time.dividing(ship.loaders.quantity)
@@ -231,20 +242,20 @@ export function calculateLoadTimeBreakdown(
231
242
  let mass_load = UInt64.from(0)
232
243
 
233
244
  for (const cargo of cargos) {
234
- const goodId = Number(cargo.good_id)
245
+ const goodId = Number(cargo.item_id)
235
246
  const loadQty = loadQuantities?.get(goodId) ?? 0
236
247
  const unloadQty = unloadQuantities?.get(goodId) ?? 0
237
248
 
238
249
  if (loadQty > 0 || unloadQty > 0) {
239
- const good = getGood(cargo.good_id)
250
+ const good = getItem(cargo.item_id)
240
251
 
241
252
  if (loadQty > 0) {
242
- const cargo_mass = good.mass.multiplying(loadQty)
243
- 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))
244
255
  }
245
256
  if (unloadQty > 0) {
246
- const cargo_mass = good.mass.multiplying(unloadQty)
247
- 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))
248
259
  }
249
260
  }
250
261
  }
@@ -252,17 +263,17 @@ export function calculateLoadTimeBreakdown(
252
263
  let unloadTime = 0
253
264
  let loadTime = 0
254
265
 
255
- if (mass_unload.gt(UInt64.zero)) {
266
+ if (mass_unload.gt(UInt64.zero) && ship.loaders) {
256
267
  const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
257
268
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
258
269
  }
259
270
 
260
- if (mass_load.gt(UInt64.zero)) {
271
+ if (mass_load.gt(UInt64.zero) && ship.loaders) {
261
272
  const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
262
273
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
263
274
  }
264
275
 
265
- const numLoaders = Number(ship.loaders.quantity)
276
+ const numLoaders = ship.loaders ? Number(ship.loaders.quantity) : 0
266
277
  const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
267
278
  const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
268
279
  const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
@@ -307,6 +318,7 @@ export function estimateTravelTime(
307
318
  if (
308
319
  loadMass &&
309
320
  UInt32.from(loadMass).gt(UInt32.zero) &&
321
+ ship.loaders &&
310
322
  ship.loaders.quantity.gt(UInt32.zero)
311
323
  ) {
312
324
  const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
@@ -316,6 +328,7 @@ export function estimateTravelTime(
316
328
  if (
317
329
  unloadMass &&
318
330
  UInt32.from(unloadMass).gt(UInt32.zero) &&
331
+ ship.loaders &&
319
332
  ship.loaders.quantity.gt(UInt32.zero)
320
333
  ) {
321
334
  const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
@@ -346,8 +359,9 @@ export function estimateDealTravelTime(
346
359
  }
347
360
 
348
361
  export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): boolean {
362
+ if (!ship.engines) return false
349
363
  const energyNeeded = UInt64.from(distance).dividing(PRECISION).multiplying(ship.engines.drain)
350
- return UInt64.from(ship.energy).gte(energyNeeded)
364
+ return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
351
365
  }
352
366
 
353
367
  export interface TransferEntity {
@@ -20,12 +20,8 @@ export interface LoaderCapability {
20
20
  loaders: ServerContract.Types.loader_stats
21
21
  }
22
22
 
23
- export interface TradeCapability {
24
- trade: ServerContract.Types.trade_stats
25
- }
26
-
27
- export interface ExtractorCapability {
28
- extractor: ServerContract.Types.extractor_stats
23
+ export interface GathererCapability {
24
+ gatherer: ServerContract.Types.gatherer_stats
29
25
  }
30
26
 
31
27
  export interface MassCapability {
@@ -42,8 +38,9 @@ export interface EntityCapabilities {
42
38
  engines?: ServerContract.Types.movement_stats
43
39
  generator?: ServerContract.Types.energy_stats
44
40
  loaders?: ServerContract.Types.loader_stats
45
- trade?: ServerContract.Types.trade_stats
46
- extractor?: ServerContract.Types.extractor_stats
41
+ gatherer?: ServerContract.Types.gatherer_stats
42
+ crafter?: ServerContract.Types.crafter_stats
43
+ hauler?: ServerContract.Types.hauler_stats
47
44
  }
48
45
 
49
46
  export interface EntityState {
@@ -66,14 +63,14 @@ export function capsHasLoaders(caps: EntityCapabilities): boolean {
66
63
  return caps.loaders !== undefined
67
64
  }
68
65
 
69
- export function capsHasTrade(caps: EntityCapabilities): boolean {
70
- return caps.trade !== undefined
71
- }
72
-
73
- export function capsHasExtractor(caps: EntityCapabilities): boolean {
74
- return caps.extractor !== undefined
66
+ export function capsHasGatherer(caps: EntityCapabilities): boolean {
67
+ return caps.gatherer !== undefined
75
68
  }
76
69
 
77
70
  export function capsHasMass(caps: EntityCapabilities): boolean {
78
71
  return caps.hullmass !== undefined
79
72
  }
73
+
74
+ export function capsHasHauler(caps: EntityCapabilities): boolean {
75
+ return caps.hauler !== undefined
76
+ }
@@ -11,7 +11,6 @@ export interface EntityTraits {
11
11
  isMovable: boolean
12
12
  hasEnergy: boolean
13
13
  hasLoaders: boolean
14
- hasTrade: boolean
15
14
  notFoundError: string
16
15
  }
17
16
 
@@ -20,7 +19,7 @@ export const shipTraits: EntityTraits = {
20
19
  isMovable: true,
21
20
  hasEnergy: true,
22
21
  hasLoaders: true,
23
- hasTrade: true,
22
+
24
23
  notFoundError: 'ship not found',
25
24
  }
26
25
 
@@ -29,7 +28,7 @@ export const warehouseTraits: EntityTraits = {
29
28
  isMovable: false,
30
29
  hasEnergy: false,
31
30
  hasLoaders: true,
32
- hasTrade: false,
31
+
33
32
  notFoundError: 'warehouse not found',
34
33
  }
35
34
 
@@ -38,7 +37,7 @@ export const containerTraits: EntityTraits = {
38
37
  isMovable: true,
39
38
  hasEnergy: false,
40
39
  hasLoaders: false,
41
- hasTrade: false,
40
+
42
41
  notFoundError: 'container not found',
43
42
  }
44
43
 
@@ -19,17 +19,20 @@ export interface Entity {
19
19
  }
20
20
 
21
21
  export type ShipEntity = Entity &
22
- MovementCapability &
23
- EnergyCapability &
22
+ Partial<MovementCapability> &
23
+ Partial<EnergyCapability> &
24
24
  StorageCapability &
25
- LoaderCapability &
25
+ Partial<LoaderCapability> &
26
26
  MassCapability &
27
27
  ScheduleCapability & {
28
- trade?: ServerContract.Types.trade_stats
29
- extractor?: ServerContract.Types.extractor_stats
28
+ gatherer?: ServerContract.Types.gatherer_stats
30
29
  }
31
30
 
32
- export type WarehouseEntity = Entity & StorageCapability & LoaderCapability & ScheduleCapability
31
+ export type WarehouseEntity = Entity &
32
+ StorageCapability &
33
+ Partial<LoaderCapability> &
34
+ MassCapability &
35
+ ScheduleCapability
33
36
 
34
37
  export type ContainerEntity = Entity & StorageCapability & MassCapability & ScheduleCapability
35
38