@shipload/sdk 0.7.1 → 2.0.0-rc2
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/README.md +349 -1
- package/lib/shipload.d.ts +2016 -230
- package/lib/shipload.js +5733 -2094
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +5425 -2012
- package/lib/shipload.m.js.map +1 -1
- package/package.json +5 -5
- package/src/capabilities/extraction.ts +37 -0
- package/src/capabilities/guards.ts +43 -0
- package/src/capabilities/index.ts +5 -0
- package/src/capabilities/loading.ts +8 -0
- package/src/capabilities/movement.ts +29 -0
- package/src/capabilities/storage.ts +67 -0
- package/src/contracts/server.ts +788 -202
- package/src/data/goods.json +23 -0
- package/src/data/syllables.json +1184 -0
- package/src/entities/cargo-utils.ts +142 -0
- package/src/entities/container.ts +70 -0
- package/src/entities/entity-inventory.ts +39 -0
- package/src/entities/gamestate.ts +152 -0
- package/src/entities/inventory-accessor.ts +46 -0
- package/src/entities/location.ts +255 -0
- package/src/entities/makers.ts +69 -0
- package/src/entities/player.ts +288 -0
- package/src/entities/ship.ts +208 -0
- package/src/entities/warehouse.ts +89 -0
- package/src/errors.ts +46 -9
- package/src/index-module.ts +152 -7
- package/src/managers/actions.ts +200 -0
- package/src/managers/base.ts +25 -0
- package/src/managers/context.ts +104 -0
- package/src/managers/entities.ts +103 -0
- package/src/managers/epochs.ts +47 -0
- package/src/managers/index.ts +9 -0
- package/src/managers/locations.ts +122 -0
- package/src/managers/players.ts +13 -0
- package/src/managers/trades.ts +119 -0
- package/src/market/goods.ts +31 -0
- package/src/{market.ts → market/market.ts} +31 -37
- package/src/{rolls.ts → market/rolls.ts} +3 -3
- package/src/scheduling/accessor.ts +82 -0
- package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
- package/src/scheduling/projection.ts +290 -0
- package/src/scheduling/schedule.ts +179 -0
- package/src/shipload.ts +39 -157
- package/src/trading/collect.ts +938 -0
- package/src/trading/deal.ts +207 -0
- package/src/trading/trade.ts +203 -0
- package/src/travel/travel.ts +486 -0
- package/src/types/capabilities.ts +79 -0
- package/src/types/entity-traits.ts +70 -0
- package/src/types/entity.ts +36 -0
- package/src/types/index.ts +3 -0
- package/src/types.ts +127 -25
- package/src/{hash.ts → utils/hash.ts} +1 -1
- package/src/utils/system.ts +155 -0
- package/src/goods.ts +0 -124
- package/src/ship.ts +0 -36
- package/src/state.ts +0 -0
- package/src/syllables.ts +0 -1184
- package/src/system.ts +0 -37
- package/src/travel.ts +0 -259
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Travel calculations for ship movement, energy usage, and flight times.
|
|
3
|
+
*
|
|
4
|
+
* Functions prefixed with `calc_` are contract-parity functions that mirror
|
|
5
|
+
* the C++ implementation in the server contract (schedule.cpp, ship.cpp).
|
|
6
|
+
* These use snake_case intentionally to match the contract naming convention
|
|
7
|
+
* and signal that they must produce identical results to the on-chain code.
|
|
8
|
+
*
|
|
9
|
+
* Functions prefixed with `calculate` are higher-level SDK helpers that may
|
|
10
|
+
* combine multiple contract calculations for convenience.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
Checksum256,
|
|
15
|
+
Int64,
|
|
16
|
+
Int64Type,
|
|
17
|
+
UInt32,
|
|
18
|
+
UInt32Type,
|
|
19
|
+
UInt64,
|
|
20
|
+
UInt64Type,
|
|
21
|
+
} from '@wharfkit/antelope'
|
|
22
|
+
|
|
23
|
+
import {ServerContract} from '../contracts'
|
|
24
|
+
import {
|
|
25
|
+
CargoMassInfo,
|
|
26
|
+
Distance,
|
|
27
|
+
INITIAL_SHIP_MASS,
|
|
28
|
+
MAX_ORBITAL_ALTITUDE,
|
|
29
|
+
MIN_ORBITAL_ALTITUDE,
|
|
30
|
+
PRECISION,
|
|
31
|
+
ShipLike,
|
|
32
|
+
TaskType,
|
|
33
|
+
} from '../types'
|
|
34
|
+
import {getGood} from '../market/goods'
|
|
35
|
+
import {hasSystem} from '../utils/system'
|
|
36
|
+
|
|
37
|
+
export function calc_orbital_altitude(mass: number): number {
|
|
38
|
+
if (mass <= INITIAL_SHIP_MASS) {
|
|
39
|
+
return MIN_ORBITAL_ALTITUDE
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ratio = mass / INITIAL_SHIP_MASS
|
|
43
|
+
const capRatio = 10.0
|
|
44
|
+
let scale = Math.log(ratio) / Math.log(capRatio)
|
|
45
|
+
scale = Math.min(scale, 1.0)
|
|
46
|
+
|
|
47
|
+
return MIN_ORBITAL_ALTITUDE + Math.floor((MAX_ORBITAL_ALTITUDE - MIN_ORBITAL_ALTITUDE) * scale)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function distanceBetweenCoordinates(
|
|
51
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
52
|
+
destination: ServerContract.ActionParams.Type.coordinates
|
|
53
|
+
): UInt64 {
|
|
54
|
+
return distanceBetweenPoints(origin.x, origin.y, destination.x, destination.y)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function distanceBetweenPoints(
|
|
58
|
+
x1: Int64Type,
|
|
59
|
+
y1: Int64Type,
|
|
60
|
+
x2: Int64Type,
|
|
61
|
+
y2: Int64Type
|
|
62
|
+
): UInt64 {
|
|
63
|
+
const x = Math.pow(x1 - x2, 2)
|
|
64
|
+
const y = Math.pow(y1 - y2, 2)
|
|
65
|
+
return UInt64.from(Math.sqrt(x + y) * PRECISION)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function lerp(
|
|
69
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
70
|
+
destination: ServerContract.ActionParams.Type.coordinates,
|
|
71
|
+
time: number
|
|
72
|
+
): ServerContract.ActionParams.Type.coordinates {
|
|
73
|
+
return {
|
|
74
|
+
x: (1 - time) * Number(origin.x) + time * Number(destination.x),
|
|
75
|
+
y: (1 - time) * Number(origin.y) + time * Number(destination.y),
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function rotation(
|
|
80
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
81
|
+
destination: ServerContract.ActionParams.Type.coordinates
|
|
82
|
+
) {
|
|
83
|
+
return Math.atan2(destination.y - origin.y, destination.x - origin.x) * (180 / Math.PI) + 90
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function findNearbyPlanets(
|
|
87
|
+
seed: Checksum256,
|
|
88
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
89
|
+
maxDistance: UInt64Type = 20 * PRECISION
|
|
90
|
+
): Distance[] {
|
|
91
|
+
const nearbySystems: Distance[] = []
|
|
92
|
+
|
|
93
|
+
const max = UInt64.from(maxDistance / PRECISION)
|
|
94
|
+
const xMin = Int64.from(origin.x).subtracting(max)
|
|
95
|
+
const xMax = Int64.from(origin.x).adding(max)
|
|
96
|
+
const yMin = Int64.from(origin.y).subtracting(max)
|
|
97
|
+
const yMax = Int64.from(origin.y).adding(max)
|
|
98
|
+
|
|
99
|
+
for (let x = Number(xMin); x <= Number(xMax); x++) {
|
|
100
|
+
for (let y = Number(yMin); y <= Number(yMax); y++) {
|
|
101
|
+
const samePlace = x === Number(origin.x) && y === Number(origin.y)
|
|
102
|
+
if (!samePlace) {
|
|
103
|
+
const distance = distanceBetweenPoints(origin.x, origin.y, x, y)
|
|
104
|
+
if (Number(distance) <= Number(maxDistance)) {
|
|
105
|
+
const system = hasSystem(seed, {x, y})
|
|
106
|
+
if (system) {
|
|
107
|
+
nearbySystems.push({origin, destination: {x, y}, distance})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return nearbySystems
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function calc_rechargetime(
|
|
118
|
+
capacity: UInt32Type,
|
|
119
|
+
energy: UInt32Type,
|
|
120
|
+
recharge: UInt32Type
|
|
121
|
+
): UInt32 {
|
|
122
|
+
const cap = UInt32.from(capacity)
|
|
123
|
+
const eng = UInt32.from(energy)
|
|
124
|
+
if (eng.gte(cap)) return UInt32.zero
|
|
125
|
+
return cap.subtracting(eng).dividing(recharge)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
|
|
129
|
+
return calc_rechargetime(ship.generator.capacity, ship.energy, ship.generator.recharge)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function calc_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
|
|
133
|
+
return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?: number): UInt32 {
|
|
137
|
+
const z = altitude ?? ship.coordinates.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
|
|
138
|
+
return calc_flighttime(z, calc_loader_acceleration(ship, mass))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
|
|
142
|
+
return calc_acceleration(Number(ship.loaders.thrust), Number(mass) + Number(ship.loaders.mass))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
|
|
146
|
+
const acceleration = calc_ship_acceleration(ship, mass)
|
|
147
|
+
return calc_flighttime(distance, acceleration)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
|
|
151
|
+
return calc_acceleration(Number(ship.engines.thrust), Number(mass))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function calc_acceleration(thrust: number, mass: number): number {
|
|
155
|
+
return (thrust / mass) * PRECISION
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64 {
|
|
159
|
+
const mass = UInt64.from(0)
|
|
160
|
+
|
|
161
|
+
mass.add(ship.hullmass)
|
|
162
|
+
|
|
163
|
+
if (ship.loaders.quantity.gt(UInt32.zero)) {
|
|
164
|
+
mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const cargo of cargos) {
|
|
168
|
+
mass.add(getGood(cargo.good_id).mass.multiplying(cargo.quantity))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return mass
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function calc_energyusage(distance: UInt64Type, drain: UInt32Type): UInt32 {
|
|
175
|
+
return UInt64.from(distance).dividing(PRECISION).multiplying(drain)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function calculateTransferTime(
|
|
179
|
+
ship: ShipLike,
|
|
180
|
+
cargos: CargoMassInfo[],
|
|
181
|
+
quantities?: Map<number, number>
|
|
182
|
+
): UInt32 {
|
|
183
|
+
let mass = UInt64.from(0)
|
|
184
|
+
|
|
185
|
+
for (const cargo of cargos) {
|
|
186
|
+
const qty = quantities?.get(Number(cargo.good_id)) ?? 0
|
|
187
|
+
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)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (mass.equals(UInt64.zero)) {
|
|
195
|
+
return UInt32.from(0)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
mass = UInt64.from(mass).adding(ship.loaders.mass)
|
|
199
|
+
const transfer_time = calc_loader_flighttime(ship, mass)
|
|
200
|
+
return transfer_time.dividing(ship.loaders.quantity)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function calculateRefuelingTime(ship: ShipLike): UInt32 {
|
|
204
|
+
return calc_ship_rechargetime(ship)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function calculateFlightTime(
|
|
208
|
+
ship: ShipLike,
|
|
209
|
+
cargos: CargoMassInfo[],
|
|
210
|
+
distance: UInt64Type
|
|
211
|
+
): UInt32 {
|
|
212
|
+
const mass = calc_ship_mass(ship, cargos)
|
|
213
|
+
return calc_ship_flighttime(ship, mass, distance)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface LoadTimeBreakdown {
|
|
217
|
+
unloadTime: number
|
|
218
|
+
loadTime: number
|
|
219
|
+
totalTime: number
|
|
220
|
+
unloadMass: number
|
|
221
|
+
loadMass: number
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function calculateLoadTimeBreakdown(
|
|
225
|
+
ship: ShipLike,
|
|
226
|
+
cargos: CargoMassInfo[],
|
|
227
|
+
loadQuantities?: Map<number, number>,
|
|
228
|
+
unloadQuantities?: Map<number, number>
|
|
229
|
+
): LoadTimeBreakdown {
|
|
230
|
+
let mass_unload = UInt64.from(0)
|
|
231
|
+
let mass_load = UInt64.from(0)
|
|
232
|
+
|
|
233
|
+
for (const cargo of cargos) {
|
|
234
|
+
const goodId = Number(cargo.good_id)
|
|
235
|
+
const loadQty = loadQuantities?.get(goodId) ?? 0
|
|
236
|
+
const unloadQty = unloadQuantities?.get(goodId) ?? 0
|
|
237
|
+
|
|
238
|
+
if (loadQty > 0 || unloadQty > 0) {
|
|
239
|
+
const good = getGood(cargo.good_id)
|
|
240
|
+
|
|
241
|
+
if (loadQty > 0) {
|
|
242
|
+
const cargo_mass = good.mass.multiplying(loadQty)
|
|
243
|
+
mass_load = UInt64.from(mass_load).adding(cargo_mass)
|
|
244
|
+
}
|
|
245
|
+
if (unloadQty > 0) {
|
|
246
|
+
const cargo_mass = good.mass.multiplying(unloadQty)
|
|
247
|
+
mass_unload = UInt64.from(mass_unload).adding(cargo_mass)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let unloadTime = 0
|
|
253
|
+
let loadTime = 0
|
|
254
|
+
|
|
255
|
+
if (mass_unload.gt(UInt64.zero)) {
|
|
256
|
+
const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
|
|
257
|
+
unloadTime = Number(calc_loader_flighttime(ship, totalMass))
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (mass_load.gt(UInt64.zero)) {
|
|
261
|
+
const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
|
|
262
|
+
loadTime = Number(calc_loader_flighttime(ship, totalMass))
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const numLoaders = Number(ship.loaders.quantity)
|
|
266
|
+
const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
|
|
267
|
+
const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
|
|
268
|
+
const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
unloadTime: unloadTimePerLoader,
|
|
272
|
+
loadTime: loadTimePerLoader,
|
|
273
|
+
totalTime,
|
|
274
|
+
unloadMass: Number(mass_unload),
|
|
275
|
+
loadMass: Number(mass_load),
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface EstimatedTravelTime {
|
|
280
|
+
flightTime: UInt32
|
|
281
|
+
rechargeTime: UInt32
|
|
282
|
+
loadTime: UInt32
|
|
283
|
+
unloadTime: UInt32
|
|
284
|
+
total: UInt32
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface EstimateTravelTimeOptions {
|
|
288
|
+
needsRecharge?: boolean
|
|
289
|
+
loadMass?: UInt32Type
|
|
290
|
+
unloadMass?: UInt32Type
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function estimateTravelTime(
|
|
294
|
+
ship: ShipLike,
|
|
295
|
+
travelMass: UInt64Type,
|
|
296
|
+
distance: UInt64Type,
|
|
297
|
+
options: EstimateTravelTimeOptions = {}
|
|
298
|
+
): EstimatedTravelTime {
|
|
299
|
+
const {needsRecharge = false, loadMass, unloadMass} = options
|
|
300
|
+
|
|
301
|
+
const flightTime = calc_ship_flighttime(ship, UInt64.from(travelMass), UInt64.from(distance))
|
|
302
|
+
const rechargeTime = needsRecharge ? calc_ship_rechargetime(ship) : UInt32.zero
|
|
303
|
+
|
|
304
|
+
let loadTime = UInt32.zero
|
|
305
|
+
let unloadTime = UInt32.zero
|
|
306
|
+
|
|
307
|
+
if (
|
|
308
|
+
loadMass &&
|
|
309
|
+
UInt32.from(loadMass).gt(UInt32.zero) &&
|
|
310
|
+
ship.loaders.quantity.gt(UInt32.zero)
|
|
311
|
+
) {
|
|
312
|
+
const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
|
|
313
|
+
loadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (
|
|
317
|
+
unloadMass &&
|
|
318
|
+
UInt32.from(unloadMass).gt(UInt32.zero) &&
|
|
319
|
+
ship.loaders.quantity.gt(UInt32.zero)
|
|
320
|
+
) {
|
|
321
|
+
const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
|
|
322
|
+
unloadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
flightTime,
|
|
327
|
+
rechargeTime,
|
|
328
|
+
loadTime,
|
|
329
|
+
unloadTime,
|
|
330
|
+
total: flightTime.adding(rechargeTime).adding(loadTime).adding(unloadTime),
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export function estimateDealTravelTime(
|
|
335
|
+
ship: ShipLike,
|
|
336
|
+
shipMass: UInt64Type,
|
|
337
|
+
distance: UInt64Type,
|
|
338
|
+
loadMass: UInt32Type
|
|
339
|
+
): UInt32 {
|
|
340
|
+
const needsRecharge = !hasEnergyForDistance(ship, distance)
|
|
341
|
+
const estimate = estimateTravelTime(ship, shipMass, distance, {
|
|
342
|
+
needsRecharge,
|
|
343
|
+
loadMass,
|
|
344
|
+
})
|
|
345
|
+
return estimate.total
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): boolean {
|
|
349
|
+
const energyNeeded = UInt64.from(distance).dividing(PRECISION).multiplying(ship.engines.drain)
|
|
350
|
+
return UInt64.from(ship.energy).gte(energyNeeded)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export interface TransferEntity {
|
|
354
|
+
location: {z?: {toNumber(): number} | number}
|
|
355
|
+
loaders?: {
|
|
356
|
+
thrust: {toNumber(): number} | number
|
|
357
|
+
mass: {toNumber(): number} | number
|
|
358
|
+
quantity: {toNumber(): number} | number
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export interface HasScheduleAndLocation {
|
|
363
|
+
coordinates: ServerContract.ActionParams.Type.coordinates
|
|
364
|
+
schedule?: ServerContract.Types.schedule
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function getFlightOrigin(
|
|
368
|
+
entity: HasScheduleAndLocation,
|
|
369
|
+
flightTaskIndex: number
|
|
370
|
+
): ServerContract.ActionParams.Type.coordinates {
|
|
371
|
+
if (!entity.schedule) return entity.coordinates
|
|
372
|
+
|
|
373
|
+
let origin = entity.coordinates
|
|
374
|
+
for (let i = 0; i < flightTaskIndex && i < entity.schedule.tasks.length; i++) {
|
|
375
|
+
const task = entity.schedule.tasks[i]
|
|
376
|
+
if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
|
|
377
|
+
origin = task.coordinates
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return origin
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export function getDestinationLocation(
|
|
384
|
+
entity: HasScheduleAndLocation
|
|
385
|
+
): ServerContract.ActionParams.Type.coordinates | undefined {
|
|
386
|
+
if (!entity.schedule) return undefined
|
|
387
|
+
|
|
388
|
+
for (let i = entity.schedule.tasks.length - 1; i >= 0; i--) {
|
|
389
|
+
const task = entity.schedule.tasks[i]
|
|
390
|
+
if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
|
|
391
|
+
return task.coordinates
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return undefined
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export function getPositionAt(
|
|
398
|
+
entity: HasScheduleAndLocation,
|
|
399
|
+
taskIndex: number,
|
|
400
|
+
taskProgress: number
|
|
401
|
+
): ServerContract.ActionParams.Type.coordinates {
|
|
402
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0 || taskIndex < 0) {
|
|
403
|
+
return entity.coordinates
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const task = entity.schedule.tasks[taskIndex]
|
|
407
|
+
|
|
408
|
+
if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
|
|
409
|
+
return getFlightOrigin(entity, taskIndex)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const origin = getFlightOrigin(entity, taskIndex)
|
|
413
|
+
const destination = task.coordinates
|
|
414
|
+
|
|
415
|
+
const interpolated = lerp(origin, destination, taskProgress)
|
|
416
|
+
return {
|
|
417
|
+
x: Math.round(interpolated.x),
|
|
418
|
+
y: Math.round(interpolated.y),
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function calc_transfer_duration(
|
|
423
|
+
source: TransferEntity,
|
|
424
|
+
dest: TransferEntity,
|
|
425
|
+
cargoMass: number
|
|
426
|
+
): number {
|
|
427
|
+
if (cargoMass === 0) {
|
|
428
|
+
return 0
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
let totalThrust = 0
|
|
432
|
+
let totalLoaderMass = 0
|
|
433
|
+
let totalQuantity = 0
|
|
434
|
+
|
|
435
|
+
if (source.loaders) {
|
|
436
|
+
const thrust =
|
|
437
|
+
typeof source.loaders.thrust === 'number'
|
|
438
|
+
? source.loaders.thrust
|
|
439
|
+
: source.loaders.thrust.toNumber()
|
|
440
|
+
const mass =
|
|
441
|
+
typeof source.loaders.mass === 'number'
|
|
442
|
+
? source.loaders.mass
|
|
443
|
+
: source.loaders.mass.toNumber()
|
|
444
|
+
const qty =
|
|
445
|
+
typeof source.loaders.quantity === 'number'
|
|
446
|
+
? source.loaders.quantity
|
|
447
|
+
: source.loaders.quantity.toNumber()
|
|
448
|
+
totalThrust += thrust * qty
|
|
449
|
+
totalLoaderMass += mass * qty
|
|
450
|
+
totalQuantity += qty
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (dest.loaders) {
|
|
454
|
+
const thrust =
|
|
455
|
+
typeof dest.loaders.thrust === 'number'
|
|
456
|
+
? dest.loaders.thrust
|
|
457
|
+
: dest.loaders.thrust.toNumber()
|
|
458
|
+
const mass =
|
|
459
|
+
typeof dest.loaders.mass === 'number' ? dest.loaders.mass : dest.loaders.mass.toNumber()
|
|
460
|
+
const qty =
|
|
461
|
+
typeof dest.loaders.quantity === 'number'
|
|
462
|
+
? dest.loaders.quantity
|
|
463
|
+
: dest.loaders.quantity.toNumber()
|
|
464
|
+
totalThrust += thrust * qty
|
|
465
|
+
totalLoaderMass += mass * qty
|
|
466
|
+
totalQuantity += qty
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (totalThrust === 0 || totalQuantity === 0) {
|
|
470
|
+
return 0
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const sourceZ =
|
|
474
|
+
typeof source.location.z === 'number'
|
|
475
|
+
? source.location.z
|
|
476
|
+
: source.location.z?.toNumber() ?? 0
|
|
477
|
+
const destZ =
|
|
478
|
+
typeof dest.location.z === 'number' ? dest.location.z : dest.location.z?.toNumber() ?? 0
|
|
479
|
+
const distance = Math.abs(sourceZ - destZ)
|
|
480
|
+
|
|
481
|
+
const totalMass = cargoMass + totalLoaderMass
|
|
482
|
+
const acceleration = calc_acceleration(totalThrust, totalMass)
|
|
483
|
+
const flightTime = 2 * Math.sqrt(distance / acceleration)
|
|
484
|
+
|
|
485
|
+
return Math.floor(flightTime / totalQuantity)
|
|
486
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {Name, UInt16, UInt32} from '@wharfkit/antelope'
|
|
2
|
+
import {ServerContract} from '../contracts'
|
|
3
|
+
|
|
4
|
+
export interface MovementCapability {
|
|
5
|
+
engines: ServerContract.Types.movement_stats
|
|
6
|
+
generator: ServerContract.Types.energy_stats
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface EnergyCapability {
|
|
10
|
+
energy: UInt16
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface StorageCapability {
|
|
14
|
+
capacity: UInt32
|
|
15
|
+
cargomass: UInt32
|
|
16
|
+
cargo: ServerContract.Types.cargo_item[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface LoaderCapability {
|
|
20
|
+
loaders: ServerContract.Types.loader_stats
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TradeCapability {
|
|
24
|
+
trade: ServerContract.Types.trade_stats
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ExtractorCapability {
|
|
28
|
+
extractor: ServerContract.Types.extractor_stats
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MassCapability {
|
|
32
|
+
hullmass: UInt32
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ScheduleCapability {
|
|
36
|
+
schedule?: ServerContract.Types.schedule
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface EntityCapabilities {
|
|
40
|
+
hullmass?: UInt32
|
|
41
|
+
capacity?: UInt32
|
|
42
|
+
engines?: ServerContract.Types.movement_stats
|
|
43
|
+
generator?: ServerContract.Types.energy_stats
|
|
44
|
+
loaders?: ServerContract.Types.loader_stats
|
|
45
|
+
trade?: ServerContract.Types.trade_stats
|
|
46
|
+
extractor?: ServerContract.Types.extractor_stats
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface EntityState {
|
|
50
|
+
owner: Name
|
|
51
|
+
location: ServerContract.Types.coordinates
|
|
52
|
+
energy?: UInt16
|
|
53
|
+
cargomass: UInt32
|
|
54
|
+
cargo: ServerContract.Types.cargo_item[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function capsHasMovement(caps: EntityCapabilities): boolean {
|
|
58
|
+
return caps.engines !== undefined && caps.generator !== undefined
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function capsHasStorage(caps: EntityCapabilities): boolean {
|
|
62
|
+
return caps.capacity !== undefined
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function capsHasLoaders(caps: EntityCapabilities): boolean {
|
|
66
|
+
return caps.loaders !== undefined
|
|
67
|
+
}
|
|
68
|
+
|
|
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
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function capsHasMass(caps: EntityCapabilities): boolean {
|
|
78
|
+
return caps.hullmass !== undefined
|
|
79
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {Name} from '@wharfkit/antelope'
|
|
2
|
+
|
|
3
|
+
export const ENTITY_SHIP = Name.from('ship')
|
|
4
|
+
export const ENTITY_WAREHOUSE = Name.from('warehouse')
|
|
5
|
+
export const ENTITY_CONTAINER = Name.from('container')
|
|
6
|
+
|
|
7
|
+
export type EntityTypeName = 'ship' | 'warehouse' | 'container'
|
|
8
|
+
|
|
9
|
+
export interface EntityTraits {
|
|
10
|
+
typeName: Name
|
|
11
|
+
isMovable: boolean
|
|
12
|
+
hasEnergy: boolean
|
|
13
|
+
hasLoaders: boolean
|
|
14
|
+
hasTrade: boolean
|
|
15
|
+
notFoundError: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const shipTraits: EntityTraits = {
|
|
19
|
+
typeName: ENTITY_SHIP,
|
|
20
|
+
isMovable: true,
|
|
21
|
+
hasEnergy: true,
|
|
22
|
+
hasLoaders: true,
|
|
23
|
+
hasTrade: true,
|
|
24
|
+
notFoundError: 'ship not found',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const warehouseTraits: EntityTraits = {
|
|
28
|
+
typeName: ENTITY_WAREHOUSE,
|
|
29
|
+
isMovable: false,
|
|
30
|
+
hasEnergy: false,
|
|
31
|
+
hasLoaders: true,
|
|
32
|
+
hasTrade: false,
|
|
33
|
+
notFoundError: 'warehouse not found',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const containerTraits: EntityTraits = {
|
|
37
|
+
typeName: ENTITY_CONTAINER,
|
|
38
|
+
isMovable: true,
|
|
39
|
+
hasEnergy: false,
|
|
40
|
+
hasLoaders: false,
|
|
41
|
+
hasTrade: false,
|
|
42
|
+
notFoundError: 'container not found',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getEntityTraits(entityType: Name | EntityTypeName): EntityTraits {
|
|
46
|
+
const typeName = typeof entityType === 'string' ? entityType : entityType.toString()
|
|
47
|
+
|
|
48
|
+
switch (typeName) {
|
|
49
|
+
case 'ship':
|
|
50
|
+
return shipTraits
|
|
51
|
+
case 'warehouse':
|
|
52
|
+
return warehouseTraits
|
|
53
|
+
case 'container':
|
|
54
|
+
return containerTraits
|
|
55
|
+
default:
|
|
56
|
+
throw new Error(`Unknown entity type: ${typeName}`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isShip(entity: {type?: Name}): boolean {
|
|
61
|
+
return entity.type?.equals(ENTITY_SHIP) ?? false
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isWarehouse(entity: {type?: Name}): boolean {
|
|
65
|
+
return entity.type?.equals(ENTITY_WAREHOUSE) ?? false
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isContainer(entity: {type?: Name}): boolean {
|
|
69
|
+
return entity.type?.equals(ENTITY_CONTAINER) ?? false
|
|
70
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {Name, UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import {ServerContract} from '../contracts'
|
|
3
|
+
import {Coordinates} from '../types'
|
|
4
|
+
import {
|
|
5
|
+
EnergyCapability,
|
|
6
|
+
LoaderCapability,
|
|
7
|
+
MassCapability,
|
|
8
|
+
MovementCapability,
|
|
9
|
+
ScheduleCapability,
|
|
10
|
+
StorageCapability,
|
|
11
|
+
} from './capabilities'
|
|
12
|
+
|
|
13
|
+
export interface Entity {
|
|
14
|
+
id: UInt64
|
|
15
|
+
type: Name
|
|
16
|
+
owner: Name
|
|
17
|
+
entity_name: string
|
|
18
|
+
location: Coordinates | ServerContract.Types.coordinates
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ShipEntity = Entity &
|
|
22
|
+
MovementCapability &
|
|
23
|
+
EnergyCapability &
|
|
24
|
+
StorageCapability &
|
|
25
|
+
LoaderCapability &
|
|
26
|
+
MassCapability &
|
|
27
|
+
ScheduleCapability & {
|
|
28
|
+
trade?: ServerContract.Types.trade_stats
|
|
29
|
+
extractor?: ServerContract.Types.extractor_stats
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type WarehouseEntity = Entity & StorageCapability & LoaderCapability & ScheduleCapability
|
|
33
|
+
|
|
34
|
+
export type ContainerEntity = Entity & StorageCapability & MassCapability & ScheduleCapability
|
|
35
|
+
|
|
36
|
+
export type AnyEntity = ShipEntity | WarehouseEntity | ContainerEntity
|