@shipload/sdk 1.0.0-next.70 → 1.0.0-next.72
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 +266 -101
- package/lib/shipload.js +898 -404
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +880 -398
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +51 -13
- package/lib/testing.js +209 -64
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +209 -64
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +140 -34
- package/src/data/capability-formulas.ts +4 -4
- package/src/data/entities.json +84 -68
- package/src/data/item-ids.ts +5 -4
- package/src/data/items.json +30 -24
- package/src/data/kind-registry.json +75 -39
- package/src/data/kind-registry.ts +13 -0
- package/src/data/metadata.ts +35 -0
- package/src/data/recipes.json +194 -155
- package/src/derivation/build-methods.test.ts +4 -4
- package/src/derivation/capabilities.test.ts +14 -10
- package/src/derivation/capabilities.ts +8 -10
- package/src/derivation/capability-mappings.ts +4 -4
- package/src/derivation/capacity-fn-registry.test.ts +9 -0
- package/src/derivation/capacity-fn-registry.ts +18 -0
- package/src/derivation/recipe-usage.test.ts +7 -11
- package/src/index-module.ts +28 -8
- package/src/influence/influence.test.ts +1 -1
- package/src/managers/actions.ts +19 -4
- package/src/managers/context.ts +9 -0
- package/src/managers/fund.ts +49 -0
- package/src/managers/index.ts +3 -0
- package/src/managers/jobs.test.ts +25 -9
- package/src/managers/jobs.ts +8 -4
- package/src/nft/description.ts +5 -10
- package/src/receipts.ts +9 -9
- package/src/resolution/resolve-item.test.ts +15 -10
- package/src/scheduling/jobs.test.ts +417 -18
- package/src/scheduling/jobs.ts +222 -16
- package/src/scheduling/lanes.ts +53 -1
- package/src/shipload.ts +5 -0
package/src/index-module.ts
CHANGED
|
@@ -35,13 +35,9 @@ export type cargo_item = ServerContract.Types.cargo_item
|
|
|
35
35
|
export type entity_row = ServerContract.Types.entity_row
|
|
36
36
|
export type craftjob_row = ServerContract.Types.craftjob_row
|
|
37
37
|
export type buildjob_row = ServerContract.Types.buildjob_row
|
|
38
|
-
export type
|
|
39
|
-
export {
|
|
40
|
-
|
|
41
|
-
bookingReceiptLandsAtMs,
|
|
42
|
-
bookingReceiptRuntimeSeconds,
|
|
43
|
-
} from './receipts'
|
|
44
|
-
export type {BookingReceipt} from './receipts'
|
|
38
|
+
export type window_receipt = ServerContract.Types.window_receipt
|
|
39
|
+
export {decodeWindowReceipt, windowReceiptStartsAtMs, windowReceiptCompletesAtMs} from './receipts'
|
|
40
|
+
export type {WindowReceipt} from './receipts'
|
|
45
41
|
|
|
46
42
|
export type location_static = ServerContract.Types.location_static
|
|
47
43
|
export type location_derived = ServerContract.Types.location_derived
|
|
@@ -61,6 +57,7 @@ export {
|
|
|
61
57
|
computeFreeCells,
|
|
62
58
|
NftManager,
|
|
63
59
|
BalancesManager,
|
|
60
|
+
FundManager,
|
|
64
61
|
ConstructionManager,
|
|
65
62
|
JobsManager,
|
|
66
63
|
InfluenceManager,
|
|
@@ -84,6 +81,9 @@ export type {
|
|
|
84
81
|
NftConfigForItem,
|
|
85
82
|
WrapConfig,
|
|
86
83
|
WrapGate,
|
|
84
|
+
FundBeneficiary,
|
|
85
|
+
FundToken,
|
|
86
|
+
FundAccrued,
|
|
87
87
|
DepositConfig,
|
|
88
88
|
PlatformBalance,
|
|
89
89
|
TokenBalance,
|
|
@@ -289,6 +289,7 @@ export type {
|
|
|
289
289
|
} from './scheduling/schedule'
|
|
290
290
|
export {
|
|
291
291
|
candidateLaneCompletesAt,
|
|
292
|
+
candidateCivicDepositWindow,
|
|
292
293
|
laneKeyForModule,
|
|
293
294
|
rawScheduleEnd,
|
|
294
295
|
resolveLaneGatherer,
|
|
@@ -335,10 +336,27 @@ export {
|
|
|
335
336
|
JOB_QUEUE_CAP,
|
|
336
337
|
jobStatus,
|
|
337
338
|
jobStatusLabel,
|
|
339
|
+
jobDropoffTask,
|
|
340
|
+
jobCancelRoute,
|
|
341
|
+
buildJobCancelRoute,
|
|
342
|
+
jobCancellable,
|
|
343
|
+
jobCancellationBlockReason,
|
|
338
344
|
jobDeposited,
|
|
339
345
|
splitJobCargo,
|
|
346
|
+
workshopAvailability,
|
|
347
|
+
pickupsInFlight,
|
|
348
|
+
} from './scheduling/jobs'
|
|
349
|
+
export type {
|
|
350
|
+
JobWindow,
|
|
351
|
+
JobLane,
|
|
352
|
+
JobLaneEntry,
|
|
353
|
+
JobStatus,
|
|
354
|
+
JobStatusInput,
|
|
355
|
+
JobCancelRoute,
|
|
356
|
+
JobCancellationBlockReason,
|
|
357
|
+
OwnedJob,
|
|
358
|
+
PickupInFlight,
|
|
340
359
|
} from './scheduling/jobs'
|
|
341
|
-
export type {JobWindow, JobLane, JobLaneEntry, JobStatus, OwnedJob} from './scheduling/jobs'
|
|
342
360
|
|
|
343
361
|
export {composeIdleResolve} from './scheduling/idle-resolve'
|
|
344
362
|
export type {CounterpartLookup, IdleResolveTarget} from './scheduling/idle-resolve'
|
|
@@ -399,6 +417,7 @@ export {
|
|
|
399
417
|
ENTITY_NEXUS,
|
|
400
418
|
ENTITY_HUB,
|
|
401
419
|
ENTITY_DEPOT,
|
|
420
|
+
ENTITY_ASSEMBLY_YARD,
|
|
402
421
|
getEntityClass,
|
|
403
422
|
getPackedEntityType,
|
|
404
423
|
getKindMeta,
|
|
@@ -424,6 +443,7 @@ export {
|
|
|
424
443
|
isPlot,
|
|
425
444
|
isHub,
|
|
426
445
|
isDepot,
|
|
446
|
+
isAssemblyYard,
|
|
427
447
|
} from './data/kind-registry'
|
|
428
448
|
export type {EntityTypeName, KindMeta, TemplateMeta} from './data/kind-registry'
|
|
429
449
|
export * from './capabilities'
|
|
@@ -136,7 +136,7 @@ describe('decomposition', () => {
|
|
|
136
136
|
for (let i = 1; i < DECOMP_REGISTRY.length; i++) {
|
|
137
137
|
expect(DECOMP_REGISTRY[i].itemId).toBeGreaterThan(DECOMP_REGISTRY[i - 1].itemId)
|
|
138
138
|
}
|
|
139
|
-
expect(DECOMP_REGISTRY.length).toBe(
|
|
139
|
+
expect(DECOMP_REGISTRY.length).toBe(57)
|
|
140
140
|
})
|
|
141
141
|
|
|
142
142
|
test('the retired Workshop has no decomposition entry', () => {
|
package/src/managers/actions.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {Coordinates, PRECISION, type ClusterSlotType, type CoordinatesType} from
|
|
|
24
24
|
import {ServerContract, TokenContract} from '../contracts'
|
|
25
25
|
import {ATOMICASSETS_ABI, SHIPLOAD_COLLECTION} from '../nft/atomicassets'
|
|
26
26
|
import {getItem} from '../data/catalog'
|
|
27
|
+
import type {JobCancelRoute} from '../scheduling/jobs'
|
|
27
28
|
|
|
28
29
|
const CHARGE_K = 100n
|
|
29
30
|
const ENERGY_DIVISOR = 10n
|
|
@@ -515,7 +516,6 @@ export class ActionsManager extends BaseManager {
|
|
|
515
516
|
craftjob(
|
|
516
517
|
shipId: UInt64Type,
|
|
517
518
|
workshopId: UInt64Type,
|
|
518
|
-
slot: UInt8Type,
|
|
519
519
|
recipeId: UInt16Type,
|
|
520
520
|
quantity: UInt32Type,
|
|
521
521
|
inputs: ServerContract.ActionParams.Type.cargo_item[]
|
|
@@ -523,7 +523,6 @@ export class ActionsManager extends BaseManager {
|
|
|
523
523
|
const params: ServerContract.ActionParams.craftjob = {
|
|
524
524
|
ship_id: UInt64.from(shipId),
|
|
525
525
|
workshop_id: UInt64.from(workshopId),
|
|
526
|
-
slot: UInt8.from(slot),
|
|
527
526
|
recipe_id: UInt16.from(recipeId),
|
|
528
527
|
quantity: UInt32.from(quantity),
|
|
529
528
|
inputs,
|
|
@@ -531,6 +530,19 @@ export class ActionsManager extends BaseManager {
|
|
|
531
530
|
return this.server.action('craftjob', params)
|
|
532
531
|
}
|
|
533
532
|
|
|
533
|
+
cancelcraft(jobId: UInt64Type): Action {
|
|
534
|
+
const params: ServerContract.ActionParams.cancelcraft = {
|
|
535
|
+
job_id: UInt64.from(jobId),
|
|
536
|
+
}
|
|
537
|
+
return this.server.action('cancelcraft', params)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
canceljob(route: JobCancelRoute): Action {
|
|
541
|
+
if (route.kind === 'dropoff') return this.cancel(route.shipId, route.laneKey, route.count)
|
|
542
|
+
if (route.kind === 'build') return this.cancelbuild(route.jobId)
|
|
543
|
+
return this.cancelcraft(route.jobId)
|
|
544
|
+
}
|
|
545
|
+
|
|
534
546
|
clustercraft(
|
|
535
547
|
entityId: UInt64Type,
|
|
536
548
|
recipeId: number,
|
|
@@ -565,14 +577,12 @@ export class ActionsManager extends BaseManager {
|
|
|
565
577
|
buildjob(
|
|
566
578
|
targetId: UInt64Type,
|
|
567
579
|
dockId: UInt64Type,
|
|
568
|
-
slot: UInt8Type,
|
|
569
580
|
targetItemId: UInt16Type,
|
|
570
581
|
inputs: ServerContract.ActionParams.Type.cargo_item[]
|
|
571
582
|
): Action {
|
|
572
583
|
const params: ServerContract.ActionParams.buildjob = {
|
|
573
584
|
target_id: UInt64.from(targetId),
|
|
574
585
|
dock_id: UInt64.from(dockId),
|
|
575
|
-
slot: UInt8.from(slot),
|
|
576
586
|
target_item_id: UInt16.from(targetItemId),
|
|
577
587
|
inputs,
|
|
578
588
|
}
|
|
@@ -1028,6 +1038,11 @@ export class ActionsManager extends BaseManager {
|
|
|
1028
1038
|
})
|
|
1029
1039
|
}
|
|
1030
1040
|
|
|
1041
|
+
/** Pays every nonzero accrued token balance to the beneficiary. */
|
|
1042
|
+
claimFund(beneficiary: NameType): Action {
|
|
1043
|
+
return this.fund.action('claim', {beneficiary_account: Name.from(beneficiary)})
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1031
1046
|
collectFund(): Action {
|
|
1032
1047
|
return this.fund.action('collect', {})
|
|
1033
1048
|
}
|
package/src/managers/context.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {ActionsManager} from './actions'
|
|
|
13
13
|
import {ClusterManager} from './cluster'
|
|
14
14
|
import {NftManager} from './nft'
|
|
15
15
|
import {BalancesManager} from './balances'
|
|
16
|
+
import {FundManager} from './fund'
|
|
16
17
|
import {JobsManager} from './jobs'
|
|
17
18
|
import {InfluenceManager} from './influence'
|
|
18
19
|
import {SubscriptionsManager} from '../subscriptions/manager'
|
|
@@ -27,6 +28,7 @@ export class GameContext {
|
|
|
27
28
|
private _clusters?: ClusterManager
|
|
28
29
|
private _nft?: NftManager
|
|
29
30
|
private _balances?: BalancesManager
|
|
31
|
+
private _funds?: FundManager
|
|
30
32
|
private _jobs?: JobsManager
|
|
31
33
|
private _influence?: InfluenceManager
|
|
32
34
|
private _subscriptions?: SubscriptionsManager
|
|
@@ -106,6 +108,13 @@ export class GameContext {
|
|
|
106
108
|
return this._balances
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
get funds(): FundManager {
|
|
112
|
+
if (!this._funds) {
|
|
113
|
+
this._funds = new FundManager(this)
|
|
114
|
+
}
|
|
115
|
+
return this._funds
|
|
116
|
+
}
|
|
117
|
+
|
|
109
118
|
get jobs(): JobsManager {
|
|
110
119
|
if (!this._jobs) {
|
|
111
120
|
this._jobs = new JobsManager(this)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {type Asset, Name, type NameType, type UInt16} from '@wharfkit/antelope'
|
|
2
|
+
import type {FundContract} from '../contracts'
|
|
3
|
+
import type {PlatformBalance} from './balances'
|
|
4
|
+
import {BaseManager} from './base'
|
|
5
|
+
|
|
6
|
+
export interface FundBeneficiary {
|
|
7
|
+
account: Name
|
|
8
|
+
bps: UInt16
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FundToken {
|
|
12
|
+
tokenContract: Name
|
|
13
|
+
symbol: Asset.Symbol
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FundAccrued {
|
|
17
|
+
tokenContract: Name
|
|
18
|
+
balance: Asset
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Live fund ledger reads. Token custody can exceed the amounts accrued to beneficiaries. */
|
|
22
|
+
export class FundManager extends BaseManager {
|
|
23
|
+
async getBeneficiaries(): Promise<FundBeneficiary[]> {
|
|
24
|
+
const rows = (await this.fund
|
|
25
|
+
.table('benefs', this.fund.account)
|
|
26
|
+
.all()) as FundContract.Types.benef_row[]
|
|
27
|
+
return rows.map((row) => ({account: row.account, bps: row.bps}))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async getTokens(): Promise<FundToken[]> {
|
|
31
|
+
const rows = (await this.fund
|
|
32
|
+
.table('tokens', this.fund.account)
|
|
33
|
+
.all()) as FundContract.Types.token_row[]
|
|
34
|
+
return rows.map((row) => ({tokenContract: row.token_contract, symbol: row.token_symbol}))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Includes zero rows and claims for tokens no longer accepted; no rows returns []. */
|
|
38
|
+
async getAccrued(beneficiary: NameType): Promise<FundAccrued[]> {
|
|
39
|
+
const rows = (await this.fund
|
|
40
|
+
.table('accrued', Name.from(beneficiary))
|
|
41
|
+
.all()) as FundContract.Types.accrued_row[]
|
|
42
|
+
return rows.map((row) => ({tokenContract: row.token_contract, balance: row.balance}))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Platform balances that have not reached the fund's accrual ledger yet. */
|
|
46
|
+
async getUncollected(): Promise<PlatformBalance[]> {
|
|
47
|
+
return this.context.balances.getPlatformBalances(this.fund.account)
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/managers/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ const row = (over: Record<string, unknown> = {}) => ({
|
|
|
12
12
|
coords: {x: {toNumber: () => 12}, y: {toNumber: () => 34}},
|
|
13
13
|
starts_at: {toDate: () => new Date('2026-07-26T10:00:00Z')},
|
|
14
14
|
completes_at: {toDate: () => new Date('2026-07-26T11:00:00Z')},
|
|
15
|
+
arrives_at: {toDate: () => new Date('2026-07-26T09:45:00Z')},
|
|
15
16
|
recipe_id: {toNumber: () => 10001},
|
|
16
17
|
quantity: {toNumber: () => 5},
|
|
17
18
|
energy_paid: {toNumber: () => 0},
|
|
@@ -26,37 +27,52 @@ function managerWith(queryImpl: () => Promise<unknown[]>, allImpl: () => Promise
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
describe('JobsManager.getOwnedJobs', () => {
|
|
29
|
-
it('parses a
|
|
30
|
+
it('parses a deposited row: inputs then the output tail, status derived', async () => {
|
|
30
31
|
const m = managerWith(
|
|
31
|
-
async () => [row()],
|
|
32
|
+
async () => [row({cargo: [{item: 'in'}, {item: 'out'}]})],
|
|
32
33
|
async () => []
|
|
33
34
|
)
|
|
34
35
|
const jobs = await m.getOwnedJobs(OWNER, {now: new Date('2026-07-26T11:30:00Z')})
|
|
35
36
|
expect(jobs).toHaveLength(1)
|
|
36
37
|
expect(jobs[0]).toMatchObject({id: 7, building: 42, quantity: 5, status: 'ready'})
|
|
38
|
+
expect(jobs[0].arrivesAt).toEqual(new Date('2026-07-26T09:45:00Z'))
|
|
37
39
|
expect(jobs[0].coords).toEqual({x: 12, y: 34})
|
|
38
40
|
expect(jobs[0].output).toEqual({item: 'out'} as never)
|
|
39
|
-
expect(jobs[0].inputs).toEqual([] as never)
|
|
41
|
+
expect(jobs[0].inputs).toEqual([{item: 'in'}] as never)
|
|
40
42
|
})
|
|
41
43
|
|
|
42
|
-
it('reports
|
|
43
|
-
const
|
|
44
|
-
starts_at: {toDate: () => new Date(0)},
|
|
45
|
-
completes_at: {toDate: () => new Date(0)},
|
|
44
|
+
it('reports an undeposited row as dropping off, whatever its window says', async () => {
|
|
45
|
+
const inFlight = row({
|
|
46
46
|
deposited: false,
|
|
47
47
|
cargo: [{item: 'in'}],
|
|
48
48
|
})
|
|
49
49
|
const m = managerWith(
|
|
50
|
-
async () => [
|
|
50
|
+
async () => [inFlight],
|
|
51
51
|
async () => []
|
|
52
52
|
)
|
|
53
53
|
const jobs = await m.getOwnedJobs(OWNER, {now: new Date('2026-07-26T11:30:00Z')})
|
|
54
|
-
expect(jobs[0].status).toBe('
|
|
54
|
+
expect(jobs[0].status).toBe('dropping')
|
|
55
55
|
expect(jobs[0].deposited).toBe(false)
|
|
56
56
|
expect(jobs[0].output).toBeNull()
|
|
57
57
|
expect(jobs[0].inputs).toEqual([{item: 'in'}] as never)
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
+
it('reports a cancelled row as ready with its inputs held', async () => {
|
|
61
|
+
const cancelled = row({
|
|
62
|
+
quantity: {toNumber: () => 0},
|
|
63
|
+
deposited: true,
|
|
64
|
+
cargo: [{item: 'in'}],
|
|
65
|
+
})
|
|
66
|
+
const m = managerWith(
|
|
67
|
+
async () => [cancelled],
|
|
68
|
+
async () => []
|
|
69
|
+
)
|
|
70
|
+
const jobs = await m.getOwnedJobs(OWNER, {now: new Date('2026-07-26T09:00:00Z')})
|
|
71
|
+
expect(jobs[0].status).toBe('ready')
|
|
72
|
+
expect(jobs[0].output).toBeNull()
|
|
73
|
+
expect(jobs[0].inputs).toEqual([{item: 'in'}] as never)
|
|
74
|
+
})
|
|
75
|
+
|
|
60
76
|
it('drops rows whose owner does not match (positional-index safety re-filter)', async () => {
|
|
61
77
|
const other = row({owner: Name.from('someoneelse.gm')})
|
|
62
78
|
const m = managerWith(
|
package/src/managers/jobs.ts
CHANGED
|
@@ -32,19 +32,23 @@ export class JobsManager extends BaseManager {
|
|
|
32
32
|
private parseOwnedJob(r: JobRow, now: Date): OwnedJob {
|
|
33
33
|
const startsAt = r.starts_at.toDate()
|
|
34
34
|
const completesAt = r.completes_at.toDate()
|
|
35
|
+
const arrivesAt = r.arrives_at.toDate()
|
|
35
36
|
const deposited = jobDeposited(r.deposited)
|
|
36
|
-
const
|
|
37
|
+
const quantity = r.quantity.toNumber()
|
|
38
|
+
const building = r.building.toNumber()
|
|
39
|
+
const {output, inputs} = splitJobCargo(r.cargo, deposited, quantity)
|
|
37
40
|
return {
|
|
38
41
|
id: r.id.toNumber(),
|
|
39
|
-
building
|
|
42
|
+
building,
|
|
40
43
|
socket: r.socket.toNumber(),
|
|
41
44
|
shipId: r.ship_id.toNumber(),
|
|
42
45
|
coords: {x: r.coords.x.toNumber(), y: r.coords.y.toNumber()},
|
|
43
46
|
startsAt,
|
|
44
47
|
completesAt,
|
|
48
|
+
arrivesAt,
|
|
45
49
|
recipeId: r.recipe_id.toNumber(),
|
|
46
|
-
quantity
|
|
47
|
-
status: jobStatus({startsAt, completesAt, deposited}, now),
|
|
50
|
+
quantity,
|
|
51
|
+
status: jobStatus({startsAt, completesAt, deposited, quantity, building, inputs}, now),
|
|
48
52
|
deposited,
|
|
49
53
|
output,
|
|
50
54
|
inputs,
|
package/src/nft/description.ts
CHANGED
|
@@ -32,6 +32,7 @@ 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'
|
|
35
|
+
import {resolveCapacityFnName, type CapacityFnName} from '../derivation/capacity-fn-registry'
|
|
35
36
|
|
|
36
37
|
function idiv(a: number, b: number): number {
|
|
37
38
|
return Math.floor(a / b)
|
|
@@ -89,24 +90,18 @@ export function computeBaseCapacityDepot(stats: bigint): number {
|
|
|
89
90
|
return Math.floor(500_000 * 6 ** (s / 1998))
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
const
|
|
93
|
+
const CAPACITY_FN_BY_NAME: Record<CapacityFnName, (stats: bigint) => number> = {
|
|
93
94
|
ship: computeBaseCapacityShip,
|
|
94
95
|
warehouse: computeBaseCapacityWarehouse,
|
|
95
96
|
workshop: computeBaseCapacityWorkshop,
|
|
96
|
-
extractor: computeBaseCapacityContainer,
|
|
97
|
-
factory: computeBaseCapacityContainer,
|
|
98
|
-
builddock: computeBaseCapacityContainer,
|
|
99
|
-
mdriver: computeBaseCapacityContainer,
|
|
100
|
-
mcatcher: computeBaseCapacityContainer,
|
|
101
97
|
container: computeBaseCapacityContainer,
|
|
102
|
-
nexus: computeBaseCapacityContainer,
|
|
103
98
|
depot: computeBaseCapacityDepot,
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
export function computeBaseCapacityForEntity(itemId: number, stats: bigint): number {
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
109
|
-
return
|
|
102
|
+
const fnName = resolveCapacityFnName(itemId)
|
|
103
|
+
if (!fnName) return 0
|
|
104
|
+
return CAPACITY_FN_BY_NAME[fnName](stats)
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
export const computeEngineThrust = (vol: number, tier: number): number =>
|
package/src/receipts.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {Serializer} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from './contracts'
|
|
3
3
|
|
|
4
|
-
export type
|
|
4
|
+
export type WindowReceipt = ServerContract.Types.window_receipt
|
|
5
5
|
|
|
6
|
-
export function
|
|
6
|
+
export function decodeWindowReceipt(data: unknown): WindowReceipt {
|
|
7
7
|
if (data === null || data === undefined) {
|
|
8
|
-
throw new Error('
|
|
8
|
+
throw new Error('decodeWindowReceipt: no return value')
|
|
9
9
|
}
|
|
10
10
|
if (data instanceof Uint8Array || typeof data === 'string') {
|
|
11
|
-
return Serializer.decode({data, type: ServerContract.Types.
|
|
11
|
+
return Serializer.decode({data, type: ServerContract.Types.window_receipt})
|
|
12
12
|
}
|
|
13
|
-
return ServerContract.Types.
|
|
13
|
+
return ServerContract.Types.window_receipt.from(data as ServerContract.Types.window_receipt)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function
|
|
17
|
-
return receipt.
|
|
16
|
+
export function windowReceiptStartsAtMs(receipt: WindowReceipt): number {
|
|
17
|
+
return receipt.starts_at.toMilliseconds()
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function
|
|
21
|
-
return
|
|
20
|
+
export function windowReceiptCompletesAtMs(receipt: WindowReceipt): number {
|
|
21
|
+
return receipt.completes_at.toMilliseconds()
|
|
22
22
|
}
|
|
@@ -2,11 +2,16 @@ import {expect, test} from 'bun:test'
|
|
|
2
2
|
import {UInt16, UInt64} from '@wharfkit/antelope'
|
|
3
3
|
import {resolveItem} from './resolve-item'
|
|
4
4
|
import {encodeStats} from '../derivation/crafting'
|
|
5
|
-
import {computeBaseHullmass, computeContainerCapabilities} from '../derivation/capabilities'
|
|
6
5
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
computeBaseHullmass,
|
|
7
|
+
computeContainerCapabilities,
|
|
8
|
+
applyCapacityTier,
|
|
9
|
+
} from '../derivation/capabilities'
|
|
10
|
+
import {getItem} from '../data/catalog'
|
|
11
|
+
import {
|
|
12
|
+
ITEM_EXTRACTOR_T2_PACKED,
|
|
13
|
+
ITEM_FACTORY_T2_PACKED,
|
|
14
|
+
ITEM_HUB_T2_PACKED,
|
|
10
15
|
ITEM_MASS_DRIVER_T1_PACKED,
|
|
11
16
|
ITEM_MASS_CATCHER_T1_PACKED,
|
|
12
17
|
} from '../data/item-ids'
|
|
@@ -16,8 +21,8 @@ function hullStats(strength: number, density: number, hardness: number): UInt64
|
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
const CONTAINER_ENTITIES = [
|
|
19
|
-
['factory',
|
|
20
|
-
['extractor',
|
|
24
|
+
['factory', ITEM_FACTORY_T2_PACKED],
|
|
25
|
+
['extractor', ITEM_EXTRACTOR_T2_PACKED],
|
|
21
26
|
['mass driver', ITEM_MASS_DRIVER_T1_PACKED],
|
|
22
27
|
['mass catcher', ITEM_MASS_CATCHER_T1_PACKED],
|
|
23
28
|
] as const
|
|
@@ -28,21 +33,21 @@ for (const [label, itemId] of CONTAINER_ENTITIES) {
|
|
|
28
33
|
const resolved = resolveItem(UInt16.from(itemId), stats)
|
|
29
34
|
const hull = resolved.attributes?.find((g) => g.capability === 'Hull')
|
|
30
35
|
const capacity = hull?.attributes.find((a) => a.label === 'Capacity')?.value
|
|
31
|
-
const
|
|
36
|
+
const base = computeContainerCapabilities({
|
|
32
37
|
strength: 300,
|
|
33
38
|
hardness: 400,
|
|
34
39
|
density: 100,
|
|
35
40
|
}).capacity
|
|
36
|
-
expect(capacity).toBe(
|
|
41
|
+
expect(capacity).toBe(applyCapacityTier(base, getItem(itemId).tier))
|
|
37
42
|
})
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
test('resolveItem resolves the station hub with hullmass and zero cargo capacity', () => {
|
|
41
46
|
const stats = hullStats(300, 100, 400)
|
|
42
|
-
const resolved = resolveItem(UInt16.from(
|
|
47
|
+
const resolved = resolveItem(UInt16.from(ITEM_HUB_T2_PACKED), stats)
|
|
43
48
|
const hull = resolved.attributes?.find((g) => g.capability === 'Hull')
|
|
44
49
|
expect(hull?.attributes.find((a) => a.label === 'Mass')?.value).toBe(
|
|
45
|
-
computeBaseHullmass(
|
|
50
|
+
computeBaseHullmass(ITEM_HUB_T2_PACKED, {density: 100})
|
|
46
51
|
)
|
|
47
52
|
expect(hull?.attributes.find((a) => a.label === 'Capacity')?.value).toBe(0)
|
|
48
53
|
})
|