@shipload/sdk 1.0.0-next.6 → 1.0.0-next.61
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 +3601 -1364
- package/lib/shipload.js +15671 -5261
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +15392 -5209
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1173 -0
- package/lib/testing.js +4971 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +4965 -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 +27 -30
- 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 +7 -8
- package/src/data/colors.ts +14 -48
- package/src/data/entities.json +380 -15
- package/src/data/item-ids.ts +51 -13
- package/src/data/items.json +318 -77
- package/src/data/kind-registry.json +195 -0
- package/src/data/kind-registry.ts +182 -0
- package/src/data/metadata.ts +291 -51
- package/src/data/recipes-runtime.ts +6 -23
- package/src/data/recipes.json +2260 -173
- package/src/data/tiers.ts +9 -6
- 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 +693 -0
- package/src/derivation/capability-mappings.ts +60 -16
- package/src/derivation/crafting.test.ts +17 -0
- package/src/derivation/crafting.ts +57 -34
- package/src/derivation/index.ts +27 -2
- package/src/derivation/recipe-usage.test.ts +90 -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 +388 -0
- package/src/nft/description.ts +215 -99
- 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
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {describe, expect, test} from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
derivedLoaders,
|
|
4
|
+
unwrapTransitDuration,
|
|
5
|
+
unwrapLoadDuration,
|
|
6
|
+
estimateUnwrapDuration,
|
|
7
|
+
incomingHoldMass,
|
|
8
|
+
projectedPeakCargomass,
|
|
9
|
+
} from './unwrap'
|
|
10
|
+
|
|
11
|
+
describe('unwrap duration mirror', () => {
|
|
12
|
+
test('derivedLoaders aggregates lanes like derived_loaders()', () => {
|
|
13
|
+
expect(derivedLoaders([])).toBeNull()
|
|
14
|
+
expect(
|
|
15
|
+
derivedLoaders([
|
|
16
|
+
{mass: 1000, thrust: 10},
|
|
17
|
+
{mass: 1400, thrust: 20},
|
|
18
|
+
])
|
|
19
|
+
).toEqual({mass: 1200, thrust: 30, quantity: 2}) // floor(2400/2)=1200, sum thrust, count
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('transit floors distance then flight time', () => {
|
|
23
|
+
// distance = floor(sqrt(3^2+4^2)*10000)=50000; accel=400/mass*10000; flight=floor(2*sqrt(d/accel))
|
|
24
|
+
const mass = 1000
|
|
25
|
+
const accel = (400 / mass) * 10000
|
|
26
|
+
const expected = Math.floor(2 * Math.sqrt(50000 / accel))
|
|
27
|
+
expect(unwrapTransitDuration(mass, {x: 0, y: 0}, {x: 3, y: 4})).toBe(expected)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('load uses altitude z, adds loader mass, divides by quantity', () => {
|
|
31
|
+
const loaders = {mass: 1200, thrust: 30, quantity: 2}
|
|
32
|
+
const itemMass = 800
|
|
33
|
+
const accel = (30 / (itemMass + 1200)) * 10000
|
|
34
|
+
const flight = Math.floor(2 * Math.sqrt(3000 / accel))
|
|
35
|
+
expect(unwrapLoadDuration(loaders, itemMass, 3000)).toBe(Math.floor(flight / 2))
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('zero item mass and no loaders are safe', () => {
|
|
39
|
+
expect(unwrapTransitDuration(0, {x: 0, y: 0}, {x: 9, y: 9})).toBe(0)
|
|
40
|
+
expect(unwrapLoadDuration(null, 500, 3000)).toBe(0)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('load altitude is floored so ground-level (z=0) destinations are not instant', () => {
|
|
44
|
+
const loaders = {mass: 500, thrust: 200, quantity: 1}
|
|
45
|
+
const atZero = unwrapLoadDuration(loaders, 1000, 0)
|
|
46
|
+
const at800 = unwrapLoadDuration(loaders, 1000, 800)
|
|
47
|
+
expect(atZero).toBeGreaterThan(0)
|
|
48
|
+
expect(atZero).toBe(at800)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('estimateUnwrapDuration uses worst-loader baseline when dest has no loaders', () => {
|
|
52
|
+
// IRON (101); same coords so transit is 0 and the estimate is baseline load alone
|
|
53
|
+
const item = {itemId: 101, quantity: 10, modules: [], originX: 0, originY: 0}
|
|
54
|
+
const bareDest = {loader_lanes: [], coordinates: {x: 0, y: 0, z: 800}}
|
|
55
|
+
|
|
56
|
+
const bare = estimateUnwrapDuration(bareDest, item)
|
|
57
|
+
expect(bare).toBeGreaterThan(0)
|
|
58
|
+
|
|
59
|
+
const loadedDest = {
|
|
60
|
+
loader_lanes: [{mass: 500, thrust: 200}],
|
|
61
|
+
coordinates: {x: 0, y: 0, z: 800},
|
|
62
|
+
}
|
|
63
|
+
const loaded = estimateUnwrapDuration(loadedDest, item)
|
|
64
|
+
expect(loaded).toBeLessThanOrEqual(bare)
|
|
65
|
+
|
|
66
|
+
expect(unwrapLoadDuration(null, 500, 3000)).toBe(0)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('incomingHoldMass sums incoming-kind hold mass', () => {
|
|
71
|
+
expect(incomingHoldMass([])).toBe(0)
|
|
72
|
+
// PUSH(2) + FLIGHT(5) count; BUILD(4) does not
|
|
73
|
+
expect(
|
|
74
|
+
incomingHoldMass([
|
|
75
|
+
{kind: 2, incoming_mass: 100},
|
|
76
|
+
{kind: 4, incoming_mass: 999},
|
|
77
|
+
{kind: 5, incoming_mass: 50},
|
|
78
|
+
])
|
|
79
|
+
).toBe(150)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('projectedPeakCargomass tracks the running peak from cargomass', () => {
|
|
83
|
+
const entity = {cargomass: 1000, lanes: [], cargo: [], schedule: undefined} as never
|
|
84
|
+
// No pending tasks: peak = base + candidate add.
|
|
85
|
+
expect(projectedPeakCargomass(entity, new Date(0), 500)).toBe(1500)
|
|
86
|
+
})
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type {UInt16Type, UInt32Type} from '@wharfkit/antelope'
|
|
2
|
+
import {calcCargoItemMass} from '../capabilities/storage'
|
|
3
|
+
import type {ServerContract} from '../contracts'
|
|
4
|
+
import {PRECISION} from '../types'
|
|
5
|
+
import * as sched from './schedule'
|
|
6
|
+
import {taskCargoEffect} from './availability'
|
|
7
|
+
import {candidateLaneCompletesAt} from './lanes'
|
|
8
|
+
|
|
9
|
+
const NFT_TRANSIT_THRUST = 400
|
|
10
|
+
const BASELINE_LOADER: DerivedLoaders = {mass: 2000, thrust: 1, quantity: 1}
|
|
11
|
+
// ground-level entities (warehouses, z=0) still incur a base orbital climb of load effort
|
|
12
|
+
const MIN_LOAD_Z = 800
|
|
13
|
+
|
|
14
|
+
export interface DerivedLoaders {
|
|
15
|
+
mass: number
|
|
16
|
+
thrust: number
|
|
17
|
+
quantity: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function derivedLoaders(
|
|
21
|
+
lanes: {mass: UInt32Type | number; thrust: UInt16Type | number}[] | undefined
|
|
22
|
+
): DerivedLoaders | null {
|
|
23
|
+
if (!lanes || lanes.length === 0) return null
|
|
24
|
+
let totalMass = 0
|
|
25
|
+
let totalThrust = 0
|
|
26
|
+
for (const l of lanes) {
|
|
27
|
+
totalMass += Number(l.mass)
|
|
28
|
+
totalThrust += Number(l.thrust)
|
|
29
|
+
}
|
|
30
|
+
const count = lanes.length
|
|
31
|
+
return {
|
|
32
|
+
mass: Math.floor(totalMass / count),
|
|
33
|
+
thrust: Math.min(totalThrust, 65_535),
|
|
34
|
+
quantity: count,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function acceleration(thrust: number, mass: number): number {
|
|
39
|
+
if (mass <= 0) return 0
|
|
40
|
+
return (thrust / mass) * PRECISION
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function flightTime(distance: number, accel: number): number {
|
|
44
|
+
if (accel <= 0 || distance <= 0) return 0
|
|
45
|
+
return Math.floor(2 * Math.sqrt(distance / accel))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function distance2d(ax: number, ay: number, bx: number, by: number): number {
|
|
49
|
+
const dx = ax - bx
|
|
50
|
+
const dy = ay - by
|
|
51
|
+
return Math.floor(Math.sqrt(dx * dx + dy * dy) * PRECISION)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function unwrapTransitDuration(
|
|
55
|
+
itemMass: number,
|
|
56
|
+
origin: {x: number; y: number},
|
|
57
|
+
dest: {x: number; y: number}
|
|
58
|
+
): number {
|
|
59
|
+
if (itemMass <= 0) return 0
|
|
60
|
+
return flightTime(
|
|
61
|
+
distance2d(origin.x, origin.y, dest.x, dest.y),
|
|
62
|
+
acceleration(NFT_TRANSIT_THRUST, itemMass)
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function unwrapLoadDuration(
|
|
67
|
+
loaders: DerivedLoaders | null,
|
|
68
|
+
itemMass: number,
|
|
69
|
+
destZ: number
|
|
70
|
+
): number {
|
|
71
|
+
if (!loaders || itemMass <= 0) return 0
|
|
72
|
+
const total = itemMass + loaders.mass
|
|
73
|
+
const flight = flightTime(Math.max(destZ, MIN_LOAD_Z), acceleration(loaders.thrust, total))
|
|
74
|
+
return Math.floor(flight / loaders.quantity)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface UnwrapItem {
|
|
78
|
+
itemId: number
|
|
79
|
+
quantity: number
|
|
80
|
+
modules: ServerContract.Types.module_entry[]
|
|
81
|
+
originX: number
|
|
82
|
+
originY: number
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface UnwrapDestination {
|
|
86
|
+
loader_lanes?: {mass: UInt32Type | number; thrust: UInt16Type | number}[]
|
|
87
|
+
coordinates: {x: UInt32Type | number; y: UInt32Type | number; z?: UInt32Type | number}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function estimateUnwrapDuration(dest: UnwrapDestination, item: UnwrapItem): number {
|
|
91
|
+
const itemMass = Number(
|
|
92
|
+
calcCargoItemMass({
|
|
93
|
+
item_id: item.itemId as never,
|
|
94
|
+
quantity: item.quantity as never,
|
|
95
|
+
modules: item.modules,
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
const loaders = derivedLoaders(dest.loader_lanes) ?? BASELINE_LOADER
|
|
99
|
+
const dz = Number(dest.coordinates.z ?? 0)
|
|
100
|
+
const load = unwrapLoadDuration(loaders, itemMass, dz)
|
|
101
|
+
const transit = unwrapTransitDuration(
|
|
102
|
+
itemMass,
|
|
103
|
+
{x: item.originX, y: item.originY},
|
|
104
|
+
{
|
|
105
|
+
x: Number(dest.coordinates.x),
|
|
106
|
+
y: Number(dest.coordinates.y),
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
return load + transit
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Hold kinds that count as incoming (mirror is_incoming_hold_kind in holds.hpp).
|
|
113
|
+
const INCOMING_HOLD_KINDS = new Set<number>([2, 3, 5])
|
|
114
|
+
|
|
115
|
+
export function incomingHoldMass(
|
|
116
|
+
holds:
|
|
117
|
+
| {kind: number | {toNumber(): number}; incoming_mass: number | {toNumber(): number}}[]
|
|
118
|
+
| undefined
|
|
119
|
+
): number {
|
|
120
|
+
if (!holds) return 0
|
|
121
|
+
let total = 0
|
|
122
|
+
for (const h of holds) {
|
|
123
|
+
if (INCOMING_HOLD_KINDS.has(Number(h.kind))) total += Number(h.incoming_mass)
|
|
124
|
+
}
|
|
125
|
+
return total
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
type CargoItem = ServerContract.Types.cargo_item
|
|
129
|
+
|
|
130
|
+
function cargoListMass(items: CargoItem[]): number {
|
|
131
|
+
let m = 0
|
|
132
|
+
for (const it of items) m += Number(calcCargoItemMass(it))
|
|
133
|
+
return m
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function projectedPeakCargomass(
|
|
137
|
+
entity: sched.ScheduleData & {cargomass: number | {toNumber(): number}},
|
|
138
|
+
at: Date,
|
|
139
|
+
addMass: number,
|
|
140
|
+
removeMass = 0
|
|
141
|
+
): number {
|
|
142
|
+
const events: {t: number; delta: number}[] = []
|
|
143
|
+
for (const ordered of sched.orderedTasks(entity)) {
|
|
144
|
+
const eff = taskCargoEffect(ordered.task)
|
|
145
|
+
const delta = cargoListMass(eff.added) - cargoListMass(eff.removed)
|
|
146
|
+
events.push({t: ordered.completesAt.getTime(), delta})
|
|
147
|
+
}
|
|
148
|
+
events.push({t: at.getTime(), delta: addMass - removeMass})
|
|
149
|
+
events.sort((a, b) => (a.t !== b.t ? a.t - b.t : b.delta - a.delta))
|
|
150
|
+
let running = Number(entity.cargomass)
|
|
151
|
+
let peak = running
|
|
152
|
+
for (const e of events) {
|
|
153
|
+
running += e.delta
|
|
154
|
+
if (running < 0) running = 0
|
|
155
|
+
if (running > peak) peak = running
|
|
156
|
+
}
|
|
157
|
+
return Math.min(peak, 0xffff_ffff)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function receiveFits(
|
|
161
|
+
dest: UnwrapDestination &
|
|
162
|
+
sched.ScheduleData & {
|
|
163
|
+
cargomass: number | {toNumber(): number}
|
|
164
|
+
capacity?: number | {toNumber(): number}
|
|
165
|
+
holds?: {
|
|
166
|
+
kind: number | {toNumber(): number}
|
|
167
|
+
incoming_mass: number | {toNumber(): number}
|
|
168
|
+
}[]
|
|
169
|
+
},
|
|
170
|
+
item: UnwrapItem,
|
|
171
|
+
now: Date
|
|
172
|
+
): boolean {
|
|
173
|
+
const capacity = Number(dest.capacity ?? 0)
|
|
174
|
+
if (capacity <= 0) return false
|
|
175
|
+
const itemMass = Number(
|
|
176
|
+
calcCargoItemMass({
|
|
177
|
+
item_id: item.itemId as never,
|
|
178
|
+
quantity: item.quantity as never,
|
|
179
|
+
modules: item.modules,
|
|
180
|
+
})
|
|
181
|
+
)
|
|
182
|
+
const duration = estimateUnwrapDuration(dest, item)
|
|
183
|
+
const candidateCompletes = candidateLaneCompletesAt(dest, sched.LANE_MOBILITY, duration, now)
|
|
184
|
+
const peak = projectedPeakCargomass(
|
|
185
|
+
dest,
|
|
186
|
+
candidateCompletes,
|
|
187
|
+
itemMass + incomingHoldMass(dest.holds)
|
|
188
|
+
)
|
|
189
|
+
return peak <= capacity
|
|
190
|
+
}
|
package/src/shipload.ts
CHANGED
|
@@ -7,8 +7,11 @@ import {GameContext} from './managers/context'
|
|
|
7
7
|
import type {EntitiesManager} from './managers/entities'
|
|
8
8
|
import type {PlayersManager} from './managers/players'
|
|
9
9
|
import type {LocationsManager} from './managers/locations'
|
|
10
|
+
import type {CoordinatesManager} from './managers/coordinates'
|
|
10
11
|
import type {EpochsManager} from './managers/epochs'
|
|
11
12
|
import type {ActionsManager} from './managers/actions'
|
|
13
|
+
import type {ClusterManager} from './managers/cluster'
|
|
14
|
+
import type {NftManager} from './managers/nft'
|
|
12
15
|
import type {SubscriptionsManager} from './subscriptions/manager'
|
|
13
16
|
import type {GameState} from './entities/gamestate'
|
|
14
17
|
|
|
@@ -17,6 +20,7 @@ interface ShiploadOptions {
|
|
|
17
20
|
serverContractName?: string
|
|
18
21
|
client?: APIClient
|
|
19
22
|
subscriptionsUrl?: string
|
|
23
|
+
atomicAssetsAccount?: string
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
interface ShiploadConstructorOptions extends ShiploadOptions {
|
|
@@ -39,7 +43,12 @@ export class Shipload {
|
|
|
39
43
|
? serverContract
|
|
40
44
|
: new ServerContract.Contract({client: apiClient})
|
|
41
45
|
|
|
42
|
-
this._context = new GameContext(
|
|
46
|
+
this._context = new GameContext(
|
|
47
|
+
apiClient,
|
|
48
|
+
server,
|
|
49
|
+
platform,
|
|
50
|
+
constructorOptions?.atomicAssetsAccount ?? 'atomicassets'
|
|
51
|
+
)
|
|
43
52
|
|
|
44
53
|
if (constructorOptions?.subscriptionsUrl) {
|
|
45
54
|
this._context.setSubscriptionsUrl(constructorOptions.subscriptionsUrl)
|
|
@@ -79,6 +88,10 @@ export class Shipload {
|
|
|
79
88
|
return this._context.client
|
|
80
89
|
}
|
|
81
90
|
|
|
91
|
+
get atomicAssetsAccount(): string {
|
|
92
|
+
return this._context.atomicAssetsAccount
|
|
93
|
+
}
|
|
94
|
+
|
|
82
95
|
get server(): Contract {
|
|
83
96
|
return this._context.server
|
|
84
97
|
}
|
|
@@ -99,6 +112,10 @@ export class Shipload {
|
|
|
99
112
|
return this._context.locations
|
|
100
113
|
}
|
|
101
114
|
|
|
115
|
+
get coordinates(): CoordinatesManager {
|
|
116
|
+
return this._context.coordinates
|
|
117
|
+
}
|
|
118
|
+
|
|
102
119
|
get epochs(): EpochsManager {
|
|
103
120
|
return this._context.epochs
|
|
104
121
|
}
|
|
@@ -107,6 +124,14 @@ export class Shipload {
|
|
|
107
124
|
return this._context.actions
|
|
108
125
|
}
|
|
109
126
|
|
|
127
|
+
get clusters(): ClusterManager {
|
|
128
|
+
return this._context.clusters
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get nft(): NftManager {
|
|
132
|
+
return this._context.nft
|
|
133
|
+
}
|
|
134
|
+
|
|
110
135
|
get subscriptions(): SubscriptionsManager {
|
|
111
136
|
return this._context.subscriptions
|
|
112
137
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {afterEach, describe, expect, test} from 'bun:test'
|
|
2
|
+
import {SubscriptionsManager} from './manager'
|
|
3
|
+
import type {ServerMessage} from './types'
|
|
4
|
+
|
|
5
|
+
function createManager(): SubscriptionsManager {
|
|
6
|
+
return new SubscriptionsManager({url: 'ws://localhost:0'})
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function deliver(mgr: SubscriptionsManager, msg: ServerMessage) {
|
|
10
|
+
;(mgr as unknown as {onMessage(m: ServerMessage): void}).onMessage(msg)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('cluster delta routing', () => {
|
|
14
|
+
let mgr: SubscriptionsManager | undefined
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
mgr?.close()
|
|
18
|
+
mgr = undefined
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('routes a cluster frame to the matching entity subscription onCluster', () => {
|
|
22
|
+
mgr = createManager()
|
|
23
|
+
const received: unknown[] = []
|
|
24
|
+
const handle = mgr.subscribeEntity(42, {
|
|
25
|
+
onCluster: (p) => received.push(p),
|
|
26
|
+
})
|
|
27
|
+
deliver(mgr, {
|
|
28
|
+
type: 'cluster',
|
|
29
|
+
sub_id: handle.subId,
|
|
30
|
+
hub_id: 42,
|
|
31
|
+
seq: 7,
|
|
32
|
+
cells: [{gx: 0, gy: 1, entity: 99, type: 'warehouse'}],
|
|
33
|
+
})
|
|
34
|
+
expect(received).toEqual([
|
|
35
|
+
{
|
|
36
|
+
hubId: 42,
|
|
37
|
+
seq: 7,
|
|
38
|
+
cells: [{gx: 0, gy: 1, entity: 99, type: 'warehouse'}],
|
|
39
|
+
erased: false,
|
|
40
|
+
},
|
|
41
|
+
])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('an erased cluster frame yields cells:null, erased:true', () => {
|
|
45
|
+
mgr = createManager()
|
|
46
|
+
const received: unknown[] = []
|
|
47
|
+
const handle = mgr.subscribeEntity(42, {onCluster: (p) => received.push(p)})
|
|
48
|
+
deliver(mgr, {type: 'cluster', sub_id: handle.subId, hub_id: 42, seq: 8, erased: true})
|
|
49
|
+
expect(received).toEqual([{hubId: 42, seq: 8, cells: null, erased: true}])
|
|
50
|
+
})
|
|
51
|
+
})
|