@shipload/sdk 1.0.0-next.6 → 1.0.0-next.60
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 +3589 -1363
- package/lib/shipload.js +15700 -5454
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +15423 -5402
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1173 -0
- package/lib/testing.js +4947 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +4941 -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 +35 -0
- package/src/capabilities/crafting.ts +34 -7
- package/src/capabilities/gathering.test.ts +29 -0
- package/src/capabilities/gathering.ts +37 -19
- package/src/capabilities/hauling.ts +0 -5
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +42 -0
- package/src/capabilities/movement.ts +1 -1
- package/src/capabilities/storage.ts +16 -1
- package/src/contracts/platform.ts +231 -3
- package/src/contracts/server.ts +1518 -501
- 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.ts +0 -5
- package/src/data/colors.ts +13 -47
- package/src/data/entities.json +379 -14
- package/src/data/item-ids.ts +48 -12
- package/src/data/items.json +301 -74
- package/src/data/kind-registry.json +195 -0
- package/src/data/kind-registry.ts +182 -0
- package/src/data/metadata.ts +277 -48
- package/src/data/recipes-runtime.ts +6 -23
- package/src/data/recipes.json +2074 -173
- package/src/derivation/build-methods.test.ts +13 -0
- package/src/derivation/build-methods.ts +48 -0
- package/src/derivation/capabilities.test.ts +348 -0
- package/src/derivation/capabilities.ts +692 -0
- package/src/derivation/capability-mappings.ts +60 -16
- package/src/derivation/crafting.test.ts +17 -0
- package/src/derivation/crafting.ts +56 -33
- 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/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 +141 -135
- package/src/entities/slot-multiplier.ts +43 -0
- package/src/errors.ts +12 -16
- package/src/format.ts +26 -4
- package/src/index-module.ts +333 -35
- package/src/managers/actions.ts +668 -103
- package/src/managers/base.ts +6 -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 +443 -0
- package/src/managers/context.ts +29 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +27 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +20 -1
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.test.ts +14 -0
- package/src/managers/nft.ts +70 -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 +385 -0
- package/src/nft/description.ts +225 -52
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +242 -0
- package/src/planner/planner.test.ts +334 -0
- package/src/resolution/describe-module.ts +43 -25
- package/src/resolution/display-name.ts +38 -10
- 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 +204 -0
- package/src/scheduling/availability.ts +211 -0
- package/src/scheduling/cancel.test.ts +542 -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/idle-resolve.ts +45 -0
- package/src/scheduling/jobs.ts +71 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +250 -0
- package/src/scheduling/lanes.ts +227 -0
- package/src/scheduling/projection.ts +257 -133
- package/src/scheduling/schedule.test.ts +119 -0
- package/src/scheduling/schedule.ts +257 -117
- package/src/scheduling/task-cargo.test.ts +44 -0
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/scheduling/unwrap.test.ts +86 -0
- package/src/scheduling/unwrap.ts +190 -0
- package/src/shipload.ts +26 -1
- 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.ts +21 -0
- package/src/travel/route-planner.ts +288 -0
- package/src/travel/route-simulator.ts +170 -0
- package/src/travel/travel.ts +188 -122
- 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 +51 -16
- package/src/utils/cargo.test.ts +14 -0
- package/src/utils/cargo.ts +29 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/system.ts +15 -16
- 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
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {Name,
|
|
1
|
+
import {Name, type UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
|
-
import {Coordinates,
|
|
3
|
+
import {Coordinates, TaskType} from '../types'
|
|
4
4
|
import {
|
|
5
|
-
capsHasLoaders,
|
|
6
5
|
capsHasMovement,
|
|
7
6
|
capsHasStorage,
|
|
8
7
|
type EntityCapabilities,
|
|
@@ -14,38 +13,47 @@ import {
|
|
|
14
13
|
RECIPE_INPUTS_INSUFFICIENT,
|
|
15
14
|
RECIPE_INPUTS_INVALID,
|
|
16
15
|
RECIPE_NOT_FOUND,
|
|
17
|
-
|
|
16
|
+
ENTITY_CARGO_NOT_LOADED,
|
|
18
17
|
} from '../errors'
|
|
19
|
-
import {getRecipe, type RecipeInput} from '../data/recipes-runtime'
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
18
|
+
import {getEntityLayout, getRecipe, type RecipeInput} from '../data/recipes-runtime'
|
|
19
|
+
import {ITEM_SHIP_T1_PACKED} from '../data/item-ids'
|
|
20
|
+
import {computeEntityCapabilities} from '../derivation/capabilities'
|
|
21
|
+
import {decodeCraftedItemStats, decodeStat} from '../derivation/crafting'
|
|
22
|
+
import {packedModulesToInstalled, type InstalledModule} from '../entities/slot-multiplier'
|
|
23
|
+
import {lerp} from '../travel/travel'
|
|
22
24
|
import {
|
|
23
25
|
calcStacksMass,
|
|
24
26
|
cargoItemToStack,
|
|
25
27
|
type CargoStack,
|
|
26
28
|
mergeStacks,
|
|
27
|
-
|
|
29
|
+
subtractFromStacks,
|
|
28
30
|
stackToCargoItem,
|
|
29
31
|
} from '../capabilities/storage'
|
|
32
|
+
import {craftCargoOwnership} from './availability'
|
|
30
33
|
import * as schedule from './schedule'
|
|
31
34
|
import type {ScheduleData} from './schedule'
|
|
32
35
|
|
|
33
36
|
export interface ProjectedEntity {
|
|
34
37
|
location: Coordinates
|
|
35
|
-
energy:
|
|
38
|
+
energy: UInt32
|
|
36
39
|
cargo: CargoStack[]
|
|
37
40
|
shipMass: UInt32
|
|
38
41
|
capacity?: UInt64
|
|
39
42
|
engines?: ServerContract.Types.movement_stats
|
|
40
|
-
|
|
43
|
+
loaderLanes: ServerContract.Types.loader_lane[]
|
|
41
44
|
generator?: ServerContract.Types.energy_stats
|
|
42
45
|
hauler?: ServerContract.Types.hauler_stats
|
|
46
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
43
47
|
readonly cargoMass: UInt64
|
|
44
48
|
readonly totalMass: UInt64
|
|
49
|
+
readonly gathererLanes: ServerContract.Types.gatherer_lane[]
|
|
50
|
+
readonly crafterLanes: ServerContract.Types.crafter_lane[]
|
|
51
|
+
readonly builderLanes: ServerContract.Types.builder_lane[]
|
|
45
52
|
|
|
46
53
|
hasMovement(): boolean
|
|
47
54
|
hasStorage(): boolean
|
|
48
55
|
hasLoaders(): boolean
|
|
56
|
+
hasLauncher(): boolean
|
|
49
57
|
|
|
50
58
|
capabilities(): EntityCapabilities
|
|
51
59
|
state(): EntityState
|
|
@@ -53,53 +61,210 @@ export interface ProjectedEntity {
|
|
|
53
61
|
|
|
54
62
|
export interface Projectable extends ScheduleData {
|
|
55
63
|
coordinates: Coordinates | ServerContract.Types.coordinates
|
|
56
|
-
energy?:
|
|
64
|
+
energy?: UInt32
|
|
57
65
|
hullmass?: UInt32
|
|
58
66
|
generator?: ServerContract.Types.energy_stats
|
|
59
67
|
engines?: ServerContract.Types.movement_stats
|
|
60
|
-
|
|
68
|
+
loader_lanes?: ServerContract.Types.loader_lane[]
|
|
69
|
+
gatherer_lanes?: ServerContract.Types.gatherer_lane[]
|
|
70
|
+
crafter_lanes?: ServerContract.Types.crafter_lane[]
|
|
71
|
+
builder_lanes?: ServerContract.Types.builder_lane[]
|
|
61
72
|
hauler?: ServerContract.Types.hauler_stats
|
|
73
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
62
74
|
capacity?: UInt32
|
|
63
75
|
cargo: ServerContract.Types.cargo_item[]
|
|
64
76
|
cargomass: UInt32
|
|
65
77
|
owner?: Name
|
|
78
|
+
stats?: bigint
|
|
79
|
+
item_id?: number | UInt16
|
|
80
|
+
modules?: ServerContract.Types.module_entry[] | InstalledModule[]
|
|
66
81
|
}
|
|
67
82
|
|
|
68
|
-
function
|
|
69
|
-
|
|
83
|
+
function toInstalledModules(
|
|
84
|
+
modules: ServerContract.Types.module_entry[] | InstalledModule[]
|
|
85
|
+
): InstalledModule[] {
|
|
86
|
+
if (modules.length > 0 && 'itemId' in modules[0]) {
|
|
87
|
+
return modules as InstalledModule[]
|
|
88
|
+
}
|
|
89
|
+
return packedModulesToInstalled(modules as ServerContract.Types.module_entry[])
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface ProjectedCaps {
|
|
93
|
+
hullmass?: UInt32
|
|
94
|
+
capacity?: UInt32
|
|
95
|
+
engines?: ServerContract.Types.movement_stats
|
|
96
|
+
generator?: ServerContract.Types.energy_stats
|
|
97
|
+
loaderLanes: ServerContract.Types.loader_lane[]
|
|
98
|
+
gathererLanes: ServerContract.Types.gatherer_lane[]
|
|
99
|
+
crafterLanes: ServerContract.Types.crafter_lane[]
|
|
100
|
+
builderLanes: ServerContract.Types.builder_lane[]
|
|
101
|
+
hauler?: ServerContract.Types.hauler_stats
|
|
102
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function recomputeCaps(entity: Projectable): ProjectedCaps | undefined {
|
|
106
|
+
if (
|
|
107
|
+
entity.item_id === undefined ||
|
|
108
|
+
entity.modules === undefined ||
|
|
109
|
+
entity.stats === undefined
|
|
110
|
+
) {
|
|
111
|
+
return undefined
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const itemId = Number(
|
|
115
|
+
typeof entity.item_id === 'number' ? entity.item_id : entity.item_id.value
|
|
116
|
+
)
|
|
117
|
+
const hullStats = decodeCraftedItemStats(itemId, entity.stats)
|
|
118
|
+
if (hullStats.strength === undefined) hullStats.strength = decodeStat(entity.stats, 0)
|
|
119
|
+
if (hullStats.hardness === undefined) hullStats.hardness = decodeStat(entity.stats, 2)
|
|
120
|
+
// The retired Ship T1 recipe only assigned names to its first two stat slots.
|
|
121
|
+
// Its on-chain entity row still carries five packed channels, and the ship hull
|
|
122
|
+
// formula deliberately consumes all five. Keep the unlabelled channels internal
|
|
123
|
+
// to projection so replay remains contract-parity until deployment replaces it.
|
|
124
|
+
if (itemId === ITEM_SHIP_T1_PACKED) {
|
|
125
|
+
hullStats.__legacyShipChannel3 = decodeStat(entity.stats, 3)
|
|
126
|
+
hullStats.__legacyShipChannel4 = decodeStat(entity.stats, 4)
|
|
127
|
+
}
|
|
128
|
+
const layout = getEntityLayout(itemId)?.slots ?? []
|
|
129
|
+
const installed = toInstalledModules(entity.modules)
|
|
130
|
+
const caps = computeEntityCapabilities(hullStats, itemId, installed, layout)
|
|
131
|
+
|
|
132
|
+
const toLoaderLane = (l: {
|
|
133
|
+
slotIndex: number
|
|
134
|
+
mass: number
|
|
135
|
+
thrust: number
|
|
136
|
+
outputPct: number
|
|
137
|
+
}): ServerContract.Types.loader_lane =>
|
|
138
|
+
ServerContract.Types.loader_lane.from({
|
|
139
|
+
slot_index: l.slotIndex,
|
|
140
|
+
mass: l.mass,
|
|
141
|
+
thrust: l.thrust,
|
|
142
|
+
output_pct: l.outputPct,
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const toGathererLane = (l: {
|
|
146
|
+
slotIndex: number
|
|
147
|
+
yield: number
|
|
148
|
+
drain: number
|
|
149
|
+
depth: number
|
|
150
|
+
outputPct: number
|
|
151
|
+
}): ServerContract.Types.gatherer_lane =>
|
|
152
|
+
ServerContract.Types.gatherer_lane.from({
|
|
153
|
+
slot_index: l.slotIndex,
|
|
154
|
+
yield: l.yield,
|
|
155
|
+
drain: l.drain,
|
|
156
|
+
depth: l.depth,
|
|
157
|
+
output_pct: l.outputPct,
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
const toCrafterLane = (l: {
|
|
161
|
+
slotIndex: number
|
|
162
|
+
speed: number
|
|
163
|
+
drain: number
|
|
164
|
+
outputPct: number
|
|
165
|
+
}): ServerContract.Types.crafter_lane =>
|
|
166
|
+
ServerContract.Types.crafter_lane.from({
|
|
167
|
+
slot_index: l.slotIndex,
|
|
168
|
+
speed: l.speed,
|
|
169
|
+
drain: l.drain,
|
|
170
|
+
output_pct: l.outputPct,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const toBuilderLane = (l: {
|
|
174
|
+
slotIndex: number
|
|
175
|
+
speed: number
|
|
176
|
+
drain: number
|
|
177
|
+
outputPct: number
|
|
178
|
+
}): ServerContract.Types.builder_lane =>
|
|
179
|
+
ServerContract.Types.builder_lane.from({
|
|
180
|
+
slot_index: l.slotIndex,
|
|
181
|
+
speed: l.speed,
|
|
182
|
+
drain: l.drain,
|
|
183
|
+
output_pct: l.outputPct,
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
hullmass: UInt32.from(caps.hullmass),
|
|
188
|
+
capacity: UInt32.from(caps.capacity),
|
|
189
|
+
engines: caps.engines ? ServerContract.Types.movement_stats.from(caps.engines) : undefined,
|
|
190
|
+
generator: caps.generator
|
|
191
|
+
? ServerContract.Types.energy_stats.from(caps.generator)
|
|
192
|
+
: undefined,
|
|
193
|
+
loaderLanes: (caps.loaderLanes ?? []).map(toLoaderLane),
|
|
194
|
+
gathererLanes: (caps.gathererLanes ?? []).map(toGathererLane),
|
|
195
|
+
crafterLanes: (caps.crafterLanes ?? []).map(toCrafterLane),
|
|
196
|
+
builderLanes: (caps.builderLanes ?? []).map(toBuilderLane),
|
|
197
|
+
hauler: caps.hauler
|
|
198
|
+
? ServerContract.Types.hauler_stats.from({
|
|
199
|
+
capacity: caps.hauler.capacity,
|
|
200
|
+
efficiency: caps.hauler.efficiency,
|
|
201
|
+
drain: caps.hauler.drain,
|
|
202
|
+
capacity_by_tier: caps.hauler.capacityByTier,
|
|
203
|
+
})
|
|
204
|
+
: undefined,
|
|
205
|
+
launcher: caps.launcher
|
|
206
|
+
? ServerContract.Types.launcher_stats.from({
|
|
207
|
+
charge_rate: caps.launcher.chargeRate,
|
|
208
|
+
velocity: caps.launcher.velocity,
|
|
209
|
+
drain: caps.launcher.drain,
|
|
210
|
+
})
|
|
211
|
+
: undefined,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function loaderLanesTotalMass(lanes: ServerContract.Types.loader_lane[]): UInt64 {
|
|
216
|
+
let total = 0
|
|
217
|
+
for (const l of lanes) total += Number(l.mass)
|
|
218
|
+
return UInt64.from(total)
|
|
70
219
|
}
|
|
71
220
|
|
|
72
221
|
export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
222
|
+
const needsRecompute =
|
|
223
|
+
entity.hullmass === undefined ||
|
|
224
|
+
entity.loader_lanes === undefined ||
|
|
225
|
+
entity.engines === undefined ||
|
|
226
|
+
entity.generator === undefined ||
|
|
227
|
+
entity.hauler === undefined ||
|
|
228
|
+
entity.launcher === undefined ||
|
|
229
|
+
entity.capacity === undefined
|
|
230
|
+
const caps = needsRecompute ? recomputeCaps(entity) : undefined
|
|
231
|
+
|
|
232
|
+
const shipMass = UInt32.from(entity.hullmass ?? caps?.hullmass ?? 0)
|
|
233
|
+
const loaderLanes = entity.loader_lanes ?? caps?.loaderLanes ?? []
|
|
234
|
+
const gathererLanes = entity.gatherer_lanes ?? caps?.gathererLanes ?? []
|
|
235
|
+
const crafterLanes = entity.crafter_lanes ?? caps?.crafterLanes ?? []
|
|
236
|
+
const builderLanes = entity.builder_lanes ?? caps?.builderLanes ?? []
|
|
237
|
+
const engines = entity.engines ?? caps?.engines
|
|
238
|
+
const generator = entity.generator ?? caps?.generator
|
|
239
|
+
const hauler = entity.hauler ?? caps?.hauler
|
|
240
|
+
const launcher = entity.launcher ?? caps?.launcher
|
|
241
|
+
const capacity = entity.capacity ?? caps?.capacity
|
|
79
242
|
|
|
80
243
|
const cargo: CargoStack[] = entity.cargo.map(cargoItemToStack)
|
|
81
244
|
|
|
82
245
|
const projected: ProjectedEntity = {
|
|
83
246
|
location: Coordinates.from(entity.coordinates),
|
|
84
|
-
energy:
|
|
247
|
+
energy: UInt32.from(entity.energy ?? 0),
|
|
85
248
|
cargo,
|
|
86
249
|
shipMass,
|
|
87
250
|
capacity: capacity ? UInt64.from(capacity) : undefined,
|
|
88
251
|
engines,
|
|
89
252
|
generator,
|
|
90
253
|
hauler,
|
|
91
|
-
|
|
254
|
+
launcher,
|
|
255
|
+
loaderLanes,
|
|
256
|
+
gathererLanes,
|
|
257
|
+
crafterLanes,
|
|
258
|
+
builderLanes,
|
|
92
259
|
|
|
93
260
|
get cargoMass() {
|
|
94
261
|
return calcStacksMass(this.cargo)
|
|
95
262
|
},
|
|
96
263
|
|
|
97
264
|
get totalMass() {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
return mass
|
|
265
|
+
return UInt64.from(this.shipMass)
|
|
266
|
+
.adding(this.cargoMass)
|
|
267
|
+
.adding(loaderLanesTotalMass(this.loaderLanes))
|
|
103
268
|
},
|
|
104
269
|
|
|
105
270
|
hasMovement() {
|
|
@@ -111,7 +276,11 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
111
276
|
},
|
|
112
277
|
|
|
113
278
|
hasLoaders() {
|
|
114
|
-
return
|
|
279
|
+
return this.loaderLanes.length > 0
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
hasLauncher() {
|
|
283
|
+
return this.launcher !== undefined
|
|
115
284
|
},
|
|
116
285
|
|
|
117
286
|
capabilities(): EntityCapabilities {
|
|
@@ -120,7 +289,7 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
120
289
|
capacity: this.capacity ? UInt32.from(this.capacity) : undefined,
|
|
121
290
|
engines: this.engines,
|
|
122
291
|
generator: this.generator,
|
|
123
|
-
|
|
292
|
+
launcher: this.launcher,
|
|
124
293
|
}
|
|
125
294
|
},
|
|
126
295
|
|
|
@@ -146,12 +315,12 @@ function applyRechargeTask(
|
|
|
146
315
|
if (!projected.generator) return
|
|
147
316
|
|
|
148
317
|
if (options.complete) {
|
|
149
|
-
projected.energy =
|
|
318
|
+
projected.energy = UInt32.from(projected.generator.capacity)
|
|
150
319
|
} else if (options.progress !== undefined) {
|
|
151
320
|
const capacity = Number(projected.generator.capacity)
|
|
152
321
|
const currentEnergy = Number(projected.energy)
|
|
153
322
|
const rechargeAmount = (capacity - currentEnergy) * options.progress
|
|
154
|
-
projected.energy =
|
|
323
|
+
projected.energy = UInt32.from(Math.min(capacity, currentEnergy + rechargeAmount))
|
|
155
324
|
}
|
|
156
325
|
}
|
|
157
326
|
|
|
@@ -160,28 +329,25 @@ function applyFlightTask(
|
|
|
160
329
|
task: ServerContract.Types.task,
|
|
161
330
|
options: {complete: boolean; progress?: number}
|
|
162
331
|
): void {
|
|
163
|
-
if (!task.coordinates
|
|
332
|
+
if (!task.coordinates) return
|
|
164
333
|
|
|
165
|
-
const origin = projected.location
|
|
166
334
|
const destination = Coordinates.from(task.coordinates)
|
|
167
|
-
const distance = distanceBetweenCoordinates(origin, task.coordinates)
|
|
168
|
-
const energyUsage = distance.dividing(PRECISION).multiplying(projected.engines.drain)
|
|
169
335
|
|
|
170
336
|
if (options.complete) {
|
|
171
|
-
projected
|
|
172
|
-
? UInt16.from(projected.energy.subtracting(energyUsage))
|
|
173
|
-
: UInt16.from(0)
|
|
337
|
+
applyEnergyCost(projected, task)
|
|
174
338
|
projected.location = destination
|
|
175
339
|
} else if (options.progress !== undefined) {
|
|
176
|
-
const interpolated = lerp(
|
|
340
|
+
const interpolated = lerp(projected.location, destination, options.progress)
|
|
177
341
|
projected.location = Coordinates.from({
|
|
178
342
|
x: Math.round(interpolated.x),
|
|
179
343
|
y: Math.round(interpolated.y),
|
|
180
344
|
})
|
|
181
|
-
const partialEnergy = UInt64.from(
|
|
345
|
+
const partialEnergy = UInt64.from(
|
|
346
|
+
Math.floor(Number(task.energy_cost ?? 0) * options.progress)
|
|
347
|
+
)
|
|
182
348
|
projected.energy = projected.energy.gt(partialEnergy)
|
|
183
|
-
?
|
|
184
|
-
:
|
|
349
|
+
? UInt32.from(projected.energy.subtracting(partialEnergy))
|
|
350
|
+
: UInt32.from(0)
|
|
185
351
|
}
|
|
186
352
|
}
|
|
187
353
|
|
|
@@ -190,7 +356,7 @@ function addCargoItem(projected: ProjectedEntity, item: ServerContract.Types.car
|
|
|
190
356
|
}
|
|
191
357
|
|
|
192
358
|
function removeCargoItem(projected: ProjectedEntity, item: ServerContract.Types.cargo_item): void {
|
|
193
|
-
projected.cargo =
|
|
359
|
+
projected.cargo = subtractFromStacks(projected.cargo, cargoItemToStack(item))
|
|
194
360
|
}
|
|
195
361
|
|
|
196
362
|
function applyAddCargoTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
@@ -207,10 +373,10 @@ function applyRemoveCargoTask(projected: ProjectedEntity, task: ServerContract.T
|
|
|
207
373
|
|
|
208
374
|
function applyEnergyCost(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
209
375
|
if (!task.energy_cost) return
|
|
210
|
-
const energyCost =
|
|
376
|
+
const energyCost = UInt32.from(task.energy_cost)
|
|
211
377
|
projected.energy = projected.energy.gt(energyCost)
|
|
212
|
-
?
|
|
213
|
-
:
|
|
378
|
+
? UInt32.from(projected.energy.subtracting(energyCost))
|
|
379
|
+
: UInt32.from(0)
|
|
214
380
|
}
|
|
215
381
|
|
|
216
382
|
function applyGatherTask(
|
|
@@ -220,7 +386,7 @@ function applyGatherTask(
|
|
|
220
386
|
): void {
|
|
221
387
|
if (!options.complete) return
|
|
222
388
|
applyEnergyCost(projected, task)
|
|
223
|
-
if (
|
|
389
|
+
if (task.couplings.length === 0) {
|
|
224
390
|
applyAddCargoTask(projected, task)
|
|
225
391
|
}
|
|
226
392
|
}
|
|
@@ -229,16 +395,14 @@ function applyCraftTask(projected: ProjectedEntity, task: ServerContract.Types.t
|
|
|
229
395
|
applyEnergyCost(projected, task)
|
|
230
396
|
if (task.cargo.length === 0) return
|
|
231
397
|
|
|
232
|
-
|
|
233
|
-
|
|
398
|
+
const {clustered, ownOutput} = craftCargoOwnership(task)
|
|
399
|
+
if (!clustered) {
|
|
400
|
+
for (let i = 0; i < task.cargo.length - 1; i++) {
|
|
401
|
+
removeCargoItem(projected, task.cargo[i])
|
|
402
|
+
}
|
|
234
403
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
function applyDeployTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
|
|
239
|
-
applyEnergyCost(projected, task)
|
|
240
|
-
if (task.cargo.length > 0) {
|
|
241
|
-
removeCargoItem(projected, task.cargo[0])
|
|
404
|
+
if (ownOutput) {
|
|
405
|
+
addCargoItem(projected, task.cargo[task.cargo.length - 1])
|
|
242
406
|
}
|
|
243
407
|
}
|
|
244
408
|
|
|
@@ -248,6 +412,8 @@ function applyTask(projected: ProjectedEntity, task: ServerContract.Types.task):
|
|
|
248
412
|
applyRechargeTask(projected, task, {complete: true})
|
|
249
413
|
break
|
|
250
414
|
case TaskType.TRAVEL:
|
|
415
|
+
case TaskType.WARP:
|
|
416
|
+
case TaskType.TRANSIT:
|
|
251
417
|
applyFlightTask(projected, task, {complete: true})
|
|
252
418
|
break
|
|
253
419
|
case TaskType.LOAD:
|
|
@@ -255,7 +421,6 @@ function applyTask(projected: ProjectedEntity, task: ServerContract.Types.task):
|
|
|
255
421
|
applyAddCargoTask(projected, task)
|
|
256
422
|
break
|
|
257
423
|
case TaskType.UNLOAD:
|
|
258
|
-
case TaskType.WRAP:
|
|
259
424
|
applyRemoveCargoTask(projected, task)
|
|
260
425
|
break
|
|
261
426
|
case TaskType.GATHER:
|
|
@@ -264,11 +429,7 @@ function applyTask(projected: ProjectedEntity, task: ServerContract.Types.task):
|
|
|
264
429
|
case TaskType.CRAFT:
|
|
265
430
|
applyCraftTask(projected, task)
|
|
266
431
|
break
|
|
267
|
-
case TaskType.DEPLOY:
|
|
268
|
-
applyDeployTask(projected, task)
|
|
269
|
-
break
|
|
270
432
|
case TaskType.UNDEPLOY:
|
|
271
|
-
case TaskType.WRAP_ENTITY:
|
|
272
433
|
case TaskType.DEMOLISH:
|
|
273
434
|
break
|
|
274
435
|
}
|
|
@@ -280,50 +441,27 @@ export interface ProjectionOptions {
|
|
|
280
441
|
|
|
281
442
|
export function projectEntity(entity: Projectable, options?: ProjectionOptions): ProjectedEntity {
|
|
282
443
|
const projected = createProjectedEntity(entity)
|
|
283
|
-
|
|
444
|
+
const ordered = schedule.orderedTasks(entity)
|
|
445
|
+
if (ordered.length === 0) return projected
|
|
284
446
|
|
|
285
|
-
const tasks = entity.schedule.tasks
|
|
286
447
|
const taskCount =
|
|
287
448
|
options?.upToTaskIndex !== undefined
|
|
288
|
-
? Math.max(0, Math.min(options.upToTaskIndex,
|
|
289
|
-
:
|
|
449
|
+
? Math.max(0, Math.min(options.upToTaskIndex, ordered.length))
|
|
450
|
+
: ordered.length
|
|
290
451
|
|
|
291
452
|
for (let i = 0; i < taskCount; i++) {
|
|
292
|
-
applyTask(projected,
|
|
453
|
+
applyTask(projected, ordered[i].task)
|
|
293
454
|
}
|
|
294
455
|
return projected
|
|
295
456
|
}
|
|
296
457
|
|
|
297
|
-
export
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function buildRemainingProjectable(snapshot: ProjectableSnapshot): Projectable | null {
|
|
303
|
-
if (!snapshot.schedule) return null
|
|
304
|
-
const remainingTasks: ServerContract.Types.task[] = []
|
|
305
|
-
if (snapshot.current_task) remainingTasks.push(snapshot.current_task)
|
|
306
|
-
if (snapshot.pending_tasks?.length) remainingTasks.push(...snapshot.pending_tasks)
|
|
307
|
-
if (remainingTasks.length === 0) return null
|
|
308
|
-
|
|
309
|
-
const completedCount = snapshot.schedule.tasks.length - remainingTasks.length
|
|
310
|
-
let startedMs = snapshot.schedule.started.toMilliseconds()
|
|
311
|
-
for (let i = 0; i < completedCount; i++) {
|
|
312
|
-
startedMs += snapshot.schedule.tasks[i].duration.toNumber() * 1000
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
...snapshot,
|
|
317
|
-
schedule: ServerContract.Types.schedule.from({
|
|
318
|
-
started: TimePoint.fromMilliseconds(startedMs),
|
|
319
|
-
tasks: remainingTasks,
|
|
320
|
-
}),
|
|
458
|
+
export function projectRemainingAt(entity: Projectable, _now: Date): ProjectedEntity {
|
|
459
|
+
// Resolve is lazy/entity-global: completed tasks are unsettled until resolve, so replay all.
|
|
460
|
+
const projected = createProjectedEntity(entity)
|
|
461
|
+
for (const {task} of schedule.orderedTasks(entity)) {
|
|
462
|
+
applyTask(projected, task)
|
|
321
463
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
export function projectFromCurrentState(snapshot: ProjectableSnapshot): ProjectedEntity {
|
|
325
|
-
const projectable = buildRemainingProjectable(snapshot)
|
|
326
|
-
return projectable ? projectEntity(projectable) : createProjectedEntity(snapshot)
|
|
464
|
+
return projected
|
|
327
465
|
}
|
|
328
466
|
|
|
329
467
|
function getRecipeInputsForOutput(outputItemId: number): RecipeInput[] | undefined {
|
|
@@ -346,19 +484,10 @@ function validateCraftTask(task: ServerContract.Types.task, projected: Projected
|
|
|
346
484
|
let matched = false
|
|
347
485
|
for (let ri = 0; ri < recipe.length; ri++) {
|
|
348
486
|
const req = recipe[ri]
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
break
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
const item = getItem(input.item_id)
|
|
357
|
-
if (item.category === req.category && item.tier === req.tier) {
|
|
358
|
-
groupedInputs[ri].push(input)
|
|
359
|
-
matched = true
|
|
360
|
-
break
|
|
361
|
-
}
|
|
487
|
+
if (input.item_id.toNumber() === req.itemId) {
|
|
488
|
+
groupedInputs[ri].push(input)
|
|
489
|
+
matched = true
|
|
490
|
+
break
|
|
362
491
|
}
|
|
363
492
|
}
|
|
364
493
|
if (!matched) throw new Error(RECIPE_INPUTS_INVALID)
|
|
@@ -389,15 +518,16 @@ function validateCraftTask(task: ServerContract.Types.task, projected: Projected
|
|
|
389
518
|
break
|
|
390
519
|
}
|
|
391
520
|
}
|
|
392
|
-
if (!found) throw new Error(
|
|
521
|
+
if (!found) throw new Error(ENTITY_CARGO_NOT_LOADED)
|
|
393
522
|
}
|
|
394
523
|
}
|
|
395
524
|
|
|
396
525
|
export function validateSchedule(entity: Projectable): void {
|
|
397
|
-
|
|
526
|
+
const ordered = schedule.orderedTasks(entity)
|
|
527
|
+
if (ordered.length === 0) return
|
|
398
528
|
|
|
399
529
|
const projected = createProjectedEntity(entity)
|
|
400
|
-
for (const task of
|
|
530
|
+
for (const {task} of ordered) {
|
|
401
531
|
if (task.type.toNumber() === TaskType.CRAFT) {
|
|
402
532
|
validateCraftTask(task, projected)
|
|
403
533
|
}
|
|
@@ -411,28 +541,35 @@ export function validateSchedule(entity: Projectable): void {
|
|
|
411
541
|
export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity {
|
|
412
542
|
const projected = createProjectedEntity(entity)
|
|
413
543
|
|
|
414
|
-
|
|
544
|
+
const ordered = schedule.orderedTasks(entity)
|
|
545
|
+
if (ordered.length === 0) {
|
|
415
546
|
return projected
|
|
416
547
|
}
|
|
417
548
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const
|
|
549
|
+
const nowMs = now.getTime()
|
|
550
|
+
|
|
551
|
+
for (const {task, startsAt} of ordered) {
|
|
552
|
+
const duration = task.duration.toNumber()
|
|
553
|
+
const elapsed = Math.min(
|
|
554
|
+
Math.max(0, Math.floor((nowMs - startsAt.getTime()) / 1000)),
|
|
555
|
+
duration
|
|
556
|
+
)
|
|
557
|
+
const taskComplete = elapsed >= duration
|
|
558
|
+
const taskInProgress = elapsed > 0 && elapsed < duration
|
|
422
559
|
|
|
423
560
|
if (!taskComplete && !taskInProgress) {
|
|
424
|
-
|
|
561
|
+
continue
|
|
425
562
|
}
|
|
426
563
|
|
|
427
|
-
const progress = taskInProgress
|
|
428
|
-
? schedule.getTaskElapsed(entity, i, now) / task.duration.toNumber()
|
|
429
|
-
: undefined
|
|
564
|
+
const progress = taskInProgress ? elapsed / duration : undefined
|
|
430
565
|
|
|
431
566
|
switch (task.type.toNumber()) {
|
|
432
567
|
case TaskType.RECHARGE:
|
|
433
568
|
applyRechargeTask(projected, task, {complete: taskComplete, progress})
|
|
434
569
|
break
|
|
435
570
|
case TaskType.TRAVEL:
|
|
571
|
+
case TaskType.WARP:
|
|
572
|
+
case TaskType.TRANSIT:
|
|
436
573
|
applyFlightTask(projected, task, {complete: taskComplete, progress})
|
|
437
574
|
break
|
|
438
575
|
case TaskType.LOAD:
|
|
@@ -440,7 +577,6 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
440
577
|
if (taskComplete) applyAddCargoTask(projected, task)
|
|
441
578
|
break
|
|
442
579
|
case TaskType.UNLOAD:
|
|
443
|
-
case TaskType.WRAP:
|
|
444
580
|
if (taskComplete) applyRemoveCargoTask(projected, task)
|
|
445
581
|
break
|
|
446
582
|
case TaskType.GATHER:
|
|
@@ -449,11 +585,7 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
449
585
|
case TaskType.CRAFT:
|
|
450
586
|
if (taskComplete) applyCraftTask(projected, task)
|
|
451
587
|
break
|
|
452
|
-
case TaskType.DEPLOY:
|
|
453
|
-
if (taskComplete) applyDeployTask(projected, task)
|
|
454
|
-
break
|
|
455
588
|
case TaskType.UNDEPLOY:
|
|
456
|
-
case TaskType.WRAP_ENTITY:
|
|
457
589
|
case TaskType.DEMOLISH:
|
|
458
590
|
break
|
|
459
591
|
}
|
|
@@ -461,11 +593,3 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
461
593
|
|
|
462
594
|
return projected
|
|
463
595
|
}
|
|
464
|
-
|
|
465
|
-
export function projectFromCurrentStateAt(
|
|
466
|
-
snapshot: ProjectableSnapshot,
|
|
467
|
-
now: Date
|
|
468
|
-
): ProjectedEntity {
|
|
469
|
-
const projectable = buildRemainingProjectable(snapshot)
|
|
470
|
-
return projectable ? projectEntityAt(projectable, now) : createProjectedEntity(snapshot)
|
|
471
|
-
}
|