@shipload/sdk 1.0.0-next.72 → 1.0.0-next.73
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 +75 -7
- package/lib/shipload.js +272 -332
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +269 -333
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +20 -5
- package/lib/testing.js +239 -322
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +239 -322
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +67 -10
- package/src/data/catalog.test.ts +81 -1
- package/src/data/catalog.ts +6 -4
- package/src/data/metadata.ts +197 -363
- package/src/data/task-types.json +184 -0
- package/src/entities/makers.ts +2 -2
- package/src/index-module.ts +9 -1
- package/src/managers/actions.ts +12 -0
- package/src/resolution/resolve-item.ts +2 -2
- package/src/scheduling/unwrap.test.ts +60 -0
- package/src/scheduling/unwrap.ts +24 -8
- package/src/types.ts +1 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"types": [
|
|
3
|
+
{
|
|
4
|
+
"type": 0,
|
|
5
|
+
"positionBound": false,
|
|
6
|
+
"mobility": false,
|
|
7
|
+
"consumer": false,
|
|
8
|
+
"isTerminal": false,
|
|
9
|
+
"capsPlan": false,
|
|
10
|
+
"cargoEffectResolve": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": 1,
|
|
14
|
+
"positionBound": false,
|
|
15
|
+
"mobility": true,
|
|
16
|
+
"consumer": false,
|
|
17
|
+
"isTerminal": false,
|
|
18
|
+
"capsPlan": false,
|
|
19
|
+
"cargoEffectResolve": true
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"type": 2,
|
|
23
|
+
"positionBound": false,
|
|
24
|
+
"mobility": false,
|
|
25
|
+
"consumer": false,
|
|
26
|
+
"isTerminal": false,
|
|
27
|
+
"capsPlan": false,
|
|
28
|
+
"cargoEffectResolve": true
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": 3,
|
|
32
|
+
"positionBound": true,
|
|
33
|
+
"mobility": false,
|
|
34
|
+
"consumer": false,
|
|
35
|
+
"isTerminal": false,
|
|
36
|
+
"capsPlan": false,
|
|
37
|
+
"cargoEffectResolve": true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": 4,
|
|
41
|
+
"positionBound": true,
|
|
42
|
+
"mobility": false,
|
|
43
|
+
"consumer": true,
|
|
44
|
+
"isTerminal": false,
|
|
45
|
+
"capsPlan": false,
|
|
46
|
+
"cargoEffectResolve": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": 5,
|
|
50
|
+
"positionBound": true,
|
|
51
|
+
"mobility": false,
|
|
52
|
+
"consumer": false,
|
|
53
|
+
"isTerminal": false,
|
|
54
|
+
"capsPlan": false,
|
|
55
|
+
"cargoEffectResolve": true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": 6,
|
|
59
|
+
"positionBound": false,
|
|
60
|
+
"mobility": true,
|
|
61
|
+
"consumer": false,
|
|
62
|
+
"isTerminal": false,
|
|
63
|
+
"capsPlan": false,
|
|
64
|
+
"cargoEffectResolve": true
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"type": 7,
|
|
68
|
+
"positionBound": false,
|
|
69
|
+
"mobility": false,
|
|
70
|
+
"consumer": true,
|
|
71
|
+
"isTerminal": false,
|
|
72
|
+
"capsPlan": false,
|
|
73
|
+
"cargoEffectResolve": false
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": 9,
|
|
77
|
+
"positionBound": false,
|
|
78
|
+
"mobility": true,
|
|
79
|
+
"consumer": false,
|
|
80
|
+
"isTerminal": false,
|
|
81
|
+
"capsPlan": false,
|
|
82
|
+
"cargoEffectResolve": true
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": 10,
|
|
86
|
+
"positionBound": false,
|
|
87
|
+
"mobility": false,
|
|
88
|
+
"consumer": false,
|
|
89
|
+
"isTerminal": false,
|
|
90
|
+
"capsPlan": false,
|
|
91
|
+
"cargoEffectResolve": false
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"type": 11,
|
|
95
|
+
"positionBound": false,
|
|
96
|
+
"mobility": false,
|
|
97
|
+
"consumer": false,
|
|
98
|
+
"isTerminal": true,
|
|
99
|
+
"capsPlan": true,
|
|
100
|
+
"cargoEffectResolve": false
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"type": 12,
|
|
104
|
+
"positionBound": false,
|
|
105
|
+
"mobility": false,
|
|
106
|
+
"consumer": false,
|
|
107
|
+
"isTerminal": false,
|
|
108
|
+
"capsPlan": false,
|
|
109
|
+
"cargoEffectResolve": true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"type": 13,
|
|
113
|
+
"positionBound": false,
|
|
114
|
+
"mobility": false,
|
|
115
|
+
"consumer": false,
|
|
116
|
+
"isTerminal": true,
|
|
117
|
+
"capsPlan": true,
|
|
118
|
+
"cargoEffectResolve": false
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": 15,
|
|
122
|
+
"positionBound": true,
|
|
123
|
+
"mobility": false,
|
|
124
|
+
"consumer": false,
|
|
125
|
+
"isTerminal": false,
|
|
126
|
+
"capsPlan": false,
|
|
127
|
+
"cargoEffectResolve": false
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"type": 16,
|
|
131
|
+
"positionBound": false,
|
|
132
|
+
"mobility": false,
|
|
133
|
+
"consumer": false,
|
|
134
|
+
"isTerminal": false,
|
|
135
|
+
"capsPlan": false,
|
|
136
|
+
"cargoEffectResolve": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"type": 17,
|
|
140
|
+
"positionBound": true,
|
|
141
|
+
"mobility": false,
|
|
142
|
+
"consumer": true,
|
|
143
|
+
"isTerminal": false,
|
|
144
|
+
"capsPlan": false,
|
|
145
|
+
"cargoEffectResolve": false
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"type": 18,
|
|
149
|
+
"positionBound": true,
|
|
150
|
+
"mobility": false,
|
|
151
|
+
"consumer": false,
|
|
152
|
+
"isTerminal": false,
|
|
153
|
+
"capsPlan": false,
|
|
154
|
+
"cargoEffectResolve": true
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": 20,
|
|
158
|
+
"positionBound": false,
|
|
159
|
+
"mobility": false,
|
|
160
|
+
"consumer": true,
|
|
161
|
+
"isTerminal": false,
|
|
162
|
+
"capsPlan": false,
|
|
163
|
+
"cargoEffectResolve": false
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"type": 21,
|
|
167
|
+
"positionBound": true,
|
|
168
|
+
"mobility": false,
|
|
169
|
+
"consumer": true,
|
|
170
|
+
"isTerminal": false,
|
|
171
|
+
"capsPlan": false,
|
|
172
|
+
"cargoEffectResolve": false
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"type": 22,
|
|
176
|
+
"positionBound": true,
|
|
177
|
+
"mobility": false,
|
|
178
|
+
"consumer": false,
|
|
179
|
+
"isTerminal": false,
|
|
180
|
+
"capsPlan": false,
|
|
181
|
+
"cargoEffectResolve": false
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
package/src/entities/makers.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {getKindMeta, getTemplateMeta} from '../data/kind-registry'
|
|
|
6
6
|
import type {EntityTypeName} from '../data/kind-registry'
|
|
7
7
|
import {getEntityLayout} from '../data/recipes-runtime'
|
|
8
8
|
import type {EntitySlot} from '../data/recipes-runtime'
|
|
9
|
-
import {
|
|
9
|
+
import {getItemFamily} from '../data/metadata'
|
|
10
10
|
import {getItem} from '../data/catalog'
|
|
11
11
|
import {getModuleCapabilityType, moduleAccepts, moduleSlotTypeToCode} from '../capabilities/modules'
|
|
12
12
|
import {computeEntityCapabilities} from '../derivation/capabilities'
|
|
@@ -52,7 +52,7 @@ function assignModulesToSlots(
|
|
|
52
52
|
try {
|
|
53
53
|
modName = getItem(mod.itemId).name
|
|
54
54
|
} catch {
|
|
55
|
-
modName =
|
|
55
|
+
modName = getItemFamily(mod.itemId)?.name ?? `item ${mod.itemId}`
|
|
56
56
|
}
|
|
57
57
|
throw new Error(
|
|
58
58
|
`No compatible slot for module ${modName} (type ${modType}) on ${entityLabel}`
|
package/src/index-module.ts
CHANGED
|
@@ -124,6 +124,8 @@ export {
|
|
|
124
124
|
categoryFromIndex,
|
|
125
125
|
categoryLabelFromIndex,
|
|
126
126
|
} from './data/catalog'
|
|
127
|
+
export {getItemFamily, itemFamilies, itemFamilyKey} from './data/metadata'
|
|
128
|
+
export type {ItemFamily} from './data/metadata'
|
|
127
129
|
export {getCurrentEpoch, getEpochInfo} from './scheduling/epoch'
|
|
128
130
|
export type {EpochInfo} from './scheduling/epoch'
|
|
129
131
|
export {
|
|
@@ -374,12 +376,18 @@ export {
|
|
|
374
376
|
derivedLoaders,
|
|
375
377
|
estimateUnwrapDuration,
|
|
376
378
|
incomingHoldMass,
|
|
379
|
+
projectCargomass,
|
|
377
380
|
projectedPeakCargomass,
|
|
378
381
|
receiveFits,
|
|
379
382
|
unwrapLoadDuration,
|
|
380
383
|
unwrapTransitDuration,
|
|
381
384
|
} from './scheduling/unwrap'
|
|
382
|
-
export type {
|
|
385
|
+
export type {
|
|
386
|
+
CargomassProjection,
|
|
387
|
+
DerivedLoaders,
|
|
388
|
+
UnwrapDestination,
|
|
389
|
+
UnwrapItem,
|
|
390
|
+
} from './scheduling/unwrap'
|
|
383
391
|
|
|
384
392
|
export {
|
|
385
393
|
projectedCargoAvailableAt,
|
package/src/managers/actions.ts
CHANGED
|
@@ -610,6 +610,18 @@ export class ActionsManager extends BaseManager {
|
|
|
610
610
|
})
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
blenddepot(
|
|
614
|
+
depotId: UInt64Type,
|
|
615
|
+
owner: NameType,
|
|
616
|
+
inputs: ServerContract.ActionParams.Type.cargo_item[]
|
|
617
|
+
): Action {
|
|
618
|
+
return this.server.action('blenddepot', {
|
|
619
|
+
depot_id: UInt64.from(depotId),
|
|
620
|
+
owner: Name.from(owner),
|
|
621
|
+
inputs,
|
|
622
|
+
})
|
|
623
|
+
}
|
|
624
|
+
|
|
613
625
|
deploy(
|
|
614
626
|
entityId: UInt64Type,
|
|
615
627
|
ref: ServerContract.ActionParams.Type.cargo_ref,
|
|
@@ -4,7 +4,7 @@ import type {ResourceCategory} from '../types'
|
|
|
4
4
|
import {getItem, getModules} from '../data/catalog'
|
|
5
5
|
import {ENTITY_SHIP, getPackedEntityType} from '../data/kind-registry'
|
|
6
6
|
import {getEntityLayout} from '../data/recipes-runtime'
|
|
7
|
-
import {entityMetadata,
|
|
7
|
+
import {entityMetadata, getItemFamily} from '../data/metadata'
|
|
8
8
|
import {
|
|
9
9
|
getModuleCapabilityType,
|
|
10
10
|
isModuleItem,
|
|
@@ -370,7 +370,7 @@ function resolveEntity(
|
|
|
370
370
|
modName = modItem.name
|
|
371
371
|
modTier = modItem.tier
|
|
372
372
|
} catch {
|
|
373
|
-
modName =
|
|
373
|
+
modName = getItemFamily(modItemId)?.name ?? 'Module'
|
|
374
374
|
}
|
|
375
375
|
const group = computeCapabilityGroup(modType, decodedStats, modTier, slot.outputPct)
|
|
376
376
|
return {
|
|
@@ -5,8 +5,14 @@ import {
|
|
|
5
5
|
unwrapLoadDuration,
|
|
6
6
|
estimateUnwrapDuration,
|
|
7
7
|
incomingHoldMass,
|
|
8
|
+
projectCargomass,
|
|
8
9
|
projectedPeakCargomass,
|
|
9
10
|
} from './unwrap'
|
|
11
|
+
import {TimePoint, UInt8, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
12
|
+
import {ServerContract} from '../contracts'
|
|
13
|
+
import {getItem} from '../data/catalog'
|
|
14
|
+
import {ITEM_BEAM} from '../data/item-ids'
|
|
15
|
+
import {TaskType} from '../types'
|
|
10
16
|
|
|
11
17
|
describe('unwrap duration mirror', () => {
|
|
12
18
|
test('derivedLoaders aggregates lanes like derived_loaders()', () => {
|
|
@@ -84,3 +90,57 @@ test('projectedPeakCargomass tracks the running peak from cargomass', () => {
|
|
|
84
90
|
// No pending tasks: peak = base + candidate add.
|
|
85
91
|
expect(projectedPeakCargomass(entity, new Date(0), 500)).toBe(1500)
|
|
86
92
|
})
|
|
93
|
+
|
|
94
|
+
const DEPOSIT_START = new Date('2026-09-20T07:48:37.000Z')
|
|
95
|
+
const BEAM_QTY = 2_500
|
|
96
|
+
const BEAM_MASS = getItem(ITEM_BEAM).mass
|
|
97
|
+
|
|
98
|
+
function unloadingShip(projectedAtMs?: number) {
|
|
99
|
+
const cargo = ServerContract.Types.cargo_item.from({
|
|
100
|
+
item_id: UInt16.from(ITEM_BEAM),
|
|
101
|
+
quantity: UInt32.from(BEAM_QTY),
|
|
102
|
+
stats: UInt64.from(0),
|
|
103
|
+
modules: [],
|
|
104
|
+
})
|
|
105
|
+
const lane = ServerContract.Types.lane.from({
|
|
106
|
+
lane_key: UInt8.from(0),
|
|
107
|
+
schedule: ServerContract.Types.schedule.from({
|
|
108
|
+
started: TimePoint.fromMilliseconds(DEPOSIT_START.getTime()),
|
|
109
|
+
tasks: [
|
|
110
|
+
ServerContract.Types.task.from({
|
|
111
|
+
type: UInt8.from(TaskType.CIVIC_DEPOSIT),
|
|
112
|
+
duration: UInt32.from(1_309),
|
|
113
|
+
cancelable: UInt8.from(2),
|
|
114
|
+
cargo: [cargo],
|
|
115
|
+
couplings: [],
|
|
116
|
+
}),
|
|
117
|
+
],
|
|
118
|
+
}),
|
|
119
|
+
})
|
|
120
|
+
return {
|
|
121
|
+
cargomass: BEAM_QTY * BEAM_MASS,
|
|
122
|
+
lanes: [lane],
|
|
123
|
+
holds: [],
|
|
124
|
+
projected_at:
|
|
125
|
+
projectedAtMs === undefined ? undefined : TimePoint.fromMilliseconds(projectedAtMs),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const UNLOAD_ENDS = new Date(DEPOSIT_START.getTime() + 1_309_000)
|
|
130
|
+
const AFTER_UNLOAD = new Date(UNLOAD_ENDS.getTime() + 60_000)
|
|
131
|
+
|
|
132
|
+
test('projectCargomass reports the mass held at the candidate and the peak around it', () => {
|
|
133
|
+
const plan = projectCargomass(unloadingShip(), AFTER_UNLOAD, 400 * BEAM_MASS)
|
|
134
|
+
// The queued unload empties the hold before the candidate lands.
|
|
135
|
+
expect(plan.used).toBe(400 * BEAM_MASS)
|
|
136
|
+
expect(plan.peak).toBe(BEAM_QTY * BEAM_MASS)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('a task already applied to a projected row is not replayed', () => {
|
|
140
|
+
const applied = unloadingShip(UNLOAD_ENDS.getTime())
|
|
141
|
+
applied.cargomass = 0
|
|
142
|
+
const plan = projectCargomass(applied, AFTER_UNLOAD, 400 * BEAM_MASS)
|
|
143
|
+
expect(plan.used).toBe(400 * BEAM_MASS)
|
|
144
|
+
expect(plan.peak).toBe(400 * BEAM_MASS)
|
|
145
|
+
expect(projectedPeakCargomass(applied, AFTER_UNLOAD, 400 * BEAM_MASS)).toBe(plan.peak)
|
|
146
|
+
})
|
package/src/scheduling/unwrap.ts
CHANGED
|
@@ -133,28 +133,44 @@ function cargoListMass(items: CargoItem[]): number {
|
|
|
133
133
|
return m
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
export
|
|
137
|
-
|
|
136
|
+
export interface CargomassProjection {
|
|
137
|
+
used: number
|
|
138
|
+
peak: number
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function projectCargomass(
|
|
142
|
+
entity: sched.AnchoredScheduleData & {cargomass: number | {toNumber(): number}},
|
|
138
143
|
at: Date,
|
|
139
144
|
addMass: number,
|
|
140
145
|
removeMass = 0
|
|
141
|
-
):
|
|
142
|
-
const events: {t: number; delta: number}[] = []
|
|
143
|
-
for (const ordered of sched.
|
|
146
|
+
): CargomassProjection {
|
|
147
|
+
const events: {t: number; delta: number; candidate: boolean}[] = []
|
|
148
|
+
for (const ordered of sched.unappliedTasks(entity)) {
|
|
144
149
|
const eff = taskCargoEffect(ordered.task)
|
|
145
150
|
const delta = cargoListMass(eff.added) - cargoListMass(eff.removed)
|
|
146
|
-
events.push({t: ordered.completesAt.getTime(), delta})
|
|
151
|
+
events.push({t: ordered.completesAt.getTime(), delta, candidate: false})
|
|
147
152
|
}
|
|
148
|
-
events.push({t: at.getTime(), delta: addMass - removeMass})
|
|
153
|
+
events.push({t: at.getTime(), delta: addMass - removeMass, candidate: true})
|
|
149
154
|
events.sort((a, b) => (a.t !== b.t ? a.t - b.t : b.delta - a.delta))
|
|
150
155
|
let running = Number(entity.cargomass)
|
|
151
156
|
let peak = running
|
|
157
|
+
let used = running
|
|
152
158
|
for (const e of events) {
|
|
153
159
|
running += e.delta
|
|
154
160
|
if (running < 0) running = 0
|
|
155
161
|
if (running > peak) peak = running
|
|
162
|
+
if (e.candidate) used = running
|
|
156
163
|
}
|
|
157
|
-
return Math.min(peak, 0xffff_ffff)
|
|
164
|
+
return {used: Math.min(used, 0xffff_ffff), peak: Math.min(peak, 0xffff_ffff)}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function projectedPeakCargomass(
|
|
168
|
+
entity: sched.AnchoredScheduleData & {cargomass: number | {toNumber(): number}},
|
|
169
|
+
at: Date,
|
|
170
|
+
addMass: number,
|
|
171
|
+
removeMass = 0
|
|
172
|
+
): number {
|
|
173
|
+
return projectCargomass(entity, at, addMass, removeMass).peak
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
export function receiveFits(
|