@shipload/sdk 1.0.0-next.65 → 1.0.0-next.66
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 +698 -316
- package/lib/shipload.js +2473 -1235
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2392 -1216
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +205 -146
- package/lib/testing.js +846 -556
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +846 -556
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/crafting.test.ts +51 -6
- package/src/capabilities/crafting.ts +19 -4
- package/src/capabilities/gathering.ts +2 -2
- package/src/capabilities/storage.test.ts +26 -0
- package/src/capabilities/storage.ts +6 -6
- package/src/contracts/fund.ts +79 -2
- package/src/contracts/platform.ts +10 -1
- package/src/contracts/server.ts +467 -331
- package/src/data/charters.json +325 -127
- package/src/data/entities.json +24 -24
- package/src/data/items.json +114 -114
- package/src/data/kind-registry.json +3 -3
- package/src/data/kind-registry.ts +5 -0
- package/src/data/recipes.json +56 -95
- package/src/derivation/build-methods.test.ts +59 -1
- package/src/derivation/build-methods.ts +2 -0
- package/src/derivation/capabilities.ts +7 -7
- package/src/derivation/strata.ts +5 -3
- package/src/derivation/tiers.ts +5 -5
- package/src/entity/hydrate.test.ts +156 -0
- package/src/entity/hydrate.ts +86 -0
- package/src/errors.ts +9 -0
- package/src/format.ts +15 -13
- package/src/index-module.ts +32 -5
- package/src/influence/ballot.test.ts +103 -0
- package/src/influence/ballot.ts +98 -0
- package/src/influence/charter-metadata.test.ts +136 -0
- package/src/influence/charter-metadata.ts +236 -0
- package/src/influence/charters.test.ts +51 -65
- package/src/influence/charters.ts +70 -40
- package/src/influence/civic.test.ts +278 -0
- package/src/influence/civic.ts +269 -0
- package/src/influence/constants.ts +30 -9
- package/src/influence/decomp.ts +15 -15
- package/src/influence/duration.ts +42 -6
- package/src/influence/index.ts +49 -6
- package/src/influence/influence.test.ts +76 -9
- package/src/influence/valuation.ts +17 -17
- package/src/managers/actions.ts +65 -37
- package/src/managers/base.ts +4 -0
- package/src/managers/context.ts +3 -1
- package/src/managers/index.ts +4 -2
- package/src/managers/influence.test.ts +18 -20
- package/src/managers/influence.ts +137 -84
- package/src/managers/jobs.test.ts +2 -2
- package/src/managers/jobs.ts +4 -4
- package/src/nft/description.ts +10 -11
- package/src/planner/index.ts +54 -0
- package/src/planner/planner.test.ts +127 -2
- package/src/resolution/display-name.ts +1 -1
- package/src/scheduling/availability.test.ts +113 -0
- package/src/scheduling/availability.ts +48 -8
- package/src/scheduling/jobs.ts +1 -1
- package/src/scheduling/projection.ts +2 -16
- package/src/scheduling/task-cargo.test.ts +62 -1
- package/src/scheduling/task-cargo.ts +25 -10
- package/src/scheduling/task-effects.test.ts +35 -0
- package/src/scheduling/task-effects.ts +34 -0
- package/src/scheduling/unwrap.test.ts +3 -3
- package/src/scheduling/unwrap.ts +3 -3
- package/src/shipload.ts +22 -3
- package/src/travel/reach.test.ts +86 -0
- package/src/travel/reach.ts +23 -10
- package/src/travel/route-build.test.ts +63 -0
- package/src/travel/route-build.ts +60 -0
- package/src/travel/travel.ts +2 -1
- package/src/types.ts +6 -2
- package/src/utils/hash.ts +18 -2
|
@@ -4,6 +4,7 @@ import type {ServerContract} from '../contracts'
|
|
|
4
4
|
import {coordsToLocationId, locationIdToCoords, type CoordinatesType} from '../types'
|
|
5
5
|
import {
|
|
6
6
|
type BuiltCharter,
|
|
7
|
+
type WorldBuilding,
|
|
7
8
|
citizenryName,
|
|
8
9
|
contributeDuration,
|
|
9
10
|
decayActive,
|
|
@@ -12,19 +13,20 @@ import {
|
|
|
12
13
|
valueCargoItem,
|
|
13
14
|
type DemandTriple,
|
|
14
15
|
type DemandView,
|
|
16
|
+
isCivicEntity,
|
|
15
17
|
type ValuedItem,
|
|
16
18
|
} from '../influence'
|
|
17
19
|
import {getItem} from '../data/catalog'
|
|
18
20
|
|
|
19
21
|
export interface InfluenceStanding {
|
|
20
22
|
epoch: number
|
|
21
|
-
playerLifetime: bigint
|
|
22
|
-
playerActive: bigint
|
|
23
23
|
standingLifetime: bigint
|
|
24
24
|
standingActive: bigint
|
|
25
|
+
citizenshipLifetime: bigint
|
|
26
|
+
citizenshipActive: bigint
|
|
25
27
|
locationLifetime: bigint
|
|
26
28
|
locationActive: bigint
|
|
27
|
-
|
|
29
|
+
spent: bigint
|
|
28
30
|
mandate: number
|
|
29
31
|
founder: Name
|
|
30
32
|
founded: number
|
|
@@ -33,14 +35,23 @@ export interface InfluenceStanding {
|
|
|
33
35
|
export interface CharterProgress {
|
|
34
36
|
locationId: bigint
|
|
35
37
|
lifetime: bigint
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
spent: bigint
|
|
39
|
+
unassigned: bigint
|
|
38
40
|
mandate: number
|
|
39
41
|
nextCost: bigint
|
|
40
42
|
prereqsMet: boolean
|
|
41
43
|
buildable: boolean
|
|
42
44
|
epoch: number
|
|
43
|
-
built:
|
|
45
|
+
built: BuiltCharter[]
|
|
46
|
+
ballotId: bigint
|
|
47
|
+
settling: boolean
|
|
48
|
+
queue: QueuedSeat[]
|
|
49
|
+
progress: NodeProgress[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface NodeProgress {
|
|
53
|
+
nodeId: number
|
|
54
|
+
amount: bigint
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
export interface ContributePreviewRow {
|
|
@@ -48,13 +59,13 @@ export interface ContributePreviewRow {
|
|
|
48
59
|
quantity: number
|
|
49
60
|
stats: bigint
|
|
50
61
|
valueAtomic: bigint
|
|
51
|
-
|
|
62
|
+
mass: number
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
export interface ContributePreview {
|
|
55
66
|
rows: ContributePreviewRow[]
|
|
56
67
|
totalAtomic: bigint
|
|
57
|
-
|
|
68
|
+
totalMass: number
|
|
58
69
|
durationSeconds: number
|
|
59
70
|
demand: DemandView
|
|
60
71
|
}
|
|
@@ -65,9 +76,8 @@ export interface FoundedWorld {
|
|
|
65
76
|
y: number
|
|
66
77
|
lifetime: bigint
|
|
67
78
|
active: bigint
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
chosenEpoch: number
|
|
79
|
+
spent: bigint
|
|
80
|
+
ballotId: bigint
|
|
71
81
|
mandate: number | undefined
|
|
72
82
|
founder: Name
|
|
73
83
|
founded: number
|
|
@@ -82,33 +92,43 @@ export interface FoundedWorldRef {
|
|
|
82
92
|
export interface VoteOption {
|
|
83
93
|
nodeId: number
|
|
84
94
|
cost: bigint
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
seat: number
|
|
96
|
+
weight: bigint
|
|
97
|
+
rank: number
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
export interface VoteStandings {
|
|
90
101
|
locationId: bigint
|
|
102
|
+
ballotId: bigint
|
|
91
103
|
epoch: number
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
talliesSuppressed: boolean
|
|
104
|
+
settledEpoch: number
|
|
105
|
+
seats: number
|
|
106
|
+
settling: boolean
|
|
107
|
+
queue: number[]
|
|
97
108
|
options: VoteOption[]
|
|
109
|
+
picks: number[]
|
|
98
110
|
}
|
|
99
111
|
|
|
100
|
-
export interface
|
|
112
|
+
export interface BallotVote {
|
|
101
113
|
account: Name
|
|
102
|
-
|
|
103
|
-
nodeId: number
|
|
104
|
-
weight: bigint
|
|
114
|
+
picks: number[]
|
|
105
115
|
}
|
|
106
116
|
|
|
107
|
-
export interface
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
export interface Ballot {
|
|
118
|
+
ballotId: bigint
|
|
119
|
+
kind: number
|
|
120
|
+
subject: bigint
|
|
121
|
+
seats: number
|
|
122
|
+
settledEpoch: number
|
|
123
|
+
queue: number[]
|
|
124
|
+
settling: boolean
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface QueuedSeat {
|
|
128
|
+
nodeId: number
|
|
129
|
+
cost: bigint
|
|
130
|
+
progress: bigint
|
|
131
|
+
gap: bigint
|
|
112
132
|
}
|
|
113
133
|
|
|
114
134
|
function big(value: unknown): bigint {
|
|
@@ -125,13 +145,13 @@ export class InfluenceManager extends BaseManager {
|
|
|
125
145
|
|
|
126
146
|
return {
|
|
127
147
|
epoch: Number(result.epoch),
|
|
128
|
-
playerLifetime: big(result.player_lifetime),
|
|
129
|
-
playerActive: big(result.player_active),
|
|
130
148
|
standingLifetime: big(result.standing_lifetime),
|
|
131
149
|
standingActive: big(result.standing_active),
|
|
150
|
+
citizenshipLifetime: big(result.citizenship_lifetime),
|
|
151
|
+
citizenshipActive: big(result.citizenship_active),
|
|
132
152
|
locationLifetime: big(result.location_lifetime),
|
|
133
153
|
locationActive: big(result.location_active),
|
|
134
|
-
|
|
154
|
+
spent: big(result.spent),
|
|
135
155
|
mandate: Number(result.mandate),
|
|
136
156
|
founder: Name.from(result.founder),
|
|
137
157
|
founded: Number(result.founded),
|
|
@@ -170,6 +190,17 @@ export class InfluenceManager extends BaseManager {
|
|
|
170
190
|
})
|
|
171
191
|
}
|
|
172
192
|
|
|
193
|
+
async getCivicOwner(): Promise<Name> {
|
|
194
|
+
const row = (await this.server.table('civicconfig').get()) as
|
|
195
|
+
| ServerContract.Types.civicconfig_row
|
|
196
|
+
| undefined
|
|
197
|
+
return row ? Name.from(row.civic_owner) : Name.from(this.server.account)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async isCivic(entity: {owner: NameType}): Promise<boolean> {
|
|
201
|
+
return isCivicEntity(entity, await this.getCivicOwner())
|
|
202
|
+
}
|
|
203
|
+
|
|
173
204
|
async getCitizenryName(location: CoordinatesType): Promise<string | undefined> {
|
|
174
205
|
const game = await this.getGame()
|
|
175
206
|
return citizenryName(game.config.seed, location)
|
|
@@ -195,20 +226,20 @@ export class InfluenceManager extends BaseManager {
|
|
|
195
226
|
)
|
|
196
227
|
|
|
197
228
|
let totalAtomic = 0n
|
|
198
|
-
let
|
|
229
|
+
let totalMass = 0
|
|
199
230
|
const rows = bundle.map((item) => {
|
|
200
231
|
const valueAtomic = valueCargoItem(item, demand, pricing)
|
|
201
|
-
const
|
|
232
|
+
const mass = getItem(item.itemId).mass * item.quantity
|
|
202
233
|
totalAtomic += valueAtomic
|
|
203
|
-
|
|
204
|
-
return {...item, valueAtomic,
|
|
234
|
+
totalMass += mass
|
|
235
|
+
return {...item, valueAtomic, mass}
|
|
205
236
|
})
|
|
206
237
|
|
|
207
238
|
return {
|
|
208
239
|
rows,
|
|
209
240
|
totalAtomic,
|
|
210
|
-
|
|
211
|
-
durationSeconds: contributeDuration(
|
|
241
|
+
totalMass,
|
|
242
|
+
durationSeconds: contributeDuration(totalMass, opts.altitudeZ ?? 0),
|
|
212
243
|
demand,
|
|
213
244
|
}
|
|
214
245
|
}
|
|
@@ -222,8 +253,8 @@ export class InfluenceManager extends BaseManager {
|
|
|
222
253
|
return {
|
|
223
254
|
locationId: big(result.location_id),
|
|
224
255
|
lifetime: big(result.lifetime),
|
|
225
|
-
|
|
226
|
-
|
|
256
|
+
spent: big(result.spent),
|
|
257
|
+
unassigned: big(result.unassigned),
|
|
227
258
|
mandate: Number(result.mandate),
|
|
228
259
|
nextCost: big(result.next_cost),
|
|
229
260
|
prereqsMet: Boolean(result.prereqs_met),
|
|
@@ -231,8 +262,19 @@ export class InfluenceManager extends BaseManager {
|
|
|
231
262
|
epoch: Number(result.epoch),
|
|
232
263
|
built: result.built.map((b) => ({
|
|
233
264
|
nodeId: Number(b.node_id),
|
|
234
|
-
|
|
235
|
-
|
|
265
|
+
repeats: Number(b.repeats),
|
|
266
|
+
})),
|
|
267
|
+
ballotId: big(result.ballot_id),
|
|
268
|
+
settling: Boolean(result.settling),
|
|
269
|
+
queue: result.queue.map((seat) => ({
|
|
270
|
+
nodeId: Number(seat.node_id),
|
|
271
|
+
cost: big(seat.cost),
|
|
272
|
+
progress: big(seat.progress),
|
|
273
|
+
gap: big(seat.gap),
|
|
274
|
+
})),
|
|
275
|
+
progress: result.progress.map((p) => ({
|
|
276
|
+
nodeId: Number(p.node_id),
|
|
277
|
+
amount: big(p.amount),
|
|
236
278
|
})),
|
|
237
279
|
}
|
|
238
280
|
}
|
|
@@ -272,73 +314,85 @@ export class InfluenceManager extends BaseManager {
|
|
|
272
314
|
}))
|
|
273
315
|
}
|
|
274
316
|
|
|
275
|
-
async getVotes(location: CoordinatesType): Promise<VoteStandings> {
|
|
317
|
+
async getVotes(location: CoordinatesType, player?: NameType): Promise<VoteStandings> {
|
|
276
318
|
const result = (await this.server.readonly('getvotes', {
|
|
277
319
|
x: Int64.from(location.x),
|
|
278
320
|
y: Int64.from(location.y),
|
|
321
|
+
player: Name.from(player ?? ''),
|
|
279
322
|
})) as ServerContract.Types.vote_result
|
|
280
323
|
|
|
281
|
-
const epoch = Number(result.epoch)
|
|
282
|
-
const rawBallotEpoch = Number(result.ballot_epoch)
|
|
283
|
-
const ballotEpoch = rawBallotEpoch === 0 ? undefined : rawBallotEpoch
|
|
284
|
-
const talliesSuppressed = ballotEpoch !== undefined && ballotEpoch < epoch
|
|
285
|
-
|
|
286
324
|
return {
|
|
287
325
|
locationId: big(result.location_id),
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
326
|
+
ballotId: big(result.ballot_id),
|
|
327
|
+
epoch: Number(result.epoch),
|
|
328
|
+
settledEpoch: Number(result.settled_epoch),
|
|
329
|
+
seats: Number(result.seats),
|
|
330
|
+
settling: Boolean(result.settling),
|
|
331
|
+
queue: result.queue.map((n) => Number(n)),
|
|
294
332
|
options: result.options.map((option) => ({
|
|
295
333
|
nodeId: Number(option.node_id),
|
|
296
334
|
cost: big(option.cost),
|
|
297
|
-
|
|
298
|
-
|
|
335
|
+
seat: Number(option.seat),
|
|
336
|
+
weight: big(option.weight),
|
|
337
|
+
rank: Number(option.rank),
|
|
299
338
|
})),
|
|
339
|
+
picks: result.picks.map((n) => Number(n)),
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async getBallotId(location: CoordinatesType): Promise<bigint | undefined> {
|
|
344
|
+
const row = (await this.server
|
|
345
|
+
.table('worlds')
|
|
346
|
+
.get(UInt64.from(coordsToLocationId(location)))) as
|
|
347
|
+
| ServerContract.Types.worlds_row
|
|
348
|
+
| undefined
|
|
349
|
+
return row ? big(row.ballot_id) : undefined
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async getBallot(ballotId: bigint): Promise<Ballot | undefined> {
|
|
353
|
+
const row = (await this.server.table('ballot').get(UInt64.from(ballotId))) as
|
|
354
|
+
| ServerContract.Types.ballot_row
|
|
355
|
+
| undefined
|
|
356
|
+
if (!row) return undefined
|
|
357
|
+
const epoch = Number((await this.getState()).epoch)
|
|
358
|
+
const settledEpoch = Number(row.settled_epoch)
|
|
359
|
+
return {
|
|
360
|
+
ballotId: big(row.ballot_id),
|
|
361
|
+
kind: Number(row.kind),
|
|
362
|
+
subject: big(row.subject),
|
|
363
|
+
seats: Number(row.seats),
|
|
364
|
+
settledEpoch,
|
|
365
|
+
queue: row.queue.map((n) => Number(n)),
|
|
366
|
+
settling: settledEpoch < epoch,
|
|
300
367
|
}
|
|
301
368
|
}
|
|
302
369
|
|
|
303
|
-
async
|
|
370
|
+
async getBallotVotes(ballotId: bigint): Promise<BallotVote[]> {
|
|
304
371
|
const rows = (await this.server
|
|
305
|
-
.table('
|
|
306
|
-
.all()) as ServerContract.Types.
|
|
372
|
+
.table('ballotpicks', UInt64.from(ballotId))
|
|
373
|
+
.all()) as ServerContract.Types.ballotpicks_row[]
|
|
307
374
|
return rows.map((row) => ({
|
|
308
375
|
account: Name.from(row.account),
|
|
309
|
-
|
|
310
|
-
nodeId: Number(row.node_id),
|
|
311
|
-
weight: big(row.weight),
|
|
376
|
+
picks: row.picks.map((n) => Number(n)),
|
|
312
377
|
}))
|
|
313
378
|
}
|
|
314
379
|
|
|
315
|
-
async getVoteTallies(location: CoordinatesType): Promise<{nodeId: number; total: bigint}[]> {
|
|
316
|
-
const rows = (await this.server
|
|
317
|
-
.table('inftally', coordsToLocationId(location))
|
|
318
|
-
.all()) as ServerContract.Types.inftally_row[]
|
|
319
|
-
return rows.map((row) => ({nodeId: Number(row.node_id), total: big(row.total)}))
|
|
320
|
-
}
|
|
321
|
-
|
|
322
380
|
async getBuiltCharters(location: CoordinatesType): Promise<BuiltCharter[]> {
|
|
323
381
|
const rows = (await this.server
|
|
324
|
-
.table('
|
|
325
|
-
.all()) as ServerContract.Types.
|
|
326
|
-
return rows.map((row) => ({nodeId: Number(row.node_id),
|
|
382
|
+
.table('mandates', coordsToLocationId(location))
|
|
383
|
+
.all()) as ServerContract.Types.mandates_row[]
|
|
384
|
+
return rows.map((row) => ({nodeId: Number(row.node_id), repeats: Number(row.repeats)}))
|
|
327
385
|
}
|
|
328
386
|
|
|
329
|
-
async
|
|
387
|
+
async getBuildings(location: CoordinatesType): Promise<WorldBuilding[]> {
|
|
330
388
|
const rows = (await this.server
|
|
331
|
-
.table('
|
|
332
|
-
.all()) as ServerContract.Types.
|
|
333
|
-
return rows.map((row) => ({
|
|
334
|
-
locationId: big(row.location_id),
|
|
335
|
-
...locationIdToCoords(row.location_id),
|
|
336
|
-
epoch: Number(row.epoch),
|
|
337
|
-
}))
|
|
389
|
+
.table('buildings', coordsToLocationId(location))
|
|
390
|
+
.all()) as ServerContract.Types.buildings_row[]
|
|
391
|
+
return rows.map((row) => ({entityId: big(row.entity_id), building: Number(row.building)}))
|
|
338
392
|
}
|
|
339
393
|
|
|
340
394
|
async getFoundedWorlds(opts: {withMandate?: boolean} = {}): Promise<FoundedWorld[]> {
|
|
341
|
-
const rows = (await this.server.table('
|
|
395
|
+
const rows = (await this.server.table('worlds').all()) as ServerContract.Types.worlds_row[]
|
|
342
396
|
const epoch = (await this.getState()).epoch
|
|
343
397
|
const worlds = rows.map((row) => ({
|
|
344
398
|
locationId: big(row.location_id),
|
|
@@ -346,11 +400,10 @@ export class InfluenceManager extends BaseManager {
|
|
|
346
400
|
lifetime: big(row.lifetime),
|
|
347
401
|
active: decayActive(
|
|
348
402
|
big(row.active),
|
|
349
|
-
Math.max(0, Number(epoch) - Number(row.
|
|
403
|
+
Math.max(0, Number(epoch) - Number(row.active_epoch))
|
|
350
404
|
),
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
chosenEpoch: Number(row.chosen_epoch),
|
|
405
|
+
spent: big(row.spent),
|
|
406
|
+
ballotId: big(row.ballot_id),
|
|
354
407
|
mandate: undefined as number | undefined,
|
|
355
408
|
founder: Name.from(row.founder),
|
|
356
409
|
founded: Number(row.founded),
|
|
@@ -366,7 +419,7 @@ export class InfluenceManager extends BaseManager {
|
|
|
366
419
|
|
|
367
420
|
async isFounded(location: CoordinatesType): Promise<boolean> {
|
|
368
421
|
const id = coordsToLocationId(location)
|
|
369
|
-
const row = await this.server.table('
|
|
422
|
+
const row = await this.server.table('worlds').get(UInt64.from(id))
|
|
370
423
|
return row !== undefined
|
|
371
424
|
}
|
|
372
425
|
}
|
|
@@ -5,7 +5,7 @@ import {JobsManager} from './jobs'
|
|
|
5
5
|
const OWNER = 'eggmaple.gm'
|
|
6
6
|
const row = (over: Record<string, unknown> = {}) => ({
|
|
7
7
|
id: {toNumber: () => 7},
|
|
8
|
-
|
|
8
|
+
building: {toNumber: () => 42},
|
|
9
9
|
socket: {toNumber: () => 0},
|
|
10
10
|
owner: Name.from(OWNER),
|
|
11
11
|
ship_id: {toNumber: () => 100},
|
|
@@ -33,7 +33,7 @@ describe('JobsManager.getOwnedJobs', () => {
|
|
|
33
33
|
)
|
|
34
34
|
const jobs = await m.getOwnedJobs(OWNER, {now: new Date('2026-07-26T11:30:00Z')})
|
|
35
35
|
expect(jobs).toHaveLength(1)
|
|
36
|
-
expect(jobs[0]).toMatchObject({id: 7,
|
|
36
|
+
expect(jobs[0]).toMatchObject({id: 7, building: 42, quantity: 5, status: 'ready'})
|
|
37
37
|
expect(jobs[0].coords).toEqual({x: 12, y: 34})
|
|
38
38
|
expect(jobs[0].output).toEqual({item: 'out'} as never)
|
|
39
39
|
expect(jobs[0].inputs).toEqual([{item: 'in'}] as never)
|
package/src/managers/jobs.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {BaseManager} from './base'
|
|
|
3
3
|
import {jobStatus, splitJobCargo, type OwnedJob} from '../scheduling/jobs'
|
|
4
4
|
import type {ServerContract} from '../contracts'
|
|
5
5
|
|
|
6
|
-
type JobRow = ServerContract.Types.
|
|
6
|
+
type JobRow = ServerContract.Types.craftjob_row
|
|
7
7
|
|
|
8
8
|
export class JobsManager extends BaseManager {
|
|
9
9
|
async getOwnedJobs(owner: NameType, opts?: {now?: Date}): Promise<OwnedJob[]> {
|
|
@@ -14,7 +14,7 @@ export class JobsManager extends BaseManager {
|
|
|
14
14
|
try {
|
|
15
15
|
// index_position 'tertiary' = nodeos slot 3 = owner's secondary index; no ABI metadata for it.
|
|
16
16
|
rows = (await this.server
|
|
17
|
-
.table('
|
|
17
|
+
.table('craftjobs')
|
|
18
18
|
.query({
|
|
19
19
|
index_position: 'tertiary',
|
|
20
20
|
key_type: 'i64',
|
|
@@ -23,7 +23,7 @@ export class JobsManager extends BaseManager {
|
|
|
23
23
|
})
|
|
24
24
|
.all()) as JobRow[]
|
|
25
25
|
} catch {
|
|
26
|
-
rows = (await this.server.table('
|
|
26
|
+
rows = (await this.server.table('craftjobs').all()) as JobRow[]
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
return rows.filter((r) => ownerName.equals(r.owner)).map((r) => this.parseOwnedJob(r, now))
|
|
@@ -35,7 +35,7 @@ export class JobsManager extends BaseManager {
|
|
|
35
35
|
const {output, inputs} = splitJobCargo(r.cargo)
|
|
36
36
|
return {
|
|
37
37
|
id: r.id.toNumber(),
|
|
38
|
-
|
|
38
|
+
building: r.building.toNumber(),
|
|
39
39
|
socket: r.socket.toNumber(),
|
|
40
40
|
shipId: r.ship_id.toNumber(),
|
|
41
41
|
coords: {x: r.coords.x.toNumber(), y: r.coords.y.toNumber()},
|
package/src/nft/description.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
BATTERY_CAPACITY_TIER_PCT,
|
|
29
29
|
} from '../derivation/capabilities'
|
|
30
30
|
import {getItem, tryGetItem} from '../data/catalog'
|
|
31
|
-
import type
|
|
31
|
+
import {MASS_UNITS_PER_TONNE, type ModuleType} from '../types'
|
|
32
32
|
import {ENTITY_SHIP, getPackedEntityType} from '../data/kind-registry'
|
|
33
33
|
import {getBaseHullmassFor} from '../derivation/capabilities'
|
|
34
34
|
import {computeEffectiveModuleStat} from '../derivation/stat-scaling'
|
|
@@ -41,9 +41,8 @@ export function toWholeEnergy(milli: number): number {
|
|
|
41
41
|
return idiv(milli + 500, 1000)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export function formatMassTonnes(
|
|
45
|
-
|
|
46
|
-
return `${idiv(tenths, 10)}.${tenths % 10} t`
|
|
44
|
+
export function formatMassTonnes(mass: number): string {
|
|
45
|
+
return `${idiv(mass, MASS_UNITS_PER_TONNE)}.${mass % MASS_UNITS_PER_TONNE} t`
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
function isShipHull(itemId: number): boolean {
|
|
@@ -67,27 +66,27 @@ export function computeBaseHullmass(itemId: number, stats: bigint): number {
|
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
export function computeBaseCapacityShip(stats: bigint): number {
|
|
70
|
-
return Math.floor(
|
|
69
|
+
return Math.floor(50_000 * 6 ** (sumPackedShipChannels(stats) / 4995))
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
export function computeBaseCapacityContainer(stats: bigint): number {
|
|
74
73
|
const s = decodeStat(stats, 0) + decodeStat(stats, 2)
|
|
75
|
-
return Math.floor(
|
|
74
|
+
return Math.floor(220_000 * 6 ** (s / 1998))
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
export function computeBaseCapacityWarehouse(stats: bigint): number {
|
|
79
78
|
const s = decodeStat(stats, 0) + decodeStat(stats, 2)
|
|
80
|
-
return Math.floor(
|
|
79
|
+
return Math.floor(1_000_000 * 6 ** (s / 1998))
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
export function computeBaseCapacityWorkshop(stats: bigint): number {
|
|
84
83
|
const s = decodeStat(stats, 0) + decodeStat(stats, 2)
|
|
85
|
-
return Math.floor(
|
|
84
|
+
return Math.floor(50_000 * 6 ** (s / 1998))
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
export function computeBaseCapacityDepot(stats: bigint): number {
|
|
89
88
|
const s = decodeStat(stats, 0) + decodeStat(stats, 2)
|
|
90
|
-
return Math.floor(
|
|
89
|
+
return Math.floor(500_000 * 6 ** (s / 1998))
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
const CAPACITY_FN_BY_KIND: Record<string, (stats: bigint) => number> = {
|
|
@@ -131,7 +130,7 @@ export const computeGathererDrain = (con: number): number =>
|
|
|
131
130
|
2 * Math.max(250_000, 1_250_000 - con * 1250)
|
|
132
131
|
export const computeGathererDepth = (tol: number, tier: number): number =>
|
|
133
132
|
gathererDepthForTier(tol, tier)
|
|
134
|
-
export const computeLoaderMass = (ins: number): number => Math.max(
|
|
133
|
+
export const computeLoaderMass = (ins: number): number => Math.max(2, 20 - idiv(ins, 50))
|
|
135
134
|
export const computeLoaderThrust = (pla: number, tier: number): number =>
|
|
136
135
|
idiv((1 + idiv(pla * pla, 10000)) * moduleTierPct(LOADER_THRUST_TIER_PCT, tier), 100)
|
|
137
136
|
export const computeCrafterSpeed = (rea: number, tier: number): number =>
|
|
@@ -164,7 +163,7 @@ export const computeCargoBayCapacity = (
|
|
|
164
163
|
tier: number
|
|
165
164
|
): number =>
|
|
166
165
|
idiv(
|
|
167
|
-
(
|
|
166
|
+
(100_000 + idiv((strength + density + hardness) * 500_000, 2997)) *
|
|
168
167
|
moduleTierPct(CARGO_BAY_CAPACITY_TIER_PCT, tier),
|
|
169
168
|
100
|
|
170
169
|
)
|
package/src/planner/index.ts
CHANGED
|
@@ -3,6 +3,9 @@ import type {ServerContract} from '../contracts'
|
|
|
3
3
|
import {calc_gather_duration, calc_gather_energy} from '../capabilities/gathering'
|
|
4
4
|
import {calc_rechargetime} from '../travel/travel'
|
|
5
5
|
import {projectRemainingAt, type Projectable} from '../scheduling/projection'
|
|
6
|
+
import {selectGatherLane} from '../scheduling/lanes'
|
|
7
|
+
|
|
8
|
+
export type GatherLane = ServerContract.Types.gatherer_lane
|
|
6
9
|
|
|
7
10
|
export interface LanePlanEntry {
|
|
8
11
|
slot: number
|
|
@@ -224,6 +227,57 @@ export function buildGatherPlan(
|
|
|
224
227
|
}
|
|
225
228
|
}
|
|
226
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
|
+
|
|
227
281
|
export function planParallelTransfer(
|
|
228
282
|
entity: GatherPlanEntity,
|
|
229
283
|
target: PlanTarget
|