@shipload/sdk 2.0.0-rc1 → 2.0.0-rc3
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 +809 -314
- package/lib/shipload.js +2745 -1740
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2158 -1154
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -2
- package/src/capabilities/extraction.ts +30 -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 +506 -183
- package/src/data/items.json +16 -0
- package/src/derivation/index.ts +25 -0
- package/src/derivation/location-size.ts +15 -0
- package/src/derivation/resources.ts +141 -0
- package/src/derivation/stratum.ts +116 -0
- package/src/entities/cargo-utils.ts +98 -3
- package/src/entities/container.ts +70 -0
- package/src/entities/entity-inventory.ts +13 -9
- package/src/entities/inventory-accessor.ts +46 -0
- package/src/entities/location.ts +31 -17
- package/src/entities/makers.ts +69 -0
- package/src/entities/player.ts +2 -1
- package/src/entities/ship.ts +93 -440
- package/src/entities/warehouse.ts +29 -145
- package/src/errors.ts +4 -4
- package/src/index-module.ts +62 -4
- package/src/managers/actions.ts +75 -31
- package/src/managers/entities.ts +22 -5
- package/src/managers/locations.ts +34 -15
- package/src/managers/trades.ts +7 -7
- package/src/market/items.ts +31 -0
- package/src/market/market.ts +12 -13
- package/src/scheduling/accessor.ts +82 -0
- package/src/scheduling/projection.ts +126 -54
- package/src/scheduling/schedule.ts +24 -0
- package/src/trading/collect.ts +25 -26
- package/src/trading/deal.ts +8 -9
- package/src/trading/trade.ts +9 -9
- package/src/travel/travel.ts +69 -8
- 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 +92 -15
- package/src/utils/hash.ts +1 -1
- package/src/utils/system.ts +97 -4
- package/src/data/goods.json +0 -23
- package/src/market/goods.ts +0 -31
|
@@ -1,46 +1,47 @@
|
|
|
1
|
-
import {Bytes, Checksum256, UInt16Type, UInt64} from '@wharfkit/antelope'
|
|
1
|
+
import {Bytes, Checksum256, UInt16Type, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
2
2
|
import {BaseManager} from './base'
|
|
3
|
-
import {CoordinatesType, Distance,
|
|
3
|
+
import {CoordinatesType, coordsToLocationId, Distance, ItemPrice} from '../types'
|
|
4
4
|
import {marketPrice, marketPrices} from '../market/market'
|
|
5
5
|
import {hasSystem} from '../utils/system'
|
|
6
6
|
import {findNearbyPlanets} from '../travel/travel'
|
|
7
7
|
import {Location, toLocation} from '../entities/location'
|
|
8
|
+
import {ServerContract} from '../contracts'
|
|
8
9
|
|
|
9
10
|
export class LocationsManager extends BaseManager {
|
|
10
|
-
async getMarketPrice(location: CoordinatesType, goodId: number): Promise<
|
|
11
|
+
async getMarketPrice(location: CoordinatesType, goodId: number): Promise<ItemPrice> {
|
|
11
12
|
const game = await this.getGame()
|
|
12
13
|
const state = await this.getState()
|
|
13
14
|
return marketPrice(location, goodId, game.config.seed, state)
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
async getMarketPrices(location: CoordinatesType): Promise<
|
|
17
|
+
async getMarketPrices(location: CoordinatesType): Promise<ItemPrice[]> {
|
|
17
18
|
const game = await this.getGame()
|
|
18
19
|
const state = await this.getState()
|
|
19
20
|
return marketPrices(location, game.config.seed, state)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
async getMarketPricesWithSupply(location: CoordinatesType): Promise<
|
|
23
|
-
const [game, state,
|
|
23
|
+
async getMarketPricesWithSupply(location: CoordinatesType): Promise<ItemPrice[]> {
|
|
24
|
+
const [game, state, supplyRows] = await Promise.all([
|
|
24
25
|
this.getGame(),
|
|
25
26
|
this.getState(),
|
|
26
|
-
this.
|
|
27
|
+
this.getSupplyRows(location),
|
|
27
28
|
])
|
|
28
29
|
|
|
29
30
|
const prices = marketPrices(location, game.config.seed, state)
|
|
30
31
|
|
|
31
32
|
const supplyMap = new Map<number, number>()
|
|
32
|
-
for (const row of
|
|
33
|
+
for (const row of supplyRows) {
|
|
33
34
|
if (UInt64.from(row.epoch).equals(state.epoch)) {
|
|
34
|
-
supplyMap.set(Number(row.
|
|
35
|
+
supplyMap.set(Number(row.item_id), Number(row.supply))
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
return prices.map((price) => {
|
|
39
40
|
const actualSupply = supplyMap.get(Number(price.id))
|
|
40
41
|
if (actualSupply !== undefined) {
|
|
41
|
-
return
|
|
42
|
+
return ItemPrice.from({
|
|
42
43
|
id: price.id,
|
|
43
|
-
|
|
44
|
+
item: price.item,
|
|
44
45
|
price: price.price,
|
|
45
46
|
supply: UInt64.from(actualSupply),
|
|
46
47
|
})
|
|
@@ -62,9 +63,9 @@ export class LocationsManager extends BaseManager {
|
|
|
62
63
|
return findNearbyPlanets(game.config.seed, origin, maxDistance)
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
async
|
|
66
|
+
async getSupplyRows(location: CoordinatesType) {
|
|
66
67
|
const hash = Checksum256.hash(Bytes.from(`${location.x}-${location.y}`, 'utf8'))
|
|
67
|
-
return this.server.table('
|
|
68
|
+
return this.server.table('supply').all({
|
|
68
69
|
index_position: 'secondary',
|
|
69
70
|
from: hash,
|
|
70
71
|
to: hash,
|
|
@@ -81,7 +82,7 @@ export class LocationsManager extends BaseManager {
|
|
|
81
82
|
async getLocationWithSupply(coords: CoordinatesType): Promise<Location> {
|
|
82
83
|
const location = toLocation(coords)
|
|
83
84
|
const [rows, state] = await Promise.all([
|
|
84
|
-
this.
|
|
85
|
+
this.getSupplyRows(location.coordinates),
|
|
85
86
|
this.getState(),
|
|
86
87
|
])
|
|
87
88
|
location.setLocationRows(rows, state.epoch)
|
|
@@ -92,7 +93,7 @@ export class LocationsManager extends BaseManager {
|
|
|
92
93
|
const location = toLocation(coords)
|
|
93
94
|
const [prices, rows, state] = await Promise.all([
|
|
94
95
|
this.getMarketPrices(location.coordinates),
|
|
95
|
-
this.
|
|
96
|
+
this.getSupplyRows(location.coordinates),
|
|
96
97
|
this.getState(),
|
|
97
98
|
])
|
|
98
99
|
|
|
@@ -100,4 +101,22 @@ export class LocationsManager extends BaseManager {
|
|
|
100
101
|
location.setLocationRows(rows, state.epoch)
|
|
101
102
|
return location
|
|
102
103
|
}
|
|
104
|
+
|
|
105
|
+
async getLocationEntity(
|
|
106
|
+
id: UInt64Type
|
|
107
|
+
): Promise<ServerContract.Types.location_row | undefined> {
|
|
108
|
+
const row = await this.server.table('location').get(UInt64.from(id))
|
|
109
|
+
return row ?? undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async getLocationEntityAt(
|
|
113
|
+
coords: CoordinatesType
|
|
114
|
+
): Promise<ServerContract.Types.location_row | undefined> {
|
|
115
|
+
const id = coordsToLocationId(coords)
|
|
116
|
+
return this.getLocationEntity(id)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getAllLocationEntities(): Promise<ServerContract.Types.location_row[]> {
|
|
120
|
+
return this.server.table('location').all()
|
|
121
|
+
}
|
|
103
122
|
}
|
package/src/managers/trades.ts
CHANGED
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
CollectAnalysisCallbacks,
|
|
9
9
|
CollectAnalysisOptions,
|
|
10
10
|
} from '../trading/collect'
|
|
11
|
-
import {Coordinates,
|
|
11
|
+
import {Coordinates, ItemPrice} from '../types'
|
|
12
12
|
import {Location, toLocation} from '../entities/location'
|
|
13
13
|
import {findNearbyPlanets} from '../travel/travel'
|
|
14
14
|
import {getCurrentEpoch} from '../scheduling/epoch'
|
|
15
15
|
|
|
16
16
|
export class TradesManager extends BaseManager {
|
|
17
|
-
private priceCache = new Map<string,
|
|
17
|
+
private priceCache = new Map<string, ItemPrice[]>()
|
|
18
18
|
private priceCacheEpoch: UInt64 | undefined
|
|
19
19
|
|
|
20
20
|
private makePriceCacheKey(location: Coordinates): string {
|
|
@@ -39,7 +39,7 @@ export class TradesManager extends BaseManager {
|
|
|
39
39
|
return nearby.map((d) => toLocation(d.destination))
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const getMarketPrices = async (location: Coordinates): Promise<
|
|
42
|
+
const getMarketPrices = async (location: Coordinates): Promise<ItemPrice[]> => {
|
|
43
43
|
const cacheKey = this.makePriceCacheKey(location)
|
|
44
44
|
const cached = this.priceCache.get(cacheKey)
|
|
45
45
|
if (cached) {
|
|
@@ -53,9 +53,9 @@ export class TradesManager extends BaseManager {
|
|
|
53
53
|
const actualSupply = locationWithSupply.getSupply(price.id)
|
|
54
54
|
|
|
55
55
|
if (actualSupply !== undefined) {
|
|
56
|
-
return
|
|
56
|
+
return ItemPrice.from({
|
|
57
57
|
id: price.id,
|
|
58
|
-
|
|
58
|
+
item: price.item,
|
|
59
59
|
price: price.price,
|
|
60
60
|
supply: actualSupply,
|
|
61
61
|
})
|
|
@@ -83,7 +83,7 @@ export class TradesManager extends BaseManager {
|
|
|
83
83
|
originLocation?: Coordinates,
|
|
84
84
|
options: FindDealsOptions = {}
|
|
85
85
|
): Promise<Deal[]> {
|
|
86
|
-
const origin = originLocation || ship.
|
|
86
|
+
const origin = originLocation || Coordinates.from(ship.coordinates)
|
|
87
87
|
const callbacks = await this.createCallbacks()
|
|
88
88
|
|
|
89
89
|
const deals = await findDealsForShip(
|
|
@@ -111,7 +111,7 @@ export class TradesManager extends BaseManager {
|
|
|
111
111
|
arrivedAt?: Coordinates,
|
|
112
112
|
options: CollectAnalysisOptions = {}
|
|
113
113
|
): Promise<CollectAnalysis> {
|
|
114
|
-
const location = arrivedAt || ship.
|
|
114
|
+
const location = arrivedAt || Coordinates.from(ship.coordinates)
|
|
115
115
|
const callbacks = await this.createCallbacks()
|
|
116
116
|
|
|
117
117
|
return analyzeCollectOptions(ship, location, callbacks, options)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {UInt16, UInt16Type} from '@wharfkit/antelope'
|
|
2
|
+
import {Item} from '../types'
|
|
3
|
+
import itemsData from '../data/items.json'
|
|
4
|
+
|
|
5
|
+
const items: Item[] = itemsData.map((g) =>
|
|
6
|
+
Item.from({
|
|
7
|
+
id: g.id,
|
|
8
|
+
name: g.name,
|
|
9
|
+
description: g.description,
|
|
10
|
+
base_price: g.base_price,
|
|
11
|
+
mass: g.mass,
|
|
12
|
+
category: g.category,
|
|
13
|
+
rarity: g.rarity,
|
|
14
|
+
color: g.color,
|
|
15
|
+
})
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
export const itemIds = items.map((i) => i.id)
|
|
19
|
+
|
|
20
|
+
export function getItem(itemId: UInt16Type): Item {
|
|
21
|
+
const id = UInt16.from(itemId)
|
|
22
|
+
const item = items.find((i) => i.id.equals(id))
|
|
23
|
+
if (!item) {
|
|
24
|
+
throw new Error(`Item with id ${id} not found`)
|
|
25
|
+
}
|
|
26
|
+
return item
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getItems(): Item[] {
|
|
30
|
+
return items
|
|
31
|
+
}
|
package/src/market/market.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {CoordinatesType,
|
|
2
|
-
import {
|
|
1
|
+
import {CoordinatesType, ItemPrice} from '../types'
|
|
2
|
+
import {getItem, getItems} from './items'
|
|
3
3
|
import {Checksum256Type, UInt16, UInt16Type, UInt32} from '@wharfkit/antelope'
|
|
4
4
|
import {roll} from './rolls'
|
|
5
5
|
import {ServerContract} from '../contracts'
|
|
@@ -163,11 +163,10 @@ export function getSupply(
|
|
|
163
163
|
const r = roll(gameSeed, seed)
|
|
164
164
|
const percent = r / 65535
|
|
165
165
|
const epoch = 1 + Number(state.epoch) / 90
|
|
166
|
-
|
|
167
|
-
// TODO: Update this when contract is fixed to use (double)1/(double)3
|
|
168
|
-
const ship = Math.pow(Number(state.ships), 0)
|
|
166
|
+
const ship = 1
|
|
169
167
|
const goodIdNum = Number(goodId)
|
|
170
|
-
|
|
168
|
+
const base = Math.floor(128 / goodIdNum)
|
|
169
|
+
return Math.floor(base * percent * ship * epoch)
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
export function marketPrice(
|
|
@@ -175,9 +174,9 @@ export function marketPrice(
|
|
|
175
174
|
goodId: UInt16Type,
|
|
176
175
|
gameSeed: Checksum256Type,
|
|
177
176
|
state: ServerContract.Types.state_row
|
|
178
|
-
):
|
|
179
|
-
const
|
|
180
|
-
let price = Number(
|
|
177
|
+
): ItemPrice {
|
|
178
|
+
const item = getItem(goodId)
|
|
179
|
+
let price = Number(item.base_price)
|
|
181
180
|
|
|
182
181
|
// Rarity multiplier of the deal (changes with epoch)
|
|
183
182
|
// Large impact range on price, from 0.285x to 3.0x
|
|
@@ -192,9 +191,9 @@ export function marketPrice(
|
|
|
192
191
|
// Determine the current supply of the good at the location
|
|
193
192
|
const supply = getSupply(gameSeed, state, location, goodId)
|
|
194
193
|
|
|
195
|
-
return
|
|
194
|
+
return ItemPrice.from({
|
|
196
195
|
id: goodId,
|
|
197
|
-
|
|
196
|
+
item,
|
|
198
197
|
price: UInt32.from(price),
|
|
199
198
|
supply: UInt16.from(supply),
|
|
200
199
|
})
|
|
@@ -204,6 +203,6 @@ export function marketPrices(
|
|
|
204
203
|
location: ServerContract.ActionParams.Type.coordinates,
|
|
205
204
|
gameSeed: Checksum256Type,
|
|
206
205
|
state: ServerContract.Types.state_row
|
|
207
|
-
):
|
|
208
|
-
return
|
|
206
|
+
): ItemPrice[] {
|
|
207
|
+
return getItems().map((item) => marketPrice(location, item.id, gameSeed, state))
|
|
209
208
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {ServerContract} from '../contracts'
|
|
2
|
+
import {TaskType} from '../types'
|
|
3
|
+
import {ScheduleData} from './schedule'
|
|
4
|
+
import * as schedule from './schedule'
|
|
5
|
+
|
|
6
|
+
type Task = ServerContract.Types.task
|
|
7
|
+
|
|
8
|
+
export class ScheduleAccessor {
|
|
9
|
+
constructor(private entity: ScheduleData) {}
|
|
10
|
+
|
|
11
|
+
get hasSchedule(): boolean {
|
|
12
|
+
return schedule.hasSchedule(this.entity)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get isIdle(): boolean {
|
|
16
|
+
return schedule.isIdle(this.entity)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get tasks(): Task[] {
|
|
20
|
+
return schedule.getTasks(this.entity)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
duration(): number {
|
|
24
|
+
return schedule.scheduleDuration(this.entity)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
elapsed(now: Date): number {
|
|
28
|
+
return schedule.scheduleElapsed(this.entity, now)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
remaining(now: Date): number {
|
|
32
|
+
return schedule.scheduleRemaining(this.entity, now)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
complete(now: Date): boolean {
|
|
36
|
+
return schedule.scheduleComplete(this.entity, now)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
currentTaskIndex(now: Date): number {
|
|
40
|
+
return schedule.currentTaskIndex(this.entity, now)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
currentTask(now: Date): Task | undefined {
|
|
44
|
+
return schedule.currentTask(this.entity, now)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
currentTaskType(now: Date): TaskType | undefined {
|
|
48
|
+
return schedule.currentTaskType(this.entity, now)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
taskStartTime(index: number): number {
|
|
52
|
+
return schedule.getTaskStartTime(this.entity, index)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
taskElapsed(index: number, now: Date): number {
|
|
56
|
+
return schedule.getTaskElapsed(this.entity, index, now)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
taskRemaining(index: number, now: Date): number {
|
|
60
|
+
return schedule.getTaskRemaining(this.entity, index, now)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
taskComplete(index: number, now: Date): boolean {
|
|
64
|
+
return schedule.isTaskComplete(this.entity, index, now)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
taskInProgress(index: number, now: Date): boolean {
|
|
68
|
+
return schedule.isTaskInProgress(this.entity, index, now)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
currentTaskProgress(now: Date): number {
|
|
72
|
+
return schedule.currentTaskProgress(this.entity, now)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
progress(now: Date): number {
|
|
76
|
+
return schedule.scheduleProgress(this.entity, now)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createScheduleAccessor(entity: ScheduleData): ScheduleAccessor {
|
|
81
|
+
return new ScheduleAccessor(entity)
|
|
82
|
+
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import {UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
1
|
+
import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
3
|
import {Coordinates, PRECISION, TaskType} from '../types'
|
|
4
|
+
import {
|
|
5
|
+
capsHasLoaders,
|
|
6
|
+
capsHasMovement,
|
|
7
|
+
capsHasStorage,
|
|
8
|
+
EntityCapabilities,
|
|
9
|
+
EntityState,
|
|
10
|
+
} from '../types/capabilities'
|
|
4
11
|
import {distanceBetweenCoordinates, lerp} from '../travel/travel'
|
|
5
|
-
import {
|
|
12
|
+
import {calcCargoMass} from '../capabilities/storage'
|
|
13
|
+
import {getItem} from '../market/items'
|
|
6
14
|
import * as schedule from './schedule'
|
|
7
15
|
import {ScheduleData} from './schedule'
|
|
8
16
|
|
|
9
|
-
/**
|
|
10
|
-
* Projected state of an entity after scheduled tasks complete.
|
|
11
|
-
* Mirrors contract's projected_entity struct.
|
|
12
|
-
*/
|
|
13
17
|
export interface ProjectedEntity {
|
|
14
18
|
location: Coordinates
|
|
15
19
|
energy: UInt16
|
|
@@ -19,41 +23,56 @@ export interface ProjectedEntity {
|
|
|
19
23
|
engines?: ServerContract.Types.movement_stats
|
|
20
24
|
loaders?: ServerContract.Types.loader_stats
|
|
21
25
|
generator?: ServerContract.Types.energy_stats
|
|
26
|
+
trade?: ServerContract.Types.trade_stats
|
|
22
27
|
readonly totalMass: UInt64
|
|
28
|
+
|
|
29
|
+
hasMovement(): boolean
|
|
30
|
+
hasStorage(): boolean
|
|
31
|
+
hasLoaders(): boolean
|
|
32
|
+
hasTrade(): boolean
|
|
33
|
+
|
|
34
|
+
capabilities(): EntityCapabilities
|
|
35
|
+
state(): EntityState
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
/**
|
|
26
|
-
* Interface for entities that can be projected.
|
|
27
|
-
* Ships and Warehouses both implement this.
|
|
28
|
-
*/
|
|
29
38
|
export interface Projectable extends ScheduleData {
|
|
30
|
-
|
|
31
|
-
energy
|
|
32
|
-
|
|
39
|
+
coordinates: Coordinates | ServerContract.Types.coordinates
|
|
40
|
+
energy?: UInt16
|
|
41
|
+
hullmass?: UInt32
|
|
33
42
|
generator?: ServerContract.Types.energy_stats
|
|
34
43
|
engines?: ServerContract.Types.movement_stats
|
|
35
44
|
loaders?: ServerContract.Types.loader_stats
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
trade?: ServerContract.Types.trade_stats
|
|
46
|
+
capacity?: UInt32
|
|
47
|
+
cargo: ServerContract.Types.cargo_item[]
|
|
48
|
+
cargomass: UInt32
|
|
49
|
+
owner?: Name
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getHullMass(entity: Projectable): UInt32 {
|
|
53
|
+
return UInt32.from(entity.hullmass ?? 0)
|
|
38
54
|
}
|
|
39
55
|
|
|
40
|
-
/**
|
|
41
|
-
* Create initial projected entity state from a projectable entity.
|
|
42
|
-
*/
|
|
43
56
|
export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
44
|
-
const cargoMass =
|
|
45
|
-
const shipMass =
|
|
57
|
+
const cargoMass = calcCargoMass(entity)
|
|
58
|
+
const shipMass = getHullMass(entity)
|
|
46
59
|
const loaders = entity.loaders
|
|
60
|
+
const engines = entity.engines
|
|
61
|
+
const generator = entity.generator
|
|
62
|
+
const trade = entity.trade
|
|
63
|
+
const capacity = entity.capacity
|
|
47
64
|
|
|
48
|
-
|
|
49
|
-
location: Coordinates.from(entity.
|
|
50
|
-
energy: UInt16.from(entity.energy),
|
|
65
|
+
const projected: ProjectedEntity = {
|
|
66
|
+
location: Coordinates.from(entity.coordinates),
|
|
67
|
+
energy: UInt16.from(entity.energy ?? 0),
|
|
51
68
|
cargoMass,
|
|
52
69
|
shipMass,
|
|
53
|
-
capacity:
|
|
54
|
-
engines
|
|
55
|
-
generator
|
|
70
|
+
capacity: capacity ? UInt64.from(capacity) : undefined,
|
|
71
|
+
engines,
|
|
72
|
+
generator,
|
|
56
73
|
loaders,
|
|
74
|
+
trade,
|
|
75
|
+
|
|
57
76
|
get totalMass() {
|
|
58
77
|
let mass = UInt64.from(this.shipMass).adding(this.cargoMass)
|
|
59
78
|
if (this.loaders) {
|
|
@@ -61,12 +80,48 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
61
80
|
}
|
|
62
81
|
return mass
|
|
63
82
|
},
|
|
83
|
+
|
|
84
|
+
hasMovement() {
|
|
85
|
+
return capsHasMovement(this.capabilities())
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
hasStorage() {
|
|
89
|
+
return capsHasStorage(this.capabilities())
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
hasLoaders() {
|
|
93
|
+
return capsHasLoaders(this.capabilities())
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
hasTrade() {
|
|
97
|
+
return this.trade !== undefined
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
capabilities(): EntityCapabilities {
|
|
101
|
+
return {
|
|
102
|
+
hullmass: this.shipMass,
|
|
103
|
+
capacity: this.capacity ? UInt32.from(this.capacity) : undefined,
|
|
104
|
+
engines: this.engines,
|
|
105
|
+
generator: this.generator,
|
|
106
|
+
loaders: this.loaders,
|
|
107
|
+
trade: this.trade,
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
state(): EntityState {
|
|
112
|
+
return {
|
|
113
|
+
owner: entity.owner ?? Name.from(''),
|
|
114
|
+
location: ServerContract.Types.coordinates.from(this.location),
|
|
115
|
+
energy: this.energy,
|
|
116
|
+
cargomass: UInt32.from(this.cargoMass),
|
|
117
|
+
cargo: entity.cargo,
|
|
118
|
+
}
|
|
119
|
+
},
|
|
64
120
|
}
|
|
121
|
+
|
|
122
|
+
return projected
|
|
65
123
|
}
|
|
66
124
|
|
|
67
|
-
/**
|
|
68
|
-
* Apply a recharge task to projected state.
|
|
69
|
-
*/
|
|
70
125
|
function applyRechargeTask(
|
|
71
126
|
projected: ProjectedEntity,
|
|
72
127
|
_task: ServerContract.Types.task,
|
|
@@ -84,19 +139,16 @@ function applyRechargeTask(
|
|
|
84
139
|
}
|
|
85
140
|
}
|
|
86
141
|
|
|
87
|
-
/**
|
|
88
|
-
* Apply a flight task to projected state.
|
|
89
|
-
*/
|
|
90
142
|
function applyFlightTask(
|
|
91
143
|
projected: ProjectedEntity,
|
|
92
144
|
task: ServerContract.Types.task,
|
|
93
145
|
options: {complete: boolean; progress?: number}
|
|
94
146
|
): void {
|
|
95
|
-
if (!task.
|
|
147
|
+
if (!task.coordinates || !projected.engines) return
|
|
96
148
|
|
|
97
149
|
const origin = projected.location
|
|
98
|
-
const destination = Coordinates.from(task.
|
|
99
|
-
const distance = distanceBetweenCoordinates(origin, task.
|
|
150
|
+
const destination = Coordinates.from(task.coordinates)
|
|
151
|
+
const distance = distanceBetweenCoordinates(origin, task.coordinates)
|
|
100
152
|
const energyUsage = distance.dividing(PRECISION).multiplying(projected.engines.drain)
|
|
101
153
|
|
|
102
154
|
if (options.complete) {
|
|
@@ -117,33 +169,48 @@ function applyFlightTask(
|
|
|
117
169
|
}
|
|
118
170
|
}
|
|
119
171
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
172
|
+
function getItemMass(item_id: UInt16 | number): UInt32 {
|
|
173
|
+
const item = getItem(item_id)
|
|
174
|
+
return item.mass
|
|
175
|
+
}
|
|
176
|
+
|
|
123
177
|
function applyLoadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
124
178
|
for (const item of task.cargo) {
|
|
125
|
-
const
|
|
126
|
-
projected.cargoMass = projected.cargoMass.adding(
|
|
179
|
+
const good_mass = getItemMass(item.item_id)
|
|
180
|
+
projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
|
|
127
181
|
}
|
|
128
182
|
}
|
|
129
183
|
|
|
130
|
-
/**
|
|
131
|
-
* Apply an unload task to projected state.
|
|
132
|
-
*/
|
|
133
184
|
function applyUnloadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
134
185
|
for (const item of task.cargo) {
|
|
135
|
-
const
|
|
136
|
-
const cargoMass =
|
|
186
|
+
const good_mass = getItemMass(item.item_id)
|
|
187
|
+
const cargoMass = good_mass.multiplying(item.quantity)
|
|
137
188
|
projected.cargoMass = projected.cargoMass.gt(cargoMass)
|
|
138
189
|
? projected.cargoMass.subtracting(cargoMass)
|
|
139
190
|
: UInt64.from(0)
|
|
140
191
|
}
|
|
141
192
|
}
|
|
142
193
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
194
|
+
function applyExtractTask(
|
|
195
|
+
projected: ProjectedEntity,
|
|
196
|
+
task: ServerContract.Types.task,
|
|
197
|
+
options: {complete: boolean}
|
|
198
|
+
): void {
|
|
199
|
+
if (!options.complete) return
|
|
200
|
+
|
|
201
|
+
if (task.energy_cost) {
|
|
202
|
+
const energyCost = UInt16.from(task.energy_cost)
|
|
203
|
+
projected.energy = projected.energy.gt(energyCost)
|
|
204
|
+
? UInt16.from(projected.energy.subtracting(energyCost))
|
|
205
|
+
: UInt16.from(0)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const item of task.cargo) {
|
|
209
|
+
const good_mass = getItemMass(item.item_id)
|
|
210
|
+
projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
147
214
|
export function projectEntity(entity: Projectable): ProjectedEntity {
|
|
148
215
|
const projected = createProjectedEntity(entity)
|
|
149
216
|
|
|
@@ -156,7 +223,7 @@ export function projectEntity(entity: Projectable): ProjectedEntity {
|
|
|
156
223
|
case TaskType.RECHARGE:
|
|
157
224
|
applyRechargeTask(projected, task, {complete: true})
|
|
158
225
|
break
|
|
159
|
-
case TaskType.
|
|
226
|
+
case TaskType.TRAVEL:
|
|
160
227
|
applyFlightTask(projected, task, {complete: true})
|
|
161
228
|
break
|
|
162
229
|
case TaskType.LOAD:
|
|
@@ -165,15 +232,15 @@ export function projectEntity(entity: Projectable): ProjectedEntity {
|
|
|
165
232
|
case TaskType.UNLOAD:
|
|
166
233
|
applyUnloadTask(projected, task)
|
|
167
234
|
break
|
|
235
|
+
case TaskType.EXTRACT:
|
|
236
|
+
applyExtractTask(projected, task, {complete: true})
|
|
237
|
+
break
|
|
168
238
|
}
|
|
169
239
|
}
|
|
170
240
|
|
|
171
241
|
return projected
|
|
172
242
|
}
|
|
173
243
|
|
|
174
|
-
/**
|
|
175
|
-
* Project entity state at a specific time (partial task execution).
|
|
176
|
-
*/
|
|
177
244
|
export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity {
|
|
178
245
|
const projected = createProjectedEntity(entity)
|
|
179
246
|
|
|
@@ -198,7 +265,7 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
198
265
|
case TaskType.RECHARGE:
|
|
199
266
|
applyRechargeTask(projected, task, {complete: taskComplete, progress})
|
|
200
267
|
break
|
|
201
|
-
case TaskType.
|
|
268
|
+
case TaskType.TRAVEL:
|
|
202
269
|
applyFlightTask(projected, task, {complete: taskComplete, progress})
|
|
203
270
|
break
|
|
204
271
|
case TaskType.LOAD:
|
|
@@ -211,6 +278,11 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
211
278
|
applyUnloadTask(projected, task)
|
|
212
279
|
}
|
|
213
280
|
break
|
|
281
|
+
case TaskType.EXTRACT:
|
|
282
|
+
if (taskComplete) {
|
|
283
|
+
applyExtractTask(projected, task, {complete: true})
|
|
284
|
+
}
|
|
285
|
+
break
|
|
214
286
|
}
|
|
215
287
|
}
|
|
216
288
|
|
|
@@ -153,3 +153,27 @@ export function scheduleProgress(entity: ScheduleData, now: Date): number {
|
|
|
153
153
|
const elapsed = scheduleElapsed(entity, now)
|
|
154
154
|
return Math.min(1, elapsed / duration)
|
|
155
155
|
}
|
|
156
|
+
|
|
157
|
+
export function isTaskType(entity: ScheduleData, taskType: TaskType, now: Date): boolean {
|
|
158
|
+
return currentTaskType(entity, now) === taskType
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function isInFlight(entity: ScheduleData, now: Date): boolean {
|
|
162
|
+
return isTaskType(entity, TaskType.TRAVEL, now)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function isRecharging(entity: ScheduleData, now: Date): boolean {
|
|
166
|
+
return isTaskType(entity, TaskType.RECHARGE, now)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function isLoading(entity: ScheduleData, now: Date): boolean {
|
|
170
|
+
return isTaskType(entity, TaskType.LOAD, now)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function isUnloading(entity: ScheduleData, now: Date): boolean {
|
|
174
|
+
return isTaskType(entity, TaskType.UNLOAD, now)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function isExtracting(entity: ScheduleData, now: Date): boolean {
|
|
178
|
+
return isTaskType(entity, TaskType.EXTRACT, now)
|
|
179
|
+
}
|