@shipload/sdk 1.0.0-next.1 → 1.0.0-next.11
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.
- package/lib/shipload.d.ts +618 -353
- package/lib/shipload.js +2250 -1059
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2193 -1044
- package/lib/shipload.m.js.map +1 -1
- package/package.json +2 -2
- package/src/capabilities/modules.ts +3 -0
- package/src/capabilities/storage.ts +1 -1
- package/src/contracts/platform.ts +13 -1
- package/src/contracts/server.ts +227 -282
- package/src/data/capabilities.ts +5 -330
- package/src/data/capability-formulas.ts +70 -0
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +2 -16
- package/src/data/entities.json +46 -10
- package/src/data/item-ids.ts +4 -1
- package/src/data/items.json +264 -0
- package/src/data/metadata.ts +63 -1
- package/src/data/recipes-runtime.ts +1 -0
- package/src/data/recipes.json +139 -11
- package/src/derivation/capability-mappings.ts +122 -0
- package/src/derivation/index.ts +1 -0
- package/src/derivation/resources.ts +116 -37
- package/src/derivation/stats.ts +1 -2
- package/src/entities/container.ts +25 -10
- package/src/entities/extractor.ts +144 -0
- package/src/entities/factory.ts +135 -0
- package/src/entities/gamestate.ts +0 -9
- package/src/entities/makers.ts +130 -20
- package/src/entities/nexus.ts +29 -0
- package/src/entities/ship-deploy.ts +114 -56
- package/src/entities/ship.ts +17 -0
- package/src/entities/slot-multiplier.ts +21 -0
- package/src/entities/warehouse.ts +20 -3
- package/src/errors.ts +10 -13
- package/src/index-module.ts +81 -26
- package/src/managers/actions.ts +53 -80
- package/src/managers/entities.ts +65 -17
- package/src/managers/locations.ts +2 -20
- package/src/nft/atomicdata.ts +128 -0
- package/src/nft/description.ts +41 -7
- package/src/nft/index.ts +1 -0
- package/src/resolution/resolve-item.ts +17 -9
- package/src/scheduling/accessor.ts +4 -0
- package/src/scheduling/projection.ts +10 -2
- package/src/scheduling/schedule.ts +15 -1
- package/src/scheduling/task-cargo.ts +47 -0
- package/src/subscriptions/connection.ts +50 -2
- package/src/subscriptions/manager.ts +84 -4
- package/src/subscriptions/mappers.ts +5 -1
- package/src/subscriptions/types.ts +2 -2
- package/src/travel/travel.ts +61 -2
- package/src/types/entity-traits.ts +103 -1
- package/src/types.ts +11 -1
- package/src/utils/cargo.ts +27 -0
- package/src/utils/system.ts +25 -24
|
@@ -7,6 +7,9 @@ export interface WebSocketConnectionOptions {
|
|
|
7
7
|
url: string
|
|
8
8
|
onMessage: (message: ServerMessage) => void
|
|
9
9
|
onStateChange?: (state: ConnectionState) => void
|
|
10
|
+
minReconnectDelay?: number
|
|
11
|
+
pingIntervalMs?: number
|
|
12
|
+
pongTimeoutMs?: number
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export class WebSocketConnection {
|
|
@@ -19,15 +22,26 @@ export class WebSocketConnection {
|
|
|
19
22
|
private _state: ConnectionState = 'disconnected'
|
|
20
23
|
private shouldReconnect = true
|
|
21
24
|
private sendQueue: string[] = []
|
|
25
|
+
private minReconnectDelay: number
|
|
26
|
+
private pingIntervalMs: number
|
|
27
|
+
private pongTimeoutMs: number
|
|
28
|
+
private pingTimer: ReturnType<typeof setInterval> | null = null
|
|
29
|
+
private staleTimer: ReturnType<typeof setTimeout> | null = null
|
|
22
30
|
|
|
23
|
-
private static readonly
|
|
31
|
+
private static readonly DEFAULT_MIN_RECONNECT_DELAY = 1000
|
|
24
32
|
private static readonly MAX_RECONNECT_DELAY = 30000
|
|
25
33
|
private static readonly RECONNECT_MULTIPLIER = 2
|
|
34
|
+
private static readonly DEFAULT_PING_INTERVAL_MS = 25000
|
|
35
|
+
private static readonly DEFAULT_PONG_TIMEOUT_MS = 10000
|
|
26
36
|
|
|
27
37
|
constructor(options: WebSocketConnectionOptions) {
|
|
28
38
|
this.url = options.url
|
|
29
39
|
this.onMessage = options.onMessage
|
|
30
40
|
this.onStateChange = options.onStateChange
|
|
41
|
+
this.minReconnectDelay =
|
|
42
|
+
options.minReconnectDelay ?? WebSocketConnection.DEFAULT_MIN_RECONNECT_DELAY
|
|
43
|
+
this.pingIntervalMs = options.pingIntervalMs ?? WebSocketConnection.DEFAULT_PING_INTERVAL_MS
|
|
44
|
+
this.pongTimeoutMs = options.pongTimeoutMs ?? WebSocketConnection.DEFAULT_PONG_TIMEOUT_MS
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
get state(): ConnectionState {
|
|
@@ -64,9 +78,11 @@ export class WebSocketConnection {
|
|
|
64
78
|
) {
|
|
65
79
|
this.ws.send(this.sendQueue.shift()!)
|
|
66
80
|
}
|
|
81
|
+
this.startHeartbeat()
|
|
67
82
|
}
|
|
68
83
|
|
|
69
84
|
this.ws.onmessage = (event) => {
|
|
85
|
+
this.resetStaleTimer()
|
|
70
86
|
try {
|
|
71
87
|
const message = JSON.parse(event.data) as ServerMessage
|
|
72
88
|
this.onMessage(message)
|
|
@@ -77,6 +93,7 @@ export class WebSocketConnection {
|
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
this.ws.onclose = () => {
|
|
96
|
+
this.stopHeartbeat()
|
|
80
97
|
this.ws = null
|
|
81
98
|
this.sendQueue.length = 0
|
|
82
99
|
|
|
@@ -104,7 +121,7 @@ export class WebSocketConnection {
|
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
const delay = Math.min(
|
|
107
|
-
|
|
124
|
+
this.minReconnectDelay *
|
|
108
125
|
WebSocketConnection.RECONNECT_MULTIPLIER ** this.reconnectAttempts,
|
|
109
126
|
WebSocketConnection.MAX_RECONNECT_DELAY
|
|
110
127
|
)
|
|
@@ -126,6 +143,8 @@ export class WebSocketConnection {
|
|
|
126
143
|
this.reconnectTimeout = null
|
|
127
144
|
}
|
|
128
145
|
|
|
146
|
+
this.stopHeartbeat()
|
|
147
|
+
|
|
129
148
|
if (this.ws) {
|
|
130
149
|
this.ws.close()
|
|
131
150
|
this.ws = null
|
|
@@ -135,6 +154,35 @@ export class WebSocketConnection {
|
|
|
135
154
|
this.setState('disconnected')
|
|
136
155
|
}
|
|
137
156
|
|
|
157
|
+
private startHeartbeat() {
|
|
158
|
+
this.stopHeartbeat()
|
|
159
|
+
this.resetStaleTimer()
|
|
160
|
+
this.pingTimer = setInterval(() => {
|
|
161
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
162
|
+
this.ws.send(JSON.stringify({type: 'ping'}))
|
|
163
|
+
}
|
|
164
|
+
}, this.pingIntervalMs)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private stopHeartbeat() {
|
|
168
|
+
if (this.pingTimer) {
|
|
169
|
+
clearInterval(this.pingTimer)
|
|
170
|
+
this.pingTimer = null
|
|
171
|
+
}
|
|
172
|
+
if (this.staleTimer) {
|
|
173
|
+
clearTimeout(this.staleTimer)
|
|
174
|
+
this.staleTimer = null
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private resetStaleTimer() {
|
|
179
|
+
if (this.staleTimer) clearTimeout(this.staleTimer)
|
|
180
|
+
this.staleTimer = setTimeout(() => {
|
|
181
|
+
debug('No frames within ping interval + pong timeout — forcing reconnect')
|
|
182
|
+
if (this.ws) this.ws.close()
|
|
183
|
+
}, this.pingIntervalMs + this.pongTimeoutMs)
|
|
184
|
+
}
|
|
185
|
+
|
|
138
186
|
close() {
|
|
139
187
|
this.disconnect()
|
|
140
188
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {WebSocketConnection} from './connection'
|
|
1
|
+
import {WebSocketConnection, type ConnectionState} from './connection'
|
|
2
2
|
import type {
|
|
3
3
|
BoundingBox,
|
|
4
4
|
BoundsDeltaMessage,
|
|
@@ -16,12 +16,16 @@ import {mapEntity, parseWireEntity} from './mappers'
|
|
|
16
16
|
import type {Ship} from '../entities/ship'
|
|
17
17
|
import type {Warehouse} from '../entities/warehouse'
|
|
18
18
|
import type {Container} from '../entities/container'
|
|
19
|
+
import type {Nexus} from '../entities/nexus'
|
|
19
20
|
|
|
20
|
-
export type SubscriptionEntityType = 'ship' | 'warehouse' | 'container'
|
|
21
|
-
export type EntityInstance = Ship | Warehouse | Container
|
|
21
|
+
export type SubscriptionEntityType = 'ship' | 'warehouse' | 'container' | 'nexus'
|
|
22
|
+
export type EntityInstance = Ship | Warehouse | Container | Nexus
|
|
22
23
|
|
|
23
24
|
export interface SubscriptionsOptions {
|
|
24
25
|
url: string
|
|
26
|
+
minReconnectDelay?: number
|
|
27
|
+
pingIntervalMs?: number
|
|
28
|
+
pongTimeoutMs?: number
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export interface BoundsSubscriptionHandle {
|
|
@@ -31,6 +35,12 @@ export interface BoundsSubscriptionHandle {
|
|
|
31
35
|
current: Map<number, EntityInstance>
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
export interface OwnerSubscriptionHandle {
|
|
39
|
+
readonly subId: string
|
|
40
|
+
unsubscribe(): void
|
|
41
|
+
current: Map<number, EntityInstance>
|
|
42
|
+
}
|
|
43
|
+
|
|
34
44
|
export interface EntitySubscriptionHandle {
|
|
35
45
|
readonly subId: string
|
|
36
46
|
readonly entityType: SubscriptionEntityType
|
|
@@ -53,18 +63,26 @@ export class SubscriptionsManager {
|
|
|
53
63
|
private readonly boundsSubs = new Map<
|
|
54
64
|
string,
|
|
55
65
|
{
|
|
66
|
+
bounds?: BoundingBox
|
|
67
|
+
owner?: string
|
|
68
|
+
prioritizeOwner?: string
|
|
56
69
|
onSnapshot?: (entities: EntityInstance[]) => void
|
|
57
70
|
onUpdate?: (entity: EntityInstance) => void
|
|
58
71
|
onBoundsDelta?: (entered: EntityInstance[], exited: number[]) => void
|
|
59
|
-
handle: BoundsSubscriptionHandle
|
|
72
|
+
handle: BoundsSubscriptionHandle | OwnerSubscriptionHandle
|
|
60
73
|
}
|
|
61
74
|
>()
|
|
62
75
|
private subCounter = 0
|
|
76
|
+
private hasConnected = false
|
|
63
77
|
|
|
64
78
|
constructor(opts: SubscriptionsOptions) {
|
|
65
79
|
this.conn = new WebSocketConnection({
|
|
66
80
|
url: opts.url,
|
|
67
81
|
onMessage: (m) => this.onMessage(m),
|
|
82
|
+
onStateChange: (s) => this.onStateChange(s),
|
|
83
|
+
minReconnectDelay: opts.minReconnectDelay,
|
|
84
|
+
pingIntervalMs: opts.pingIntervalMs,
|
|
85
|
+
pongTimeoutMs: opts.pongTimeoutMs,
|
|
68
86
|
})
|
|
69
87
|
this.conn.connect()
|
|
70
88
|
}
|
|
@@ -139,6 +157,9 @@ export class SubscriptionsManager {
|
|
|
139
157
|
current: new Map(),
|
|
140
158
|
}
|
|
141
159
|
this.boundsSubs.set(subId, {
|
|
160
|
+
bounds,
|
|
161
|
+
owner: handlers.owner,
|
|
162
|
+
prioritizeOwner: handlers.prioritizeOwner,
|
|
142
163
|
onSnapshot: handlers.onSnapshot,
|
|
143
164
|
onUpdate: handlers.onUpdate,
|
|
144
165
|
onBoundsDelta: handlers.onBoundsDelta,
|
|
@@ -148,16 +169,75 @@ export class SubscriptionsManager {
|
|
|
148
169
|
return handle
|
|
149
170
|
}
|
|
150
171
|
|
|
172
|
+
subscribeOwner(
|
|
173
|
+
owner: string,
|
|
174
|
+
handlers: {
|
|
175
|
+
onSnapshot?: (entities: EntityInstance[]) => void
|
|
176
|
+
onUpdate?: (entity: EntityInstance) => void
|
|
177
|
+
} = {}
|
|
178
|
+
): OwnerSubscriptionHandle {
|
|
179
|
+
const subId = this.generateSubID('own')
|
|
180
|
+
const msg: SubscribeMessage = {
|
|
181
|
+
type: 'subscribe',
|
|
182
|
+
sub_id: subId,
|
|
183
|
+
owner,
|
|
184
|
+
}
|
|
185
|
+
const handle: OwnerSubscriptionHandle = {
|
|
186
|
+
subId,
|
|
187
|
+
unsubscribe: () => this.unsubscribeBounds(subId),
|
|
188
|
+
current: new Map(),
|
|
189
|
+
}
|
|
190
|
+
this.boundsSubs.set(subId, {
|
|
191
|
+
bounds: undefined,
|
|
192
|
+
owner,
|
|
193
|
+
prioritizeOwner: undefined,
|
|
194
|
+
onSnapshot: handlers.onSnapshot,
|
|
195
|
+
onUpdate: handlers.onUpdate,
|
|
196
|
+
handle,
|
|
197
|
+
})
|
|
198
|
+
this.sendMessage(msg)
|
|
199
|
+
return handle
|
|
200
|
+
}
|
|
201
|
+
|
|
151
202
|
private unsubscribeBounds(subId: string) {
|
|
152
203
|
this.boundsSubs.delete(subId)
|
|
153
204
|
this.sendMessage({type: 'unsubscribe', sub_id: subId})
|
|
154
205
|
}
|
|
155
206
|
|
|
156
207
|
private updateBounds(subId: string, bounds: BoundingBox) {
|
|
208
|
+
const entry = this.boundsSubs.get(subId)
|
|
209
|
+
if (entry) entry.bounds = bounds
|
|
157
210
|
const msg: UpdateBoundsMessage = {type: 'update_bounds', sub_id: subId, bounds}
|
|
158
211
|
this.sendMessage(msg)
|
|
159
212
|
}
|
|
160
213
|
|
|
214
|
+
private onStateChange(state: ConnectionState) {
|
|
215
|
+
if (state !== 'connected') return
|
|
216
|
+
if (!this.hasConnected) {
|
|
217
|
+
this.hasConnected = true
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
for (const [subId, entry] of this.entitySubs) {
|
|
221
|
+
const msg: SubscribeEntityMessage = {
|
|
222
|
+
type: 'subscribe_entity',
|
|
223
|
+
sub_id: subId,
|
|
224
|
+
entity_type: entry.type,
|
|
225
|
+
entity_id: entry.id,
|
|
226
|
+
}
|
|
227
|
+
this.sendMessage(msg)
|
|
228
|
+
}
|
|
229
|
+
for (const [subId, entry] of this.boundsSubs) {
|
|
230
|
+
const msg: SubscribeMessage = {
|
|
231
|
+
type: 'subscribe',
|
|
232
|
+
sub_id: subId,
|
|
233
|
+
bounds: entry.bounds,
|
|
234
|
+
owner: entry.owner,
|
|
235
|
+
prioritize_owner: entry.prioritizeOwner,
|
|
236
|
+
}
|
|
237
|
+
this.sendMessage(msg)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
161
241
|
private onMessage(msg: ServerMessage) {
|
|
162
242
|
switch (msg.type) {
|
|
163
243
|
case 'snapshot':
|
|
@@ -2,12 +2,16 @@ import {ServerContract} from '../contracts'
|
|
|
2
2
|
import {Ship} from '../entities/ship'
|
|
3
3
|
import {Warehouse} from '../entities/warehouse'
|
|
4
4
|
import {Container} from '../entities/container'
|
|
5
|
+
import {Nexus} from '../entities/nexus'
|
|
5
6
|
import type {WireEntity} from './types'
|
|
6
7
|
|
|
7
|
-
export function mapEntity(
|
|
8
|
+
export function mapEntity(
|
|
9
|
+
ei: ServerContract.Types.entity_info
|
|
10
|
+
): Ship | Warehouse | Container | Nexus {
|
|
8
11
|
if (ei.type.equals('ship')) return new Ship(ei)
|
|
9
12
|
if (ei.type.equals('warehouse')) return new Warehouse(ei)
|
|
10
13
|
if (ei.type.equals('container')) return new Container(ei)
|
|
14
|
+
if (ei.type.equals('nexus')) return new Nexus(ei)
|
|
11
15
|
throw new Error(`mapEntity: unknown entity type ${ei.type.toString()}`)
|
|
12
16
|
}
|
|
13
17
|
|
|
@@ -39,7 +39,7 @@ export type UnsubscribeMessage = {
|
|
|
39
39
|
export type SubscribeEntityMessage = {
|
|
40
40
|
type: 'subscribe_entity'
|
|
41
41
|
sub_id: string
|
|
42
|
-
entity_type: 'ship' | 'warehouse' | 'container'
|
|
42
|
+
entity_type: 'ship' | 'warehouse' | 'container' | 'nexus'
|
|
43
43
|
entity_id: string
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -80,7 +80,7 @@ export type AckMessage = {
|
|
|
80
80
|
|
|
81
81
|
export type WireEntity = Record<string, unknown> & {
|
|
82
82
|
type: number
|
|
83
|
-
type_name: 'ship' | 'warehouse' | 'container'
|
|
83
|
+
type_name: 'ship' | 'warehouse' | 'container' | 'nexus'
|
|
84
84
|
id: string | number
|
|
85
85
|
owner: string
|
|
86
86
|
coordinates: WireCoordinates
|
package/src/travel/travel.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
type Distance,
|
|
29
29
|
MAX_ORBITAL_ALTITUDE,
|
|
30
30
|
MIN_ORBITAL_ALTITUDE,
|
|
31
|
+
MIN_TRANSFER_DISTANCE,
|
|
31
32
|
PRECISION,
|
|
32
33
|
type ShipLike,
|
|
33
34
|
TaskType,
|
|
@@ -77,6 +78,59 @@ export function lerp(
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
export interface FloatPosition {
|
|
82
|
+
x: number
|
|
83
|
+
y: number
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function easeFlightProgress(t: number): number {
|
|
87
|
+
if (t <= 0) return 0
|
|
88
|
+
if (t >= 1) return 1
|
|
89
|
+
return t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function flightSpeedFactor(t: number): number {
|
|
93
|
+
if (t <= 0 || t >= 1) return 0
|
|
94
|
+
return t < 0.5 ? 4 * t : 4 * (1 - t)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function interpolateFlightPosition(
|
|
98
|
+
origin: {x: Int64Type | number; y: Int64Type | number},
|
|
99
|
+
destination: {x: Int64Type | number; y: Int64Type | number},
|
|
100
|
+
taskProgress: number,
|
|
101
|
+
options?: {easing?: 'physics' | 'linear'}
|
|
102
|
+
): FloatPosition {
|
|
103
|
+
const t = options?.easing === 'linear' ? taskProgress : easeFlightProgress(taskProgress)
|
|
104
|
+
return {
|
|
105
|
+
x: (1 - t) * Number(origin.x) + t * Number(destination.x),
|
|
106
|
+
y: (1 - t) * Number(origin.y) + t * Number(destination.y),
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getInterpolatedPosition(
|
|
111
|
+
entity: HasScheduleAndLocation,
|
|
112
|
+
taskIndex: number,
|
|
113
|
+
taskProgress: number
|
|
114
|
+
): FloatPosition {
|
|
115
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) {
|
|
116
|
+
return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
|
|
117
|
+
}
|
|
118
|
+
if (taskIndex < 0) {
|
|
119
|
+
const settled = getFlightOrigin(entity, entity.schedule.tasks.length)
|
|
120
|
+
return {x: Number(settled.x), y: Number(settled.y)}
|
|
121
|
+
}
|
|
122
|
+
const task = entity.schedule.tasks[taskIndex]
|
|
123
|
+
if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
|
|
124
|
+
const origin = getFlightOrigin(entity, taskIndex)
|
|
125
|
+
return {x: Number(origin.x), y: Number(origin.y)}
|
|
126
|
+
}
|
|
127
|
+
return interpolateFlightPosition(
|
|
128
|
+
getFlightOrigin(entity, taskIndex),
|
|
129
|
+
task.coordinates,
|
|
130
|
+
taskProgress
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
80
134
|
export function rotation(
|
|
81
135
|
origin: ServerContract.ActionParams.Type.coordinates,
|
|
82
136
|
destination: ServerContract.ActionParams.Type.coordinates
|
|
@@ -408,14 +462,18 @@ export function getDestinationLocation(
|
|
|
408
462
|
return undefined
|
|
409
463
|
}
|
|
410
464
|
|
|
465
|
+
/** Returns chain-tile coordinates (rounded). For visual position use getInterpolatedPosition. */
|
|
411
466
|
export function getPositionAt(
|
|
412
467
|
entity: HasScheduleAndLocation,
|
|
413
468
|
taskIndex: number,
|
|
414
469
|
taskProgress: number
|
|
415
470
|
): ServerContract.ActionParams.Type.coordinates {
|
|
416
|
-
if (!entity.schedule || entity.schedule.tasks.length === 0
|
|
471
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) {
|
|
417
472
|
return entity.coordinates
|
|
418
473
|
}
|
|
474
|
+
if (taskIndex < 0) {
|
|
475
|
+
return getFlightOrigin(entity, entity.schedule.tasks.length)
|
|
476
|
+
}
|
|
419
477
|
|
|
420
478
|
const task = entity.schedule.tasks[taskIndex]
|
|
421
479
|
|
|
@@ -490,7 +548,8 @@ export function calc_transfer_duration(
|
|
|
490
548
|
: (source.location.z?.toNumber() ?? 0)
|
|
491
549
|
const destZ =
|
|
492
550
|
typeof dest.location.z === 'number' ? dest.location.z : (dest.location.z?.toNumber() ?? 0)
|
|
493
|
-
const
|
|
551
|
+
const rawDistance = Math.abs(sourceZ - destZ)
|
|
552
|
+
const distance = rawDistance < MIN_TRANSFER_DISTANCE ? MIN_TRANSFER_DISTANCE : rawDistance
|
|
494
553
|
|
|
495
554
|
const totalMass = cargoMass + totalLoaderMass
|
|
496
555
|
const acceleration = calc_acceleration(totalThrust, totalMass)
|
|
@@ -1,16 +1,67 @@
|
|
|
1
1
|
import {Name} from '@wharfkit/antelope'
|
|
2
|
+
import {
|
|
3
|
+
ITEM_CONTAINER_T1_PACKED,
|
|
4
|
+
ITEM_CONTAINER_T2_PACKED,
|
|
5
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
6
|
+
ITEM_FACTORY_T1_PACKED,
|
|
7
|
+
ITEM_SHIP_T1_PACKED,
|
|
8
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
9
|
+
} from '../data/item-ids'
|
|
2
10
|
|
|
3
11
|
export const ENTITY_SHIP = Name.from('ship')
|
|
4
12
|
export const ENTITY_WAREHOUSE = Name.from('warehouse')
|
|
13
|
+
export const ENTITY_EXTRACTOR = Name.from('extractor')
|
|
14
|
+
export const ENTITY_FACTORY = Name.from('factory')
|
|
5
15
|
export const ENTITY_CONTAINER = Name.from('container')
|
|
16
|
+
export const ENTITY_NEXUS = Name.from('nexus')
|
|
6
17
|
|
|
7
|
-
export
|
|
18
|
+
export enum EntityClass {
|
|
19
|
+
OrbitalVessel = 0,
|
|
20
|
+
PlanetaryStructure = 1,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getEntityClass(entityType: Name | EntityTypeName): EntityClass {
|
|
24
|
+
const typeName = typeof entityType === 'string' ? entityType : entityType.toString()
|
|
25
|
+
switch (typeName) {
|
|
26
|
+
case 'ship':
|
|
27
|
+
case 'container':
|
|
28
|
+
case 'nexus':
|
|
29
|
+
return EntityClass.OrbitalVessel
|
|
30
|
+
case 'warehouse':
|
|
31
|
+
case 'extractor':
|
|
32
|
+
case 'factory':
|
|
33
|
+
return EntityClass.PlanetaryStructure
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(`Entity type has no class: ${typeName}`)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getPackedEntityType(itemId: number): Name | null {
|
|
40
|
+
switch (itemId) {
|
|
41
|
+
case ITEM_SHIP_T1_PACKED:
|
|
42
|
+
return ENTITY_SHIP
|
|
43
|
+
case ITEM_CONTAINER_T1_PACKED:
|
|
44
|
+
case ITEM_CONTAINER_T2_PACKED:
|
|
45
|
+
return ENTITY_CONTAINER
|
|
46
|
+
case ITEM_WAREHOUSE_T1_PACKED:
|
|
47
|
+
return ENTITY_WAREHOUSE
|
|
48
|
+
case ITEM_EXTRACTOR_T1_PACKED:
|
|
49
|
+
return ENTITY_EXTRACTOR
|
|
50
|
+
case ITEM_FACTORY_T1_PACKED:
|
|
51
|
+
return ENTITY_FACTORY
|
|
52
|
+
default:
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type EntityTypeName = 'ship' | 'warehouse' | 'extractor' | 'factory' | 'container' | 'nexus'
|
|
8
58
|
|
|
9
59
|
export interface EntityTraits {
|
|
10
60
|
typeName: Name
|
|
11
61
|
isMovable: boolean
|
|
12
62
|
hasEnergy: boolean
|
|
13
63
|
hasLoaders: boolean
|
|
64
|
+
hasModules: boolean
|
|
14
65
|
notFoundError: string
|
|
15
66
|
}
|
|
16
67
|
|
|
@@ -19,6 +70,7 @@ export const shipTraits: EntityTraits = {
|
|
|
19
70
|
isMovable: true,
|
|
20
71
|
hasEnergy: true,
|
|
21
72
|
hasLoaders: true,
|
|
73
|
+
hasModules: true,
|
|
22
74
|
|
|
23
75
|
notFoundError: 'ship not found',
|
|
24
76
|
}
|
|
@@ -28,19 +80,51 @@ export const warehouseTraits: EntityTraits = {
|
|
|
28
80
|
isMovable: false,
|
|
29
81
|
hasEnergy: false,
|
|
30
82
|
hasLoaders: true,
|
|
83
|
+
hasModules: true,
|
|
31
84
|
|
|
32
85
|
notFoundError: 'warehouse not found',
|
|
33
86
|
}
|
|
34
87
|
|
|
88
|
+
export const extractorTraits: EntityTraits = {
|
|
89
|
+
typeName: ENTITY_EXTRACTOR,
|
|
90
|
+
isMovable: false,
|
|
91
|
+
hasEnergy: true,
|
|
92
|
+
hasLoaders: false,
|
|
93
|
+
hasModules: true,
|
|
94
|
+
|
|
95
|
+
notFoundError: 'extractor not found',
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const factoryTraits: EntityTraits = {
|
|
99
|
+
typeName: ENTITY_FACTORY,
|
|
100
|
+
isMovable: false,
|
|
101
|
+
hasEnergy: true,
|
|
102
|
+
hasLoaders: false,
|
|
103
|
+
hasModules: true,
|
|
104
|
+
|
|
105
|
+
notFoundError: 'factory not found',
|
|
106
|
+
}
|
|
107
|
+
|
|
35
108
|
export const containerTraits: EntityTraits = {
|
|
36
109
|
typeName: ENTITY_CONTAINER,
|
|
37
110
|
isMovable: true,
|
|
38
111
|
hasEnergy: false,
|
|
39
112
|
hasLoaders: false,
|
|
113
|
+
hasModules: false,
|
|
40
114
|
|
|
41
115
|
notFoundError: 'container not found',
|
|
42
116
|
}
|
|
43
117
|
|
|
118
|
+
export const nexusTraits: EntityTraits = {
|
|
119
|
+
typeName: ENTITY_NEXUS,
|
|
120
|
+
isMovable: false,
|
|
121
|
+
hasEnergy: false,
|
|
122
|
+
hasLoaders: false,
|
|
123
|
+
hasModules: false,
|
|
124
|
+
|
|
125
|
+
notFoundError: 'nexus not found',
|
|
126
|
+
}
|
|
127
|
+
|
|
44
128
|
export function getEntityTraits(entityType: Name | EntityTypeName): EntityTraits {
|
|
45
129
|
const typeName = typeof entityType === 'string' ? entityType : entityType.toString()
|
|
46
130
|
|
|
@@ -49,8 +133,14 @@ export function getEntityTraits(entityType: Name | EntityTypeName): EntityTraits
|
|
|
49
133
|
return shipTraits
|
|
50
134
|
case 'warehouse':
|
|
51
135
|
return warehouseTraits
|
|
136
|
+
case 'extractor':
|
|
137
|
+
return extractorTraits
|
|
138
|
+
case 'factory':
|
|
139
|
+
return factoryTraits
|
|
52
140
|
case 'container':
|
|
53
141
|
return containerTraits
|
|
142
|
+
case 'nexus':
|
|
143
|
+
return nexusTraits
|
|
54
144
|
default:
|
|
55
145
|
throw new Error(`Unknown entity type: ${typeName}`)
|
|
56
146
|
}
|
|
@@ -64,6 +154,18 @@ export function isWarehouse(entity: {type?: Name}): boolean {
|
|
|
64
154
|
return entity.type?.equals(ENTITY_WAREHOUSE) ?? false
|
|
65
155
|
}
|
|
66
156
|
|
|
157
|
+
export function isExtractor(entity: {type?: Name}): boolean {
|
|
158
|
+
return entity.type?.equals(ENTITY_EXTRACTOR) ?? false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function isFactory(entity: {type?: Name}): boolean {
|
|
162
|
+
return entity.type?.equals(ENTITY_FACTORY) ?? false
|
|
163
|
+
}
|
|
164
|
+
|
|
67
165
|
export function isContainer(entity: {type?: Name}): boolean {
|
|
68
166
|
return entity.type?.equals(ENTITY_CONTAINER) ?? false
|
|
69
167
|
}
|
|
168
|
+
|
|
169
|
+
export function isNexus(entity: {type?: Name}): boolean {
|
|
170
|
+
return entity.type?.equals(ENTITY_NEXUS) ?? false
|
|
171
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {ServerContract} from './contracts'
|
|
|
12
12
|
export const PRECISION = 10000
|
|
13
13
|
export const CRAFT_ENERGY_DIVISOR = 150000
|
|
14
14
|
|
|
15
|
-
export const
|
|
15
|
+
export const PLANETARY_STRUCTURE_Z = 0
|
|
16
16
|
|
|
17
17
|
export const CONTAINER_Z = 300
|
|
18
18
|
|
|
@@ -23,6 +23,8 @@ export const MAX_ORBITAL_ALTITUDE = 3000
|
|
|
23
23
|
|
|
24
24
|
export const BASE_ORBITAL_MASS = 100000
|
|
25
25
|
|
|
26
|
+
export const MIN_TRANSFER_DISTANCE = 100
|
|
27
|
+
|
|
26
28
|
export interface ShipLike {
|
|
27
29
|
coordinates: ServerContract.Types.coordinates
|
|
28
30
|
hullmass?: UInt32
|
|
@@ -51,6 +53,9 @@ export enum TaskType {
|
|
|
51
53
|
DEPLOY = 8,
|
|
52
54
|
WRAP = 9,
|
|
53
55
|
UNWRAP = 10,
|
|
56
|
+
UNDEPLOY = 11,
|
|
57
|
+
WRAP_ENTITY = 12,
|
|
58
|
+
DEMOLISH = 13,
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
export enum LocationType {
|
|
@@ -58,6 +63,7 @@ export enum LocationType {
|
|
|
58
63
|
PLANET = 1,
|
|
59
64
|
ASTEROID = 2,
|
|
60
65
|
NEBULA = 3,
|
|
66
|
+
ICE_FIELD = 4,
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
export enum TaskCancelable {
|
|
@@ -159,3 +165,7 @@ export interface Item {
|
|
|
159
165
|
export function formatTier(tier: number): string {
|
|
160
166
|
return 'T' + tier
|
|
161
167
|
}
|
|
168
|
+
|
|
169
|
+
export function tierAdjective(tier: number): string {
|
|
170
|
+
return TIER_ADJECTIVES[tier] ?? `T${tier}`
|
|
171
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type {ServerContract} from '../contracts'
|
|
2
|
+
|
|
3
|
+
export function cargoRef(src: {
|
|
4
|
+
item_id: number
|
|
5
|
+
stats: bigint | number
|
|
6
|
+
modules?: ServerContract.Types.module_entry[]
|
|
7
|
+
}): ServerContract.ActionParams.Type.cargo_ref {
|
|
8
|
+
return {
|
|
9
|
+
item_id: src.item_id,
|
|
10
|
+
stats: src.stats,
|
|
11
|
+
modules: src.modules ?? [],
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function cargoItem(
|
|
16
|
+
src: {
|
|
17
|
+
item_id: number
|
|
18
|
+
stats: bigint | number
|
|
19
|
+
modules?: ServerContract.Types.module_entry[]
|
|
20
|
+
},
|
|
21
|
+
quantity: bigint | number
|
|
22
|
+
): ServerContract.ActionParams.Type.cargo_item {
|
|
23
|
+
return {
|
|
24
|
+
...cargoRef(src),
|
|
25
|
+
quantity,
|
|
26
|
+
}
|
|
27
|
+
}
|