@shipload/sdk 1.0.0-next.26 → 1.0.0-next.28
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 +201 -86
- package/lib/shipload.js +843 -425
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +825 -423
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +13 -8
- package/lib/testing.js +41 -26
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +41 -26
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/craftable.ts +51 -0
- package/src/contracts/server.ts +39 -18
- package/src/data/capabilities.ts +5 -0
- package/src/data/colors.ts +1 -1
- package/src/data/item-ids.ts +1 -1
- package/src/data/metadata.ts +3 -3
- package/src/data/recipes.json +10 -10
- package/src/derivation/capabilities.ts +11 -11
- package/src/derivation/index.ts +9 -0
- package/src/derivation/stars.test.ts +51 -0
- package/src/derivation/stars.ts +15 -0
- package/src/derivation/stats.ts +5 -4
- package/src/entities/entity.ts +1 -1
- package/src/entities/makers.ts +15 -6
- package/src/index-module.ts +33 -4
- package/src/managers/actions.ts +10 -1
- package/src/managers/construction.ts +67 -65
- package/src/nft/buildImmutableData.ts +13 -11
- package/src/nft/description.ts +2 -2
- package/src/resolution/resolve-item.ts +2 -2
- package/src/scheduling/accessor.ts +65 -23
- package/src/scheduling/availability.ts +108 -0
- package/src/scheduling/energy.ts +18 -11
- package/src/scheduling/lane-core.ts +130 -0
- package/src/scheduling/lanes.ts +60 -0
- package/src/scheduling/projection.ts +30 -54
- package/src/scheduling/schedule.ts +236 -121
- package/src/travel/travel.ts +21 -16
- package/src/types/capabilities.ts +1 -0
|
@@ -1,198 +1,313 @@
|
|
|
1
1
|
import type {ServerContract} from '../contracts'
|
|
2
2
|
import {TaskType} from '../types'
|
|
3
|
+
import * as core from './lane-core'
|
|
3
4
|
|
|
4
5
|
type Schedule = ServerContract.Types.schedule
|
|
5
6
|
type Task = ServerContract.Types.task
|
|
7
|
+
type Lane = ServerContract.Types.lane
|
|
8
|
+
|
|
9
|
+
export const LANE_MOBILITY = 0
|
|
10
|
+
export const LANE_BARRIER = 255
|
|
6
11
|
|
|
7
12
|
export interface ScheduleData {
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
13
|
+
lanes?: Lane[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LaneView {
|
|
17
|
+
laneKey: number
|
|
18
|
+
schedule: Schedule
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
laneStartsIn,
|
|
23
|
+
currentTaskIndexForLane,
|
|
24
|
+
laneTaskComplete,
|
|
25
|
+
laneTaskInProgress,
|
|
26
|
+
laneCompletesAt,
|
|
27
|
+
currentTaskProgressFloatForLane,
|
|
28
|
+
} from './lane-core'
|
|
29
|
+
|
|
30
|
+
export function getLanes(entity: ScheduleData): LaneView[] {
|
|
31
|
+
const lanes = entity.lanes
|
|
32
|
+
if (!lanes || lanes.length === 0) return []
|
|
33
|
+
return lanes.map((l) => ({laneKey: l.lane_key.toNumber(), schedule: l.schedule}))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getLane(entity: ScheduleData, laneKey: number): LaneView | undefined {
|
|
37
|
+
const lanes = entity.lanes
|
|
38
|
+
if (!lanes) return undefined
|
|
39
|
+
for (const l of lanes) {
|
|
40
|
+
if (l.lane_key.toNumber() === laneKey) return {laneKey, schedule: l.schedule}
|
|
41
|
+
}
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function mobilityLane(entity: ScheduleData): LaneView | undefined {
|
|
46
|
+
return getLane(entity, LANE_MOBILITY)
|
|
29
47
|
}
|
|
30
48
|
|
|
31
49
|
export function hasSchedule(entity: ScheduleData): boolean {
|
|
32
|
-
|
|
50
|
+
const lanes = entity.lanes
|
|
51
|
+
if (!lanes) return false
|
|
52
|
+
return lanes.some((l) => l.schedule.tasks.length > 0)
|
|
33
53
|
}
|
|
34
54
|
|
|
35
55
|
export function isIdle(entity: ScheduleData): boolean {
|
|
36
56
|
return !hasSchedule(entity)
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
export function isEntityIdle(entity: ScheduleData, now: Date): boolean {
|
|
60
|
+
const lanes = entity.lanes
|
|
61
|
+
if (!lanes) return true
|
|
62
|
+
return lanes.every((l) => core.currentTaskIndexForLane(l.schedule, now) < 0)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function entityIdleAt(entity: ScheduleData, _now: Date): Date | undefined {
|
|
66
|
+
const lanes = entity.lanes
|
|
67
|
+
if (!lanes) return undefined
|
|
68
|
+
let maxMs: number | undefined
|
|
69
|
+
for (const l of lanes) {
|
|
70
|
+
if (l.schedule.tasks.length === 0) continue
|
|
71
|
+
const endMs = l.schedule.started.toDate().getTime() + core.laneDuration(l.schedule) * 1000
|
|
72
|
+
if (maxMs === undefined || endMs > maxMs) maxMs = endMs
|
|
73
|
+
}
|
|
74
|
+
return maxMs === undefined ? undefined : new Date(maxMs)
|
|
75
|
+
}
|
|
76
|
+
|
|
39
77
|
export function getTasks(entity: ScheduleData): Task[] {
|
|
40
|
-
|
|
78
|
+
const lanes = entity.lanes
|
|
79
|
+
if (!lanes) return []
|
|
80
|
+
return lanes.flatMap((l) => l.schedule.tasks)
|
|
41
81
|
}
|
|
42
82
|
|
|
43
83
|
export function scheduleDuration(entity: ScheduleData): number {
|
|
44
|
-
|
|
45
|
-
|
|
84
|
+
let max = 0
|
|
85
|
+
for (const l of entity.lanes ?? []) max = Math.max(max, core.laneDuration(l.schedule))
|
|
86
|
+
return max
|
|
46
87
|
}
|
|
47
88
|
|
|
48
89
|
export function scheduleElapsed(entity: ScheduleData, now: Date): number {
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
return Math.max(0, elapsed)
|
|
90
|
+
let max = 0
|
|
91
|
+
for (const l of entity.lanes ?? []) max = Math.max(max, core.laneElapsed(l.schedule, now))
|
|
92
|
+
return max
|
|
53
93
|
}
|
|
54
94
|
|
|
55
95
|
export function scheduleRemaining(entity: ScheduleData, now: Date): number {
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
96
|
+
let remaining = 0
|
|
97
|
+
for (const l of entity.lanes ?? []) {
|
|
98
|
+
remaining = Math.max(remaining, core.laneRemaining(l.schedule, now))
|
|
99
|
+
}
|
|
100
|
+
return remaining
|
|
60
101
|
}
|
|
61
102
|
|
|
62
103
|
export function scheduleComplete(entity: ScheduleData, now: Date): boolean {
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for (let i = 0; i < entity.schedule.tasks.length; i++) {
|
|
76
|
-
const taskDuration = entity.schedule.tasks[i].duration.toNumber()
|
|
77
|
-
if (elapsed < timeAccum + taskDuration) {
|
|
78
|
-
return i
|
|
104
|
+
const lanes = entity.lanes
|
|
105
|
+
if (!lanes) return false
|
|
106
|
+
let hasAnyTask = false
|
|
107
|
+
let remaining = 0
|
|
108
|
+
for (const l of lanes) {
|
|
109
|
+
const tasks = l.schedule.tasks
|
|
110
|
+
if (tasks.length > 0) {
|
|
111
|
+
hasAnyTask = true
|
|
112
|
+
for (const t of tasks) {
|
|
113
|
+
if (t.type.toNumber() === TaskType.RESERVED) return false
|
|
114
|
+
}
|
|
79
115
|
}
|
|
80
|
-
|
|
116
|
+
remaining = Math.max(remaining, core.laneRemaining(l.schedule, now))
|
|
81
117
|
}
|
|
118
|
+
if (!hasAnyTask) return false
|
|
119
|
+
return remaining === 0
|
|
120
|
+
}
|
|
82
121
|
|
|
83
|
-
|
|
122
|
+
// Mirrors contract lane_front_complete: any lane whose front task is complete and non-reserved.
|
|
123
|
+
export function hasResolvable(entity: ScheduleData, now: Date): boolean {
|
|
124
|
+
for (const l of entity.lanes ?? []) {
|
|
125
|
+
if (core.laneTaskComplete(l.schedule, 0, now)) return true
|
|
126
|
+
}
|
|
127
|
+
return false
|
|
84
128
|
}
|
|
85
129
|
|
|
86
|
-
export function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
130
|
+
export function currentTaskForLane(
|
|
131
|
+
entity: ScheduleData,
|
|
132
|
+
laneKey: number,
|
|
133
|
+
now: Date
|
|
134
|
+
): Task | undefined {
|
|
135
|
+
const lane = getLane(entity, laneKey)
|
|
136
|
+
return lane ? core.currentTask(lane.schedule, now) : undefined
|
|
90
137
|
}
|
|
91
138
|
|
|
92
|
-
export function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
139
|
+
export function currentTaskTypeForLane(
|
|
140
|
+
entity: ScheduleData,
|
|
141
|
+
laneKey: number,
|
|
142
|
+
now: Date
|
|
143
|
+
): TaskType | undefined {
|
|
144
|
+
const lane = getLane(entity, laneKey)
|
|
145
|
+
return lane ? core.currentTaskType(lane.schedule, now) : undefined
|
|
96
146
|
}
|
|
97
147
|
|
|
98
|
-
export function
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
148
|
+
export function activeTasks(entity: ScheduleData, now: Date): Task[] {
|
|
149
|
+
const out: Task[] = []
|
|
150
|
+
for (const l of entity.lanes ?? []) {
|
|
151
|
+
const idx = core.currentTaskIndexForLane(l.schedule, now)
|
|
152
|
+
if (idx >= 0) out.push(l.schedule.tasks[idx])
|
|
103
153
|
}
|
|
104
|
-
return
|
|
154
|
+
return out
|
|
105
155
|
}
|
|
106
156
|
|
|
107
|
-
export
|
|
108
|
-
|
|
157
|
+
export interface ResolvedEvent {
|
|
158
|
+
laneKey: number
|
|
159
|
+
taskIndex: number
|
|
160
|
+
task: Task
|
|
161
|
+
completesAt: Date
|
|
162
|
+
}
|
|
109
163
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
164
|
+
// Canonical lane-front order (mirrors contract front_precedes): completion, then RECHARGE-last, then lane key.
|
|
165
|
+
function frontPrecedes(
|
|
166
|
+
a: {completesAt: Date; task: Task; laneKey: number},
|
|
167
|
+
b: {completesAt: Date; task: Task; laneKey: number}
|
|
168
|
+
): number {
|
|
169
|
+
if (a.completesAt.getTime() !== b.completesAt.getTime()) {
|
|
170
|
+
return a.completesAt.getTime() - b.completesAt.getTime()
|
|
171
|
+
}
|
|
172
|
+
const aRecharge = a.task.type.toNumber() === TaskType.RECHARGE
|
|
173
|
+
const bRecharge = b.task.type.toNumber() === TaskType.RECHARGE
|
|
174
|
+
if (aRecharge !== bRecharge) return aRecharge ? 1 : -1
|
|
175
|
+
return a.laneKey - b.laneKey
|
|
176
|
+
}
|
|
113
177
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
178
|
+
// Completed lane-fronts in canonical order (mirrors contract front_precedes).
|
|
179
|
+
export function resolveOrder(entity: ScheduleData, now: Date): ResolvedEvent[] {
|
|
180
|
+
const events: ResolvedEvent[] = []
|
|
181
|
+
for (const l of entity.lanes ?? []) {
|
|
182
|
+
const laneKey = l.lane_key.toNumber()
|
|
183
|
+
const startedMs = l.schedule.started.toDate().getTime()
|
|
184
|
+
let endSec = 0
|
|
185
|
+
for (let i = 0; i < l.schedule.tasks.length; i++) {
|
|
186
|
+
const task = l.schedule.tasks[i]
|
|
187
|
+
endSec += task.duration.toNumber()
|
|
188
|
+
const completesAt = new Date(startedMs + endSec * 1000)
|
|
189
|
+
if (task.type.toNumber() === TaskType.RESERVED) break
|
|
190
|
+
if (completesAt.getTime() > now.getTime()) break
|
|
191
|
+
events.push({laneKey, taskIndex: i, task, completesAt})
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
events.sort(frontPrecedes)
|
|
195
|
+
return events
|
|
117
196
|
}
|
|
118
197
|
|
|
119
|
-
export
|
|
120
|
-
|
|
198
|
+
export interface OrderedTask {
|
|
199
|
+
laneKey: number
|
|
200
|
+
taskIndex: number
|
|
201
|
+
task: Task
|
|
202
|
+
startsAt: Date
|
|
203
|
+
completesAt: Date
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Every task across all lanes in canonical order (mirrors contract front_precedes).
|
|
207
|
+
export function orderedTasks(entity: ScheduleData): OrderedTask[] {
|
|
208
|
+
const out: OrderedTask[] = []
|
|
209
|
+
for (const l of entity.lanes ?? []) {
|
|
210
|
+
const laneKey = l.lane_key.toNumber()
|
|
211
|
+
const startedMs = l.schedule.started.toDate().getTime()
|
|
212
|
+
let endSec = 0
|
|
213
|
+
for (let i = 0; i < l.schedule.tasks.length; i++) {
|
|
214
|
+
const task = l.schedule.tasks[i]
|
|
215
|
+
const startsAt = new Date(startedMs + endSec * 1000)
|
|
216
|
+
endSec += task.duration.toNumber()
|
|
217
|
+
const completesAt = new Date(startedMs + endSec * 1000)
|
|
218
|
+
out.push({laneKey, taskIndex: i, task, startsAt, completesAt})
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
out.sort(frontPrecedes)
|
|
222
|
+
return out
|
|
223
|
+
}
|
|
121
224
|
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
return
|
|
225
|
+
export function laneRemainingOf(entity: ScheduleData, laneKey: number, now: Date): number {
|
|
226
|
+
const lane = getLane(entity, laneKey)
|
|
227
|
+
return lane ? core.laneRemaining(lane.schedule, now) : 0
|
|
125
228
|
}
|
|
126
229
|
|
|
127
|
-
export function
|
|
128
|
-
|
|
230
|
+
export function laneStartsInOf(entity: ScheduleData, laneKey: number, now: Date): number {
|
|
231
|
+
const lane = getLane(entity, laneKey)
|
|
232
|
+
return lane ? core.laneStartsIn(lane.schedule, now) : 0
|
|
233
|
+
}
|
|
129
234
|
|
|
130
|
-
|
|
235
|
+
export function laneCompleteOf(entity: ScheduleData, laneKey: number, now: Date): boolean {
|
|
236
|
+
const lane = getLane(entity, laneKey)
|
|
237
|
+
return lane ? core.laneComplete(lane.schedule, now) : false
|
|
238
|
+
}
|
|
131
239
|
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
return
|
|
240
|
+
export function laneProgressOf(entity: ScheduleData, laneKey: number, now: Date): number {
|
|
241
|
+
const lane = getLane(entity, laneKey)
|
|
242
|
+
return lane ? core.laneProgress(lane.schedule, now) : 0
|
|
135
243
|
}
|
|
136
244
|
|
|
137
|
-
export function
|
|
138
|
-
|
|
245
|
+
export function laneTaskElapsedOf(
|
|
246
|
+
entity: ScheduleData,
|
|
247
|
+
laneKey: number,
|
|
248
|
+
index: number,
|
|
249
|
+
now: Date
|
|
250
|
+
): number {
|
|
251
|
+
const lane = getLane(entity, laneKey)
|
|
252
|
+
return lane ? core.laneTaskElapsed(lane.schedule, index, now) : 0
|
|
253
|
+
}
|
|
139
254
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
255
|
+
export function laneTaskRemainingOf(
|
|
256
|
+
entity: ScheduleData,
|
|
257
|
+
laneKey: number,
|
|
258
|
+
index: number,
|
|
259
|
+
now: Date
|
|
260
|
+
): number {
|
|
261
|
+
const lane = getLane(entity, laneKey)
|
|
262
|
+
return lane ? core.laneTaskRemaining(lane.schedule, index, now) : 0
|
|
143
263
|
}
|
|
144
264
|
|
|
145
|
-
export function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return
|
|
265
|
+
export function laneTaskCompleteOf(
|
|
266
|
+
entity: ScheduleData,
|
|
267
|
+
laneKey: number,
|
|
268
|
+
index: number,
|
|
269
|
+
now: Date
|
|
270
|
+
): boolean {
|
|
271
|
+
const lane = getLane(entity, laneKey)
|
|
272
|
+
return lane ? core.laneTaskComplete(lane.schedule, index, now) : false
|
|
153
273
|
}
|
|
154
274
|
|
|
155
|
-
export function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const taskStartMs = startedMs + getTaskStartTime(entity, index) * 1000
|
|
164
|
-
const elapsedMs = now.getTime() - taskStartMs
|
|
165
|
-
if (elapsedMs <= 0) return 0
|
|
166
|
-
return Math.min(1, elapsedMs / durationMs)
|
|
275
|
+
export function laneTaskInProgressOf(
|
|
276
|
+
entity: ScheduleData,
|
|
277
|
+
laneKey: number,
|
|
278
|
+
index: number,
|
|
279
|
+
now: Date
|
|
280
|
+
): boolean {
|
|
281
|
+
const lane = getLane(entity, laneKey)
|
|
282
|
+
return lane ? core.laneTaskInProgress(lane.schedule, index, now) : false
|
|
167
283
|
}
|
|
168
284
|
|
|
169
|
-
export function
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
const elapsed = scheduleElapsed(entity, now)
|
|
173
|
-
return Math.min(1, elapsed / duration)
|
|
285
|
+
export function currentTaskIndexOf(entity: ScheduleData, laneKey: number, now: Date): number {
|
|
286
|
+
const lane = getLane(entity, laneKey)
|
|
287
|
+
return lane ? core.currentTaskIndexForLane(lane.schedule, now) : -1
|
|
174
288
|
}
|
|
175
289
|
|
|
176
|
-
|
|
177
|
-
return
|
|
290
|
+
function entityDoesTaskType(entity: ScheduleData, taskType: TaskType, now: Date): boolean {
|
|
291
|
+
return activeTasks(entity, now).some((t) => t.type.toNumber() === taskType)
|
|
178
292
|
}
|
|
179
293
|
|
|
180
294
|
export function isInFlight(entity: ScheduleData, now: Date): boolean {
|
|
181
|
-
|
|
295
|
+
const lane = mobilityLane(entity)
|
|
296
|
+
return lane ? core.currentTaskType(lane.schedule, now) === TaskType.TRAVEL : false
|
|
182
297
|
}
|
|
183
298
|
|
|
184
299
|
export function isRecharging(entity: ScheduleData, now: Date): boolean {
|
|
185
|
-
return
|
|
300
|
+
return entityDoesTaskType(entity, TaskType.RECHARGE, now)
|
|
186
301
|
}
|
|
187
302
|
|
|
188
303
|
export function isLoading(entity: ScheduleData, now: Date): boolean {
|
|
189
|
-
return
|
|
304
|
+
return entityDoesTaskType(entity, TaskType.LOAD, now)
|
|
190
305
|
}
|
|
191
306
|
|
|
192
307
|
export function isUnloading(entity: ScheduleData, now: Date): boolean {
|
|
193
|
-
return
|
|
308
|
+
return entityDoesTaskType(entity, TaskType.UNLOAD, now)
|
|
194
309
|
}
|
|
195
310
|
|
|
196
311
|
export function isGathering(entity: ScheduleData, now: Date): boolean {
|
|
197
|
-
return
|
|
312
|
+
return entityDoesTaskType(entity, TaskType.GATHER, now)
|
|
198
313
|
}
|
package/src/travel/travel.ts
CHANGED
|
@@ -35,6 +35,8 @@ import {
|
|
|
35
35
|
} from '../types'
|
|
36
36
|
import {getItem} from '../data/catalog'
|
|
37
37
|
import {hasSystem} from '../utils/system'
|
|
38
|
+
import * as scheduleModel from '../scheduling/schedule'
|
|
39
|
+
import type {ScheduleData} from '../scheduling/schedule'
|
|
38
40
|
|
|
39
41
|
export function calc_orbital_altitude(mass: number): number {
|
|
40
42
|
if (mass <= BASE_ORBITAL_MASS) {
|
|
@@ -112,14 +114,15 @@ export function getInterpolatedPosition(
|
|
|
112
114
|
taskIndex: number,
|
|
113
115
|
taskProgress: number
|
|
114
116
|
): FloatPosition {
|
|
115
|
-
|
|
117
|
+
const tasks = mobilityTasks(entity)
|
|
118
|
+
if (tasks.length === 0) {
|
|
116
119
|
return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
|
|
117
120
|
}
|
|
118
121
|
if (taskIndex < 0) {
|
|
119
|
-
const settled = getFlightOrigin(entity,
|
|
122
|
+
const settled = getFlightOrigin(entity, tasks.length)
|
|
120
123
|
return {x: Number(settled.x), y: Number(settled.y)}
|
|
121
124
|
}
|
|
122
|
-
const task =
|
|
125
|
+
const task = tasks[taskIndex]
|
|
123
126
|
if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
|
|
124
127
|
const origin = getFlightOrigin(entity, taskIndex)
|
|
125
128
|
return {x: Number(origin.x), y: Number(origin.y)}
|
|
@@ -427,20 +430,22 @@ export interface TransferEntity {
|
|
|
427
430
|
}
|
|
428
431
|
}
|
|
429
432
|
|
|
430
|
-
export interface HasScheduleAndLocation {
|
|
433
|
+
export interface HasScheduleAndLocation extends ScheduleData {
|
|
431
434
|
coordinates: ServerContract.ActionParams.Type.coordinates
|
|
432
|
-
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function mobilityTasks(entity: HasScheduleAndLocation): ServerContract.Types.task[] {
|
|
438
|
+
return scheduleModel.mobilityLane(entity)?.schedule.tasks ?? []
|
|
433
439
|
}
|
|
434
440
|
|
|
435
441
|
export function getFlightOrigin(
|
|
436
442
|
entity: HasScheduleAndLocation,
|
|
437
443
|
flightTaskIndex: number
|
|
438
444
|
): ServerContract.ActionParams.Type.coordinates {
|
|
439
|
-
|
|
440
|
-
|
|
445
|
+
const tasks = mobilityTasks(entity)
|
|
441
446
|
let origin = entity.coordinates
|
|
442
|
-
for (let i = 0; i < flightTaskIndex && i <
|
|
443
|
-
const task =
|
|
447
|
+
for (let i = 0; i < flightTaskIndex && i < tasks.length; i++) {
|
|
448
|
+
const task = tasks[i]
|
|
444
449
|
if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
|
|
445
450
|
origin = task.coordinates
|
|
446
451
|
}
|
|
@@ -451,10 +456,9 @@ export function getFlightOrigin(
|
|
|
451
456
|
export function getDestinationLocation(
|
|
452
457
|
entity: HasScheduleAndLocation
|
|
453
458
|
): ServerContract.ActionParams.Type.coordinates | undefined {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const task = entity.schedule.tasks[i]
|
|
459
|
+
const tasks = mobilityTasks(entity)
|
|
460
|
+
for (let i = tasks.length - 1; i >= 0; i--) {
|
|
461
|
+
const task = tasks[i]
|
|
458
462
|
if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
|
|
459
463
|
return task.coordinates
|
|
460
464
|
}
|
|
@@ -468,14 +472,15 @@ export function getPositionAt(
|
|
|
468
472
|
taskIndex: number,
|
|
469
473
|
taskProgress: number
|
|
470
474
|
): ServerContract.ActionParams.Type.coordinates {
|
|
471
|
-
|
|
475
|
+
const tasks = mobilityTasks(entity)
|
|
476
|
+
if (tasks.length === 0) {
|
|
472
477
|
return entity.coordinates
|
|
473
478
|
}
|
|
474
479
|
if (taskIndex < 0) {
|
|
475
|
-
return getFlightOrigin(entity,
|
|
480
|
+
return getFlightOrigin(entity, tasks.length)
|
|
476
481
|
}
|
|
477
482
|
|
|
478
|
-
const task =
|
|
483
|
+
const task = tasks[taskIndex]
|
|
479
484
|
|
|
480
485
|
if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
|
|
481
486
|
return getFlightOrigin(entity, taskIndex)
|