@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,290 @@
|
|
|
1
|
+
import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import {ServerContract} from '../contracts'
|
|
3
|
+
import {Coordinates, PRECISION, TaskType} from '../types'
|
|
4
|
+
import {
|
|
5
|
+
capsHasLoaders,
|
|
6
|
+
capsHasMovement,
|
|
7
|
+
capsHasStorage,
|
|
8
|
+
EntityCapabilities,
|
|
9
|
+
EntityState,
|
|
10
|
+
} from '../types/capabilities'
|
|
11
|
+
import {distanceBetweenCoordinates, lerp} from '../travel/travel'
|
|
12
|
+
import {calcCargoMass} from '../capabilities/storage'
|
|
13
|
+
import {getGood} from '../market/goods'
|
|
14
|
+
import * as schedule from './schedule'
|
|
15
|
+
import {ScheduleData} from './schedule'
|
|
16
|
+
|
|
17
|
+
export interface ProjectedEntity {
|
|
18
|
+
location: Coordinates
|
|
19
|
+
energy: UInt16
|
|
20
|
+
cargoMass: UInt64
|
|
21
|
+
shipMass: UInt32
|
|
22
|
+
capacity?: UInt64
|
|
23
|
+
engines?: ServerContract.Types.movement_stats
|
|
24
|
+
loaders?: ServerContract.Types.loader_stats
|
|
25
|
+
generator?: ServerContract.Types.energy_stats
|
|
26
|
+
trade?: ServerContract.Types.trade_stats
|
|
27
|
+
readonly totalMass: UInt64
|
|
28
|
+
|
|
29
|
+
hasMovement(): boolean
|
|
30
|
+
hasStorage(): boolean
|
|
31
|
+
hasLoaders(): boolean
|
|
32
|
+
hasTrade(): boolean
|
|
33
|
+
|
|
34
|
+
capabilities(): EntityCapabilities
|
|
35
|
+
state(): EntityState
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface Projectable extends ScheduleData {
|
|
39
|
+
coordinates: Coordinates | ServerContract.Types.coordinates
|
|
40
|
+
energy?: UInt16
|
|
41
|
+
hullmass?: UInt32
|
|
42
|
+
generator?: ServerContract.Types.energy_stats
|
|
43
|
+
engines?: ServerContract.Types.movement_stats
|
|
44
|
+
loaders?: ServerContract.Types.loader_stats
|
|
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)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
57
|
+
const cargoMass = calcCargoMass(entity)
|
|
58
|
+
const shipMass = getHullMass(entity)
|
|
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
|
|
64
|
+
|
|
65
|
+
const projected: ProjectedEntity = {
|
|
66
|
+
location: Coordinates.from(entity.coordinates),
|
|
67
|
+
energy: UInt16.from(entity.energy ?? 0),
|
|
68
|
+
cargoMass,
|
|
69
|
+
shipMass,
|
|
70
|
+
capacity: capacity ? UInt64.from(capacity) : undefined,
|
|
71
|
+
engines,
|
|
72
|
+
generator,
|
|
73
|
+
loaders,
|
|
74
|
+
trade,
|
|
75
|
+
|
|
76
|
+
get totalMass() {
|
|
77
|
+
let mass = UInt64.from(this.shipMass).adding(this.cargoMass)
|
|
78
|
+
if (this.loaders) {
|
|
79
|
+
mass = mass.adding(this.loaders.mass.multiplying(this.loaders.quantity))
|
|
80
|
+
}
|
|
81
|
+
return mass
|
|
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
|
+
},
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return projected
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function applyRechargeTask(
|
|
126
|
+
projected: ProjectedEntity,
|
|
127
|
+
_task: ServerContract.Types.task,
|
|
128
|
+
options: {complete: boolean; progress?: number}
|
|
129
|
+
): void {
|
|
130
|
+
if (!projected.generator) return
|
|
131
|
+
|
|
132
|
+
if (options.complete) {
|
|
133
|
+
projected.energy = UInt16.from(projected.generator.capacity)
|
|
134
|
+
} else if (options.progress !== undefined) {
|
|
135
|
+
const capacity = Number(projected.generator.capacity)
|
|
136
|
+
const currentEnergy = Number(projected.energy)
|
|
137
|
+
const rechargeAmount = (capacity - currentEnergy) * options.progress
|
|
138
|
+
projected.energy = UInt16.from(Math.min(capacity, currentEnergy + rechargeAmount))
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function applyFlightTask(
|
|
143
|
+
projected: ProjectedEntity,
|
|
144
|
+
task: ServerContract.Types.task,
|
|
145
|
+
options: {complete: boolean; progress?: number}
|
|
146
|
+
): void {
|
|
147
|
+
if (!task.coordinates || !projected.engines) return
|
|
148
|
+
|
|
149
|
+
const origin = projected.location
|
|
150
|
+
const destination = Coordinates.from(task.coordinates)
|
|
151
|
+
const distance = distanceBetweenCoordinates(origin, task.coordinates)
|
|
152
|
+
const energyUsage = distance.dividing(PRECISION).multiplying(projected.engines.drain)
|
|
153
|
+
|
|
154
|
+
if (options.complete) {
|
|
155
|
+
projected.energy = projected.energy.gt(energyUsage)
|
|
156
|
+
? UInt16.from(projected.energy.subtracting(energyUsage))
|
|
157
|
+
: UInt16.from(0)
|
|
158
|
+
projected.location = destination
|
|
159
|
+
} else if (options.progress !== undefined) {
|
|
160
|
+
const interpolated = lerp(origin, destination, options.progress)
|
|
161
|
+
projected.location = Coordinates.from({
|
|
162
|
+
x: Math.round(interpolated.x),
|
|
163
|
+
y: Math.round(interpolated.y),
|
|
164
|
+
})
|
|
165
|
+
const partialEnergy = UInt64.from(Math.floor(Number(energyUsage) * options.progress))
|
|
166
|
+
projected.energy = projected.energy.gt(partialEnergy)
|
|
167
|
+
? UInt16.from(projected.energy.subtracting(partialEnergy))
|
|
168
|
+
: UInt16.from(0)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getGoodMass(good_id: UInt16 | number): UInt32 {
|
|
173
|
+
const good = getGood(good_id)
|
|
174
|
+
return good.mass
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function applyLoadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
178
|
+
for (const item of task.cargo) {
|
|
179
|
+
const good_mass = getGoodMass(item.good_id)
|
|
180
|
+
projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function applyUnloadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
185
|
+
for (const item of task.cargo) {
|
|
186
|
+
const good_mass = getGoodMass(item.good_id)
|
|
187
|
+
const cargoMass = good_mass.multiplying(item.quantity)
|
|
188
|
+
projected.cargoMass = projected.cargoMass.gt(cargoMass)
|
|
189
|
+
? projected.cargoMass.subtracting(cargoMass)
|
|
190
|
+
: UInt64.from(0)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
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 = getGoodMass(item.good_id)
|
|
210
|
+
projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function projectEntity(entity: Projectable): ProjectedEntity {
|
|
215
|
+
const projected = createProjectedEntity(entity)
|
|
216
|
+
|
|
217
|
+
if (!entity.schedule) {
|
|
218
|
+
return projected
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (const task of entity.schedule.tasks) {
|
|
222
|
+
switch (task.type.toNumber()) {
|
|
223
|
+
case TaskType.RECHARGE:
|
|
224
|
+
applyRechargeTask(projected, task, {complete: true})
|
|
225
|
+
break
|
|
226
|
+
case TaskType.TRAVEL:
|
|
227
|
+
applyFlightTask(projected, task, {complete: true})
|
|
228
|
+
break
|
|
229
|
+
case TaskType.LOAD:
|
|
230
|
+
applyLoadTask(projected, task)
|
|
231
|
+
break
|
|
232
|
+
case TaskType.UNLOAD:
|
|
233
|
+
applyUnloadTask(projected, task)
|
|
234
|
+
break
|
|
235
|
+
case TaskType.EXTRACT:
|
|
236
|
+
applyExtractTask(projected, task, {complete: true})
|
|
237
|
+
break
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return projected
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity {
|
|
245
|
+
const projected = createProjectedEntity(entity)
|
|
246
|
+
|
|
247
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) {
|
|
248
|
+
return projected
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (let i = 0; i < entity.schedule.tasks.length; i++) {
|
|
252
|
+
const task = entity.schedule.tasks[i]
|
|
253
|
+
const taskComplete = schedule.isTaskComplete(entity, i, now)
|
|
254
|
+
const taskInProgress = schedule.isTaskInProgress(entity, i, now)
|
|
255
|
+
|
|
256
|
+
if (!taskComplete && !taskInProgress) {
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const progress = taskInProgress
|
|
261
|
+
? schedule.getTaskElapsed(entity, i, now) / task.duration.toNumber()
|
|
262
|
+
: undefined
|
|
263
|
+
|
|
264
|
+
switch (task.type.toNumber()) {
|
|
265
|
+
case TaskType.RECHARGE:
|
|
266
|
+
applyRechargeTask(projected, task, {complete: taskComplete, progress})
|
|
267
|
+
break
|
|
268
|
+
case TaskType.TRAVEL:
|
|
269
|
+
applyFlightTask(projected, task, {complete: taskComplete, progress})
|
|
270
|
+
break
|
|
271
|
+
case TaskType.LOAD:
|
|
272
|
+
if (taskComplete) {
|
|
273
|
+
applyLoadTask(projected, task)
|
|
274
|
+
}
|
|
275
|
+
break
|
|
276
|
+
case TaskType.UNLOAD:
|
|
277
|
+
if (taskComplete) {
|
|
278
|
+
applyUnloadTask(projected, task)
|
|
279
|
+
}
|
|
280
|
+
break
|
|
281
|
+
case TaskType.EXTRACT:
|
|
282
|
+
if (taskComplete) {
|
|
283
|
+
applyExtractTask(projected, task, {complete: true})
|
|
284
|
+
}
|
|
285
|
+
break
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return projected
|
|
290
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {ServerContract} from '../contracts'
|
|
2
|
+
import {TaskType} from '../types'
|
|
3
|
+
|
|
4
|
+
type Schedule = ServerContract.Types.schedule
|
|
5
|
+
type Task = ServerContract.Types.task
|
|
6
|
+
|
|
7
|
+
export interface ScheduleData {
|
|
8
|
+
schedule?: Schedule
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Scheduleable extends ScheduleData {
|
|
12
|
+
hasSchedule: boolean
|
|
13
|
+
isIdle: boolean
|
|
14
|
+
tasks: Task[]
|
|
15
|
+
scheduleDuration(): number
|
|
16
|
+
scheduleElapsed(now: Date): number
|
|
17
|
+
scheduleRemaining(now: Date): number
|
|
18
|
+
scheduleComplete(now: Date): boolean
|
|
19
|
+
currentTaskIndex(now: Date): number
|
|
20
|
+
currentTask(now: Date): Task | undefined
|
|
21
|
+
currentTaskType(now: Date): TaskType | undefined
|
|
22
|
+
getTaskStartTime(index: number): number
|
|
23
|
+
getTaskElapsed(index: number, now: Date): number
|
|
24
|
+
getTaskRemaining(index: number, now: Date): number
|
|
25
|
+
isTaskComplete(index: number, now: Date): boolean
|
|
26
|
+
isTaskInProgress(index: number, now: Date): boolean
|
|
27
|
+
currentTaskProgress(now: Date): number
|
|
28
|
+
scheduleProgress(now: Date): number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function hasSchedule(entity: ScheduleData): boolean {
|
|
32
|
+
return !!entity.schedule && entity.schedule.tasks.length > 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isIdle(entity: ScheduleData): boolean {
|
|
36
|
+
return !hasSchedule(entity)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getTasks(entity: ScheduleData): Task[] {
|
|
40
|
+
return entity.schedule?.tasks || []
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function scheduleDuration(entity: ScheduleData): number {
|
|
44
|
+
if (!entity.schedule) return 0
|
|
45
|
+
return entity.schedule.tasks.reduce((sum, task) => sum + task.duration.toNumber(), 0)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function scheduleElapsed(entity: ScheduleData, now: Date): number {
|
|
49
|
+
if (!entity.schedule) return 0
|
|
50
|
+
const started = entity.schedule.started.toDate()
|
|
51
|
+
const elapsed = Math.floor((now.getTime() - started.getTime()) / 1000)
|
|
52
|
+
return Math.max(0, elapsed)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function scheduleRemaining(entity: ScheduleData, now: Date): number {
|
|
56
|
+
if (!entity.schedule) return 0
|
|
57
|
+
const duration = scheduleDuration(entity)
|
|
58
|
+
const elapsed = scheduleElapsed(entity, now)
|
|
59
|
+
return Math.max(0, duration - elapsed)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function scheduleComplete(entity: ScheduleData, now: Date): boolean {
|
|
63
|
+
return hasSchedule(entity) && scheduleRemaining(entity, now) === 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function currentTaskIndex(entity: ScheduleData, now: Date): number {
|
|
67
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) return -1
|
|
68
|
+
|
|
69
|
+
const elapsed = scheduleElapsed(entity, now)
|
|
70
|
+
let timeAccum = 0
|
|
71
|
+
|
|
72
|
+
for (let i = 0; i < entity.schedule.tasks.length; i++) {
|
|
73
|
+
const taskDuration = entity.schedule.tasks[i].duration.toNumber()
|
|
74
|
+
if (elapsed < timeAccum + taskDuration) {
|
|
75
|
+
return i
|
|
76
|
+
}
|
|
77
|
+
timeAccum += taskDuration
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return entity.schedule.tasks.length - 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function currentTask(entity: ScheduleData, now: Date): Task | undefined {
|
|
84
|
+
const index = currentTaskIndex(entity, now)
|
|
85
|
+
if (index < 0 || !entity.schedule) return undefined
|
|
86
|
+
return entity.schedule.tasks[index]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function currentTaskType(entity: ScheduleData, now: Date): TaskType | undefined {
|
|
90
|
+
const task = currentTask(entity, now)
|
|
91
|
+
if (!task) return undefined
|
|
92
|
+
return task.type.toNumber() as TaskType
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getTaskStartTime(entity: ScheduleData, index: number): number {
|
|
96
|
+
if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
|
|
97
|
+
let timeAccum = 0
|
|
98
|
+
for (let i = 0; i < index; i++) {
|
|
99
|
+
timeAccum += entity.schedule.tasks[i].duration.toNumber()
|
|
100
|
+
}
|
|
101
|
+
return timeAccum
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function getTaskElapsed(entity: ScheduleData, index: number, now: Date): number {
|
|
105
|
+
if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
|
|
106
|
+
|
|
107
|
+
const elapsed = scheduleElapsed(entity, now)
|
|
108
|
+
const taskStart = getTaskStartTime(entity, index)
|
|
109
|
+
const taskDuration = entity.schedule.tasks[index].duration.toNumber()
|
|
110
|
+
|
|
111
|
+
if (elapsed <= taskStart) return 0
|
|
112
|
+
const elapsedInTask = elapsed - taskStart
|
|
113
|
+
return Math.min(elapsedInTask, taskDuration)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function getTaskRemaining(entity: ScheduleData, index: number, now: Date): number {
|
|
117
|
+
if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
|
|
118
|
+
|
|
119
|
+
const taskDuration = entity.schedule.tasks[index].duration.toNumber()
|
|
120
|
+
const taskElapsed = getTaskElapsed(entity, index, now)
|
|
121
|
+
return Math.max(0, taskDuration - taskElapsed)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function isTaskComplete(entity: ScheduleData, index: number, now: Date): boolean {
|
|
125
|
+
if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return false
|
|
126
|
+
|
|
127
|
+
const taskDuration = entity.schedule.tasks[index].duration.toNumber()
|
|
128
|
+
const taskElapsed = getTaskElapsed(entity, index, now)
|
|
129
|
+
return taskElapsed >= taskDuration
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function isTaskInProgress(entity: ScheduleData, index: number, now: Date): boolean {
|
|
133
|
+
if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return false
|
|
134
|
+
|
|
135
|
+
const taskElapsed = getTaskElapsed(entity, index, now)
|
|
136
|
+
const taskDuration = entity.schedule.tasks[index].duration.toNumber()
|
|
137
|
+
return taskElapsed > 0 && taskElapsed < taskDuration
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function currentTaskProgress(entity: ScheduleData, now: Date): number {
|
|
141
|
+
const task = currentTask(entity, now)
|
|
142
|
+
if (!task) return 0
|
|
143
|
+
const index = currentTaskIndex(entity, now)
|
|
144
|
+
const elapsed = getTaskElapsed(entity, index, now)
|
|
145
|
+
const duration = task.duration.toNumber()
|
|
146
|
+
if (duration === 0) return 1
|
|
147
|
+
return Math.min(1, elapsed / duration)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function scheduleProgress(entity: ScheduleData, now: Date): number {
|
|
151
|
+
const duration = scheduleDuration(entity)
|
|
152
|
+
if (duration === 0) return hasSchedule(entity) ? 1 : 0
|
|
153
|
+
const elapsed = scheduleElapsed(entity, now)
|
|
154
|
+
return Math.min(1, elapsed / duration)
|
|
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
|
+
}
|