@shipload/sdk 1.0.0-next.64 → 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 +754 -316
- package/lib/shipload.js +2650 -1336
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2564 -1308
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +219 -145
- package/lib/testing.js +910 -557
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +910 -557
- 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 +110 -5
- package/src/contracts/platform.ts +10 -1
- package/src/contracts/server.ts +498 -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 +33 -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 +5 -2
- package/src/managers/influence.test.ts +18 -20
- package/src/managers/influence.ts +162 -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 +23 -4
- 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,44 +76,59 @@ 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
|
|
74
84
|
}
|
|
75
85
|
|
|
86
|
+
export interface FoundedWorldRef {
|
|
87
|
+
x: number
|
|
88
|
+
y: number
|
|
89
|
+
mandate: number
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
export interface VoteOption {
|
|
77
93
|
nodeId: number
|
|
78
94
|
cost: bigint
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
seat: number
|
|
96
|
+
weight: bigint
|
|
97
|
+
rank: number
|
|
81
98
|
}
|
|
82
99
|
|
|
83
100
|
export interface VoteStandings {
|
|
84
101
|
locationId: bigint
|
|
102
|
+
ballotId: bigint
|
|
85
103
|
epoch: number
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
talliesSuppressed: boolean
|
|
104
|
+
settledEpoch: number
|
|
105
|
+
seats: number
|
|
106
|
+
settling: boolean
|
|
107
|
+
queue: number[]
|
|
91
108
|
options: VoteOption[]
|
|
109
|
+
picks: number[]
|
|
92
110
|
}
|
|
93
111
|
|
|
94
|
-
export interface
|
|
112
|
+
export interface BallotVote {
|
|
95
113
|
account: Name
|
|
96
|
-
|
|
97
|
-
nodeId: number
|
|
98
|
-
weight: bigint
|
|
114
|
+
picks: number[]
|
|
99
115
|
}
|
|
100
116
|
|
|
101
|
-
export interface
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
106
132
|
}
|
|
107
133
|
|
|
108
134
|
function big(value: unknown): bigint {
|
|
@@ -119,13 +145,13 @@ export class InfluenceManager extends BaseManager {
|
|
|
119
145
|
|
|
120
146
|
return {
|
|
121
147
|
epoch: Number(result.epoch),
|
|
122
|
-
playerLifetime: big(result.player_lifetime),
|
|
123
|
-
playerActive: big(result.player_active),
|
|
124
148
|
standingLifetime: big(result.standing_lifetime),
|
|
125
149
|
standingActive: big(result.standing_active),
|
|
150
|
+
citizenshipLifetime: big(result.citizenship_lifetime),
|
|
151
|
+
citizenshipActive: big(result.citizenship_active),
|
|
126
152
|
locationLifetime: big(result.location_lifetime),
|
|
127
153
|
locationActive: big(result.location_active),
|
|
128
|
-
|
|
154
|
+
spent: big(result.spent),
|
|
129
155
|
mandate: Number(result.mandate),
|
|
130
156
|
founder: Name.from(result.founder),
|
|
131
157
|
founded: Number(result.founded),
|
|
@@ -164,6 +190,17 @@ export class InfluenceManager extends BaseManager {
|
|
|
164
190
|
})
|
|
165
191
|
}
|
|
166
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
|
+
|
|
167
204
|
async getCitizenryName(location: CoordinatesType): Promise<string | undefined> {
|
|
168
205
|
const game = await this.getGame()
|
|
169
206
|
return citizenryName(game.config.seed, location)
|
|
@@ -189,20 +226,20 @@ export class InfluenceManager extends BaseManager {
|
|
|
189
226
|
)
|
|
190
227
|
|
|
191
228
|
let totalAtomic = 0n
|
|
192
|
-
let
|
|
229
|
+
let totalMass = 0
|
|
193
230
|
const rows = bundle.map((item) => {
|
|
194
231
|
const valueAtomic = valueCargoItem(item, demand, pricing)
|
|
195
|
-
const
|
|
232
|
+
const mass = getItem(item.itemId).mass * item.quantity
|
|
196
233
|
totalAtomic += valueAtomic
|
|
197
|
-
|
|
198
|
-
return {...item, valueAtomic,
|
|
234
|
+
totalMass += mass
|
|
235
|
+
return {...item, valueAtomic, mass}
|
|
199
236
|
})
|
|
200
237
|
|
|
201
238
|
return {
|
|
202
239
|
rows,
|
|
203
240
|
totalAtomic,
|
|
204
|
-
|
|
205
|
-
durationSeconds: contributeDuration(
|
|
241
|
+
totalMass,
|
|
242
|
+
durationSeconds: contributeDuration(totalMass, opts.altitudeZ ?? 0),
|
|
206
243
|
demand,
|
|
207
244
|
}
|
|
208
245
|
}
|
|
@@ -216,8 +253,8 @@ export class InfluenceManager extends BaseManager {
|
|
|
216
253
|
return {
|
|
217
254
|
locationId: big(result.location_id),
|
|
218
255
|
lifetime: big(result.lifetime),
|
|
219
|
-
|
|
220
|
-
|
|
256
|
+
spent: big(result.spent),
|
|
257
|
+
unassigned: big(result.unassigned),
|
|
221
258
|
mandate: Number(result.mandate),
|
|
222
259
|
nextCost: big(result.next_cost),
|
|
223
260
|
prereqsMet: Boolean(result.prereqs_met),
|
|
@@ -225,8 +262,19 @@ export class InfluenceManager extends BaseManager {
|
|
|
225
262
|
epoch: Number(result.epoch),
|
|
226
263
|
built: result.built.map((b) => ({
|
|
227
264
|
nodeId: Number(b.node_id),
|
|
228
|
-
|
|
229
|
-
|
|
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),
|
|
230
278
|
})),
|
|
231
279
|
}
|
|
232
280
|
}
|
|
@@ -247,73 +295,104 @@ export class InfluenceManager extends BaseManager {
|
|
|
247
295
|
return (await this.server.readonly('getmintcfg')) as ServerContract.Types.mintcfg_result
|
|
248
296
|
}
|
|
249
297
|
|
|
250
|
-
async
|
|
298
|
+
async getMintReady(): Promise<number> {
|
|
299
|
+
return Number(await this.server.readonly('getmintready'))
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async getVoteReady(): Promise<number> {
|
|
303
|
+
return Number(await this.server.readonly('getvoteready'))
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async getCharterReady(): Promise<FoundedWorldRef[]> {
|
|
307
|
+
const result = (await this.server.readonly(
|
|
308
|
+
'getchrtready'
|
|
309
|
+
)) as ServerContract.Types.charterready_result
|
|
310
|
+
return result.worlds.map((w) => ({
|
|
311
|
+
x: Number(w.x),
|
|
312
|
+
y: Number(w.y),
|
|
313
|
+
mandate: Number(w.mandate),
|
|
314
|
+
}))
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async getVotes(location: CoordinatesType, player?: NameType): Promise<VoteStandings> {
|
|
251
318
|
const result = (await this.server.readonly('getvotes', {
|
|
252
319
|
x: Int64.from(location.x),
|
|
253
320
|
y: Int64.from(location.y),
|
|
321
|
+
player: Name.from(player ?? ''),
|
|
254
322
|
})) as ServerContract.Types.vote_result
|
|
255
323
|
|
|
256
|
-
const epoch = Number(result.epoch)
|
|
257
|
-
const rawBallotEpoch = Number(result.ballot_epoch)
|
|
258
|
-
const ballotEpoch = rawBallotEpoch === 0 ? undefined : rawBallotEpoch
|
|
259
|
-
const talliesSuppressed = ballotEpoch !== undefined && ballotEpoch < epoch
|
|
260
|
-
|
|
261
324
|
return {
|
|
262
325
|
locationId: big(result.location_id),
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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)),
|
|
269
332
|
options: result.options.map((option) => ({
|
|
270
333
|
nodeId: Number(option.node_id),
|
|
271
334
|
cost: big(option.cost),
|
|
272
|
-
|
|
273
|
-
|
|
335
|
+
seat: Number(option.seat),
|
|
336
|
+
weight: big(option.weight),
|
|
337
|
+
rank: Number(option.rank),
|
|
274
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,
|
|
275
367
|
}
|
|
276
368
|
}
|
|
277
369
|
|
|
278
|
-
async
|
|
370
|
+
async getBallotVotes(ballotId: bigint): Promise<BallotVote[]> {
|
|
279
371
|
const rows = (await this.server
|
|
280
|
-
.table('
|
|
281
|
-
.all()) as ServerContract.Types.
|
|
372
|
+
.table('ballotpicks', UInt64.from(ballotId))
|
|
373
|
+
.all()) as ServerContract.Types.ballotpicks_row[]
|
|
282
374
|
return rows.map((row) => ({
|
|
283
375
|
account: Name.from(row.account),
|
|
284
|
-
|
|
285
|
-
nodeId: Number(row.node_id),
|
|
286
|
-
weight: big(row.weight),
|
|
376
|
+
picks: row.picks.map((n) => Number(n)),
|
|
287
377
|
}))
|
|
288
378
|
}
|
|
289
379
|
|
|
290
|
-
async getVoteTallies(location: CoordinatesType): Promise<{nodeId: number; total: bigint}[]> {
|
|
291
|
-
const rows = (await this.server
|
|
292
|
-
.table('inftally', coordsToLocationId(location))
|
|
293
|
-
.all()) as ServerContract.Types.inftally_row[]
|
|
294
|
-
return rows.map((row) => ({nodeId: Number(row.node_id), total: big(row.total)}))
|
|
295
|
-
}
|
|
296
|
-
|
|
297
380
|
async getBuiltCharters(location: CoordinatesType): Promise<BuiltCharter[]> {
|
|
298
381
|
const rows = (await this.server
|
|
299
|
-
.table('
|
|
300
|
-
.all()) as ServerContract.Types.
|
|
301
|
-
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)}))
|
|
302
385
|
}
|
|
303
386
|
|
|
304
|
-
async
|
|
387
|
+
async getBuildings(location: CoordinatesType): Promise<WorldBuilding[]> {
|
|
305
388
|
const rows = (await this.server
|
|
306
|
-
.table('
|
|
307
|
-
.all()) as ServerContract.Types.
|
|
308
|
-
return rows.map((row) => ({
|
|
309
|
-
locationId: big(row.location_id),
|
|
310
|
-
...locationIdToCoords(row.location_id),
|
|
311
|
-
epoch: Number(row.epoch),
|
|
312
|
-
}))
|
|
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)}))
|
|
313
392
|
}
|
|
314
393
|
|
|
315
394
|
async getFoundedWorlds(opts: {withMandate?: boolean} = {}): Promise<FoundedWorld[]> {
|
|
316
|
-
const rows = (await this.server.table('
|
|
395
|
+
const rows = (await this.server.table('worlds').all()) as ServerContract.Types.worlds_row[]
|
|
317
396
|
const epoch = (await this.getState()).epoch
|
|
318
397
|
const worlds = rows.map((row) => ({
|
|
319
398
|
locationId: big(row.location_id),
|
|
@@ -321,11 +400,10 @@ export class InfluenceManager extends BaseManager {
|
|
|
321
400
|
lifetime: big(row.lifetime),
|
|
322
401
|
active: decayActive(
|
|
323
402
|
big(row.active),
|
|
324
|
-
Math.max(0, Number(epoch) - Number(row.
|
|
403
|
+
Math.max(0, Number(epoch) - Number(row.active_epoch))
|
|
325
404
|
),
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
chosenEpoch: Number(row.chosen_epoch),
|
|
405
|
+
spent: big(row.spent),
|
|
406
|
+
ballotId: big(row.ballot_id),
|
|
329
407
|
mandate: undefined as number | undefined,
|
|
330
408
|
founder: Name.from(row.founder),
|
|
331
409
|
founded: Number(row.founded),
|
|
@@ -341,7 +419,7 @@ export class InfluenceManager extends BaseManager {
|
|
|
341
419
|
|
|
342
420
|
async isFounded(location: CoordinatesType): Promise<boolean> {
|
|
343
421
|
const id = coordsToLocationId(location)
|
|
344
|
-
const row = await this.server.table('
|
|
422
|
+
const row = await this.server.table('worlds').get(UInt64.from(id))
|
|
345
423
|
return row !== undefined
|
|
346
424
|
}
|
|
347
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
|