@shipload/sdk 1.0.0-next.7 → 1.0.0-next.71
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/scan.d.ts +52 -0
- package/lib/scan.js +162 -0
- package/lib/scan.js.map +1 -0
- package/lib/scan.m.js +152 -0
- package/lib/scan.m.js.map +1 -0
- package/lib/shipload.d.ts +5822 -1484
- package/lib/shipload.js +20838 -5419
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +20674 -5669
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1691 -0
- package/lib/testing.js +7109 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +7103 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +20 -2
- package/src/capabilities/craftable.test.ts +82 -0
- package/src/capabilities/craftable.ts +82 -0
- package/src/capabilities/crafting.test.ts +80 -0
- package/src/capabilities/crafting.ts +50 -8
- package/src/capabilities/gathering.test.ts +29 -0
- package/src/capabilities/gathering.ts +38 -20
- package/src/capabilities/hauling.ts +0 -5
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +27 -30
- package/src/capabilities/movement.ts +1 -1
- package/src/capabilities/storage.test.ts +26 -0
- package/src/capabilities/storage.ts +22 -7
- package/src/contracts/fund.ts +306 -0
- package/src/contracts/platform.ts +312 -3
- package/src/contracts/server.ts +2793 -478
- package/src/contracts/token.ts +170 -0
- package/src/contracts.ts +2 -0
- package/src/coordinates/address.ts +88 -0
- package/src/coordinates/constants.test.ts +15 -0
- package/src/coordinates/constants.ts +23 -0
- package/src/coordinates/index.ts +15 -0
- package/src/coordinates/memo.test.ts +47 -0
- package/src/coordinates/memo.ts +20 -0
- package/src/coordinates/permutation.ts +77 -0
- package/src/coordinates/regions.ts +48 -0
- package/src/coordinates/sectors.ts +115 -0
- package/src/data/capabilities.ts +49 -18
- package/src/data/capability-formulas.ts +26 -14
- package/src/data/catalog.test.ts +19 -0
- package/src/data/catalog.ts +13 -3
- package/src/data/charters.json +396 -0
- package/src/data/citizenry-adjectives.json +42 -0
- package/src/data/citizenry-nouns.json +50 -0
- package/src/data/colors.ts +14 -32
- package/src/data/entities.json +421 -15
- package/src/data/item-ids.ts +53 -13
- package/src/data/items.json +330 -77
- package/src/data/kind-registry.json +212 -0
- package/src/data/kind-registry.ts +192 -0
- package/src/data/metadata.ts +312 -51
- package/src/data/recipes-runtime.ts +6 -23
- package/src/data/recipes.json +2173 -173
- package/src/data/tiers.ts +9 -6
- package/src/derivation/build-methods.test.ts +71 -0
- package/src/derivation/build-methods.ts +50 -0
- package/src/derivation/capabilities.test.ts +348 -0
- package/src/derivation/capabilities.ts +707 -0
- package/src/derivation/capability-mappings.ts +60 -16
- package/src/derivation/crafting.test.ts +17 -0
- package/src/derivation/crafting.ts +57 -34
- package/src/derivation/index.ts +27 -2
- package/src/derivation/recipe-usage.test.ts +88 -0
- package/src/derivation/recipe-usage.ts +141 -0
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +9 -1
- package/src/derivation/rollups.test.ts +55 -0
- package/src/derivation/rollups.ts +72 -0
- package/src/derivation/stars.test.ts +67 -0
- package/src/derivation/stars.ts +25 -0
- package/src/derivation/stat-scaling.ts +12 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/strata.ts +5 -3
- package/src/derivation/stratum.ts +26 -22
- package/src/derivation/tiers.ts +40 -7
- package/src/derivation/upgrades.ts +14 -0
- package/src/derivation/wormhole.ts +154 -0
- package/src/entities/entity.ts +102 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +144 -136
- package/src/entities/slot-multiplier.ts +43 -0
- package/src/entity/hydrate.test.ts +156 -0
- package/src/entity/hydrate.ts +86 -0
- package/src/errors.ts +21 -16
- package/src/format.ts +42 -9
- package/src/index-module.ts +425 -32
- package/src/influence/ballot.test.ts +103 -0
- package/src/influence/ballot.ts +98 -0
- package/src/influence/categories.ts +32 -0
- package/src/influence/charter-metadata.test.ts +136 -0
- package/src/influence/charter-metadata.ts +236 -0
- package/src/influence/charters.test.ts +112 -0
- package/src/influence/charters.ts +150 -0
- package/src/influence/citizenry.ts +38 -0
- package/src/influence/civic-shuttle.test.ts +202 -0
- package/src/influence/civic-shuttle.ts +142 -0
- package/src/influence/civic.test.ts +287 -0
- package/src/influence/civic.ts +269 -0
- package/src/influence/constants.ts +84 -0
- package/src/influence/decay.ts +20 -0
- package/src/influence/decomp.ts +95 -0
- package/src/influence/demand.ts +106 -0
- package/src/influence/duration.ts +101 -0
- package/src/influence/index.ts +118 -0
- package/src/influence/influence.test.ts +450 -0
- package/src/influence/quality.ts +25 -0
- package/src/influence/valuation.ts +154 -0
- package/src/managers/actions.ts +950 -93
- package/src/managers/balances.test.ts +161 -0
- package/src/managers/balances.ts +93 -0
- package/src/managers/base.ts +10 -2
- package/src/managers/cluster.test.ts +39 -0
- package/src/managers/cluster.ts +53 -0
- package/src/managers/construction-types.ts +80 -0
- package/src/managers/construction.ts +453 -0
- package/src/managers/context.ts +58 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +35 -63
- package/src/managers/epochs.ts +72 -1
- package/src/managers/index.ts +38 -1
- package/src/managers/influence.test.ts +56 -0
- package/src/managers/influence.ts +425 -0
- package/src/managers/jobs.test.ts +96 -0
- package/src/managers/jobs.ts +58 -0
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.test.ts +21 -0
- package/src/managers/nft.ts +110 -0
- package/src/managers/players.ts +25 -0
- package/src/managers/plot.ts +122 -0
- package/src/nft/atomicassets.abi.json +1342 -0
- package/src/nft/atomicassets.ts +237 -0
- package/src/nft/atomicdata.ts +130 -0
- package/src/nft/buildImmutableData.ts +388 -0
- package/src/nft/description.ts +222 -100
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +296 -0
- package/src/planner/planner.test.ts +459 -0
- package/src/receipts.ts +22 -0
- package/src/resolution/describe-module.ts +43 -25
- package/src/resolution/display-name.ts +39 -11
- package/src/resolution/resolve-item.test.ts +48 -0
- package/src/resolution/resolve-item.ts +112 -58
- package/src/scan/index.ts +244 -0
- package/src/scan/scan-wasm.base64.ts +2 -0
- package/src/scheduling/accessor.ts +65 -23
- package/src/scheduling/availability.test.ts +320 -0
- package/src/scheduling/availability.ts +251 -0
- package/src/scheduling/cancel.test.ts +550 -0
- package/src/scheduling/cancel.ts +254 -0
- package/src/scheduling/cluster-stock.test.ts +31 -0
- package/src/scheduling/cluster-stock.ts +15 -0
- package/src/scheduling/energy.ts +47 -0
- package/src/scheduling/epoch.ts +1 -0
- package/src/scheduling/idle-resolve.ts +45 -0
- package/src/scheduling/jobs.test.ts +448 -0
- package/src/scheduling/jobs.ts +343 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +250 -0
- package/src/scheduling/lanes.ts +279 -0
- package/src/scheduling/projection.ts +265 -149
- package/src/scheduling/schedule.test.ts +163 -0
- package/src/scheduling/schedule.ts +282 -116
- package/src/scheduling/task-cargo.test.ts +110 -0
- package/src/scheduling/task-cargo.ts +62 -0
- package/src/scheduling/task-effects.test.ts +35 -0
- package/src/scheduling/task-effects.ts +34 -0
- package/src/scheduling/unwrap.test.ts +86 -0
- package/src/scheduling/unwrap.ts +190 -0
- package/src/shipload.ts +63 -4
- package/src/subscriptions/manager.cluster.test.ts +51 -0
- package/src/subscriptions/manager.ts +245 -172
- package/src/subscriptions/mappers.ts +5 -8
- package/src/subscriptions/types.ts +28 -3
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +167 -0
- package/src/travel/reach.test.ts +86 -0
- package/src/travel/reach.ts +34 -0
- package/src/travel/route-build.test.ts +63 -0
- package/src/travel/route-build.ts +60 -0
- package/src/travel/route-planner.ts +288 -0
- package/src/travel/route-simulator.ts +170 -0
- package/src/travel/travel.ts +190 -123
- package/src/types/capabilities.ts +37 -8
- package/src/types/entity.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types.ts +81 -23
- package/src/utils/cargo.test.ts +14 -0
- package/src/utils/cargo.ts +2 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/hash.ts +22 -2
- package/src/utils/system.ts +24 -5
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -123
- package/src/entities/ship-deploy.ts +0 -295
- package/src/entities/ship.ts +0 -221
- package/src/entities/warehouse.ts +0 -127
- package/src/types/entity-traits.ts +0 -69
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import type {GathererStats} from '../types/capabilities'
|
|
2
|
+
import type {ServerContract} from '../contracts'
|
|
3
|
+
import {calc_gather_duration, calc_gather_energy} from '../capabilities/gathering'
|
|
4
|
+
import {calc_rechargetime} from '../travel/travel'
|
|
5
|
+
import {projectRemainingAt, type Projectable} from '../scheduling/projection'
|
|
6
|
+
import {selectGatherLane} from '../scheduling/lanes'
|
|
7
|
+
|
|
8
|
+
export type GatherLane = ServerContract.Types.gatherer_lane
|
|
9
|
+
|
|
10
|
+
export interface LanePlanEntry {
|
|
11
|
+
slot: number
|
|
12
|
+
quantity: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type PlanTarget = {quantity: number} | 'max'
|
|
16
|
+
|
|
17
|
+
export interface GatherPlanEntity extends Projectable {
|
|
18
|
+
gatherer_lanes: ServerContract.Types.gatherer_lane[]
|
|
19
|
+
loader_lanes: ServerContract.Types.loader_lane[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface GatherLimpet {
|
|
23
|
+
slot: number
|
|
24
|
+
quantity: number
|
|
25
|
+
durationSeconds: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GatherCycle {
|
|
29
|
+
rechargeBefore: boolean
|
|
30
|
+
rechargeSeconds: number
|
|
31
|
+
limpets: GatherLimpet[]
|
|
32
|
+
gatherSeconds: number
|
|
33
|
+
batchOre: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type FillCap = 'reserve' | 'hold' | 'requested'
|
|
37
|
+
|
|
38
|
+
export interface GatherPlan {
|
|
39
|
+
cycles: GatherCycle[]
|
|
40
|
+
cycleCount: number
|
|
41
|
+
totalOre: number
|
|
42
|
+
totalSeconds: number
|
|
43
|
+
cap: FillCap
|
|
44
|
+
reachingCount: number
|
|
45
|
+
totalLimpets: number
|
|
46
|
+
warnings: string[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface BuildGatherPlanOpts {
|
|
50
|
+
richness: number
|
|
51
|
+
itemMass: number
|
|
52
|
+
holdRoom: number
|
|
53
|
+
reserveRemaining: number
|
|
54
|
+
now: Date
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const MAX_CYCLES = 10_000
|
|
58
|
+
|
|
59
|
+
const MAX_TRANSFER_QTY = 10000
|
|
60
|
+
|
|
61
|
+
export function allocateProportional(
|
|
62
|
+
lanes: {slot: number; weight: number}[],
|
|
63
|
+
total: number
|
|
64
|
+
): LanePlanEntry[] {
|
|
65
|
+
if (lanes.length === 0) return []
|
|
66
|
+
const weightSum = lanes.reduce((s, l) => s + l.weight, 0)
|
|
67
|
+
if (weightSum === 0) return []
|
|
68
|
+
|
|
69
|
+
const entries: LanePlanEntry[] = lanes.map((l) => ({
|
|
70
|
+
slot: l.slot,
|
|
71
|
+
quantity: Math.floor((total * l.weight) / weightSum),
|
|
72
|
+
}))
|
|
73
|
+
|
|
74
|
+
let remainder = total - entries.reduce((s, e) => s + e.quantity, 0)
|
|
75
|
+
for (let i = 0; remainder > 0; i = (i + 1) % entries.length) {
|
|
76
|
+
entries[i].quantity++
|
|
77
|
+
remainder--
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return entries
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function laneStats(lane: ServerContract.Types.gatherer_lane): GathererStats {
|
|
84
|
+
return lane as unknown as GathererStats
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function gatherEnergyCost(
|
|
88
|
+
lane: ServerContract.Types.gatherer_lane,
|
|
89
|
+
quantity: number,
|
|
90
|
+
stratum: number,
|
|
91
|
+
itemMass: number,
|
|
92
|
+
richness: number
|
|
93
|
+
): number {
|
|
94
|
+
if (quantity <= 0) return 0
|
|
95
|
+
const dur = Number(calc_gather_duration(laneStats(lane), itemMass, quantity, stratum, richness))
|
|
96
|
+
return Number(calc_gather_energy(laneStats(lane), dur))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function splitCost(
|
|
100
|
+
reaching: ServerContract.Types.gatherer_lane[],
|
|
101
|
+
quantity: number,
|
|
102
|
+
stratum: number,
|
|
103
|
+
itemMass: number,
|
|
104
|
+
richness: number
|
|
105
|
+
): number {
|
|
106
|
+
if (quantity <= 0) return 0
|
|
107
|
+
const weights = reaching.map((l) => ({
|
|
108
|
+
slot: l.slot_index.toNumber(),
|
|
109
|
+
weight: l.yield.toNumber(),
|
|
110
|
+
}))
|
|
111
|
+
const split = allocateProportional(weights, quantity)
|
|
112
|
+
return split.reduce((sum, e) => {
|
|
113
|
+
const lane = reaching.find((l) => l.slot_index.toNumber() === e.slot)!
|
|
114
|
+
return sum + gatherEnergyCost(lane, e.quantity, stratum, itemMass, richness)
|
|
115
|
+
}, 0)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Binary search is exact because splitCost is monotonic non-decreasing in Q.
|
|
119
|
+
export function maxQtyForCharge(
|
|
120
|
+
reaching: ServerContract.Types.gatherer_lane[],
|
|
121
|
+
hi: number,
|
|
122
|
+
capacity: number,
|
|
123
|
+
stratum: number,
|
|
124
|
+
itemMass: number,
|
|
125
|
+
richness: number
|
|
126
|
+
): number {
|
|
127
|
+
if (hi <= 0) return 0
|
|
128
|
+
if (splitCost(reaching, hi, stratum, itemMass, richness) <= capacity) return hi
|
|
129
|
+
let lo = 0
|
|
130
|
+
let high = hi
|
|
131
|
+
while (lo < high) {
|
|
132
|
+
const mid = Math.ceil((lo + high) / 2)
|
|
133
|
+
if (splitCost(reaching, mid, stratum, itemMass, richness) <= capacity) lo = mid
|
|
134
|
+
else high = mid - 1
|
|
135
|
+
}
|
|
136
|
+
return lo
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function buildGatherPlan(
|
|
140
|
+
entity: GatherPlanEntity,
|
|
141
|
+
stratum: number,
|
|
142
|
+
target: PlanTarget,
|
|
143
|
+
opts: BuildGatherPlanOpts
|
|
144
|
+
): GatherPlan {
|
|
145
|
+
const {richness, itemMass, holdRoom, reserveRemaining, now} = opts
|
|
146
|
+
const warnings: string[] = []
|
|
147
|
+
|
|
148
|
+
const reaching = entity.gatherer_lanes.filter((l) => l.depth.toNumber() >= stratum)
|
|
149
|
+
if (reaching.length === 0) throw new Error('no gatherer reaches this stratum')
|
|
150
|
+
if (!entity.generator) throw new Error('entity has no generator')
|
|
151
|
+
|
|
152
|
+
const blocked = entity.gatherer_lanes.length - reaching.length
|
|
153
|
+
if (blocked > 0) {
|
|
154
|
+
warnings.push(
|
|
155
|
+
`${blocked} of ${entity.gatherer_lanes.length} limpets can't reach this depth`
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const capacity = entity.generator.capacity.toNumber()
|
|
160
|
+
const rechargeRate = entity.generator.recharge.toNumber()
|
|
161
|
+
let energy = Number(projectRemainingAt(entity, now).energy)
|
|
162
|
+
|
|
163
|
+
const requested = target === 'max' ? Infinity : target.quantity
|
|
164
|
+
let fillTarget = requested
|
|
165
|
+
let cap: FillCap = 'requested'
|
|
166
|
+
if (holdRoom < fillTarget) {
|
|
167
|
+
fillTarget = holdRoom
|
|
168
|
+
cap = 'hold'
|
|
169
|
+
}
|
|
170
|
+
if (reserveRemaining < fillTarget) {
|
|
171
|
+
fillTarget = reserveRemaining
|
|
172
|
+
cap = 'reserve'
|
|
173
|
+
}
|
|
174
|
+
fillTarget = Math.max(0, Math.floor(fillTarget))
|
|
175
|
+
|
|
176
|
+
const cycles: GatherCycle[] = []
|
|
177
|
+
let remaining = fillTarget
|
|
178
|
+
let guard = 0
|
|
179
|
+
while (remaining > 0 && guard++ < MAX_CYCLES) {
|
|
180
|
+
const batch = maxQtyForCharge(reaching, remaining, capacity, stratum, itemMass, richness)
|
|
181
|
+
if (batch <= 0) {
|
|
182
|
+
warnings.push('a single gather cannot fit within one full charge')
|
|
183
|
+
break
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const costFull = splitCost(reaching, batch, stratum, itemMass, richness)
|
|
187
|
+
const rechargeBefore = energy < costFull
|
|
188
|
+
const rechargeSeconds = rechargeBefore
|
|
189
|
+
? Number(calc_rechargetime(capacity, energy, rechargeRate))
|
|
190
|
+
: 0
|
|
191
|
+
if (rechargeBefore) energy = capacity
|
|
192
|
+
|
|
193
|
+
const weights = reaching.map((l) => ({
|
|
194
|
+
slot: l.slot_index.toNumber(),
|
|
195
|
+
weight: l.yield.toNumber(),
|
|
196
|
+
}))
|
|
197
|
+
const split = allocateProportional(weights, batch).filter((e) => e.quantity > 0)
|
|
198
|
+
const limpets: GatherLimpet[] = split.map((e) => {
|
|
199
|
+
const lane = reaching.find((l) => l.slot_index.toNumber() === e.slot)!
|
|
200
|
+
const dur = Number(
|
|
201
|
+
calc_gather_duration(laneStats(lane), itemMass, e.quantity, stratum, richness)
|
|
202
|
+
)
|
|
203
|
+
return {slot: e.slot, quantity: e.quantity, durationSeconds: dur}
|
|
204
|
+
})
|
|
205
|
+
const actualCost = limpets.reduce((sum, l) => {
|
|
206
|
+
const lane = reaching.find((r) => r.slot_index.toNumber() === l.slot)!
|
|
207
|
+
return sum + Number(calc_gather_energy(laneStats(lane), l.durationSeconds))
|
|
208
|
+
}, 0)
|
|
209
|
+
energy = Math.max(0, energy - actualCost)
|
|
210
|
+
|
|
211
|
+
const gatherSeconds = limpets.reduce((m, l) => Math.max(m, l.durationSeconds), 0)
|
|
212
|
+
cycles.push({rechargeBefore, rechargeSeconds, limpets, gatherSeconds, batchOre: batch})
|
|
213
|
+
remaining -= batch
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const totalOre = cycles.reduce((s, c) => s + c.batchOre, 0)
|
|
217
|
+
const totalSeconds = cycles.reduce((s, c) => s + c.rechargeSeconds + c.gatherSeconds, 0)
|
|
218
|
+
return {
|
|
219
|
+
cycles,
|
|
220
|
+
cycleCount: cycles.length,
|
|
221
|
+
totalOre,
|
|
222
|
+
totalSeconds,
|
|
223
|
+
cap,
|
|
224
|
+
reachingCount: reaching.length,
|
|
225
|
+
totalLimpets: entity.gatherer_lanes.length,
|
|
226
|
+
warnings,
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface SingleGatherPlan {
|
|
231
|
+
laneKey: number
|
|
232
|
+
quantity: number
|
|
233
|
+
energyCost: number
|
|
234
|
+
needsRecharge: boolean
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// None of these are PRECISION-scaled: stratum/itemMass/richness/energy fields are plain units, same as maxQtyForCharge/splitCost.
|
|
238
|
+
export interface SingleGatherInput {
|
|
239
|
+
modules: ServerContract.Types.module_entry[]
|
|
240
|
+
entityItemId: number
|
|
241
|
+
lanes: ServerContract.Types.lane[]
|
|
242
|
+
gathererLanes: GatherLane[]
|
|
243
|
+
stratum: number
|
|
244
|
+
desiredQuantity: number
|
|
245
|
+
itemMass: number
|
|
246
|
+
richness: number
|
|
247
|
+
generatorCapacity: number
|
|
248
|
+
currentEnergy: number
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function planSingleGather(opts: SingleGatherInput): SingleGatherPlan {
|
|
252
|
+
const {
|
|
253
|
+
modules,
|
|
254
|
+
entityItemId,
|
|
255
|
+
lanes,
|
|
256
|
+
gathererLanes,
|
|
257
|
+
stratum,
|
|
258
|
+
desiredQuantity,
|
|
259
|
+
itemMass,
|
|
260
|
+
richness,
|
|
261
|
+
generatorCapacity,
|
|
262
|
+
currentEnergy,
|
|
263
|
+
} = opts
|
|
264
|
+
|
|
265
|
+
const laneKey = selectGatherLane(modules, entityItemId, lanes, stratum)
|
|
266
|
+
const lane = gathererLanes.find((l) => l.slot_index.toNumber() === laneKey - 1)
|
|
267
|
+
if (!lane) throw new Error('gatherer lane not found for selected slot')
|
|
268
|
+
|
|
269
|
+
const quantity = maxQtyForCharge(
|
|
270
|
+
[lane],
|
|
271
|
+
desiredQuantity,
|
|
272
|
+
generatorCapacity,
|
|
273
|
+
stratum,
|
|
274
|
+
itemMass,
|
|
275
|
+
richness
|
|
276
|
+
)
|
|
277
|
+
const energyCost = splitCost([lane], quantity, stratum, itemMass, richness)
|
|
278
|
+
return {laneKey, quantity, energyCost, needsRecharge: currentEnergy < energyCost}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function planParallelTransfer(
|
|
282
|
+
entity: GatherPlanEntity,
|
|
283
|
+
target: PlanTarget
|
|
284
|
+
): LanePlanEntry[] {
|
|
285
|
+
const lanes = entity.loader_lanes.filter((l) => l.thrust.toNumber() > 0)
|
|
286
|
+
if (lanes.length === 0) return []
|
|
287
|
+
|
|
288
|
+
const requestedQty = target === 'max' ? MAX_TRANSFER_QTY : target.quantity
|
|
289
|
+
|
|
290
|
+
const laneWeights = lanes.map((l) => ({
|
|
291
|
+
slot: l.slot_index.toNumber(),
|
|
292
|
+
weight: l.thrust.toNumber(),
|
|
293
|
+
}))
|
|
294
|
+
|
|
295
|
+
return allocateProportional(laneWeights, requestedQty).filter((e) => e.quantity > 0)
|
|
296
|
+
}
|