@shipload/sdk 0.7.1 → 2.0.0-rc1

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.
Files changed (47) hide show
  1. package/lib/shipload.d.ts +1651 -226
  2. package/lib/shipload.js +4958 -1971
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +4787 -1940
  5. package/lib/shipload.m.js.map +1 -1
  6. package/package.json +5 -4
  7. package/src/contracts/server.ts +585 -203
  8. package/src/data/goods.json +23 -0
  9. package/src/data/syllables.json +1184 -0
  10. package/src/entities/cargo-utils.ts +47 -0
  11. package/src/entities/entity-inventory.ts +39 -0
  12. package/src/entities/gamestate.ts +152 -0
  13. package/src/entities/location.ts +241 -0
  14. package/src/entities/player.ts +287 -0
  15. package/src/entities/ship.ts +559 -0
  16. package/src/entities/warehouse.ts +205 -0
  17. package/src/errors.ts +46 -9
  18. package/src/index-module.ts +119 -7
  19. package/src/managers/actions.ts +168 -0
  20. package/src/managers/base.ts +25 -0
  21. package/src/managers/context.ts +104 -0
  22. package/src/managers/entities.ts +86 -0
  23. package/src/managers/epochs.ts +47 -0
  24. package/src/managers/index.ts +9 -0
  25. package/src/managers/locations.ts +103 -0
  26. package/src/managers/players.ts +13 -0
  27. package/src/managers/trades.ts +119 -0
  28. package/src/market/goods.ts +31 -0
  29. package/src/{market.ts → market/market.ts} +32 -37
  30. package/src/{rolls.ts → market/rolls.ts} +3 -3
  31. package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
  32. package/src/scheduling/projection.ts +218 -0
  33. package/src/scheduling/schedule.ts +155 -0
  34. package/src/shipload.ts +39 -157
  35. package/src/trading/collect.ts +939 -0
  36. package/src/trading/deal.ts +208 -0
  37. package/src/trading/trade.ts +203 -0
  38. package/src/travel/travel.ts +425 -0
  39. package/src/types.ts +60 -25
  40. package/src/utils/system.ts +27 -0
  41. package/src/goods.ts +0 -124
  42. package/src/ship.ts +0 -36
  43. package/src/state.ts +0 -0
  44. package/src/syllables.ts +0 -1184
  45. package/src/system.ts +0 -37
  46. package/src/travel.ts +0 -259
  47. /package/src/{hash.ts → utils/hash.ts} +0 -0
@@ -0,0 +1,47 @@
1
+ import {UInt64, UInt64Type} from '@wharfkit/antelope'
2
+ import {EntityInventory} from './entity-inventory'
3
+
4
+ export interface CargoData {
5
+ cargo: EntityInventory[]
6
+ }
7
+
8
+ export function totalCargoMass(cargo: EntityInventory[]): UInt64 {
9
+ return cargo.reduce((sum, c) => {
10
+ return sum.adding(c.totalMass)
11
+ }, UInt64.from(0))
12
+ }
13
+
14
+ export function cargoValue(cargo: EntityInventory[]): UInt64 {
15
+ return cargo.reduce((sum, c) => {
16
+ return sum.adding(c.totalCost)
17
+ }, UInt64.from(0))
18
+ }
19
+
20
+ export function getCargoForGood(
21
+ cargo: EntityInventory[],
22
+ goodId: UInt64Type
23
+ ): EntityInventory | undefined {
24
+ return cargo.find((c) => c.good_id.equals(goodId))
25
+ }
26
+
27
+ export function hasSpace(
28
+ currentMass: UInt64,
29
+ maxCapacity: UInt64,
30
+ goodMass: UInt64,
31
+ quantity: number
32
+ ): boolean {
33
+ const additionalMass = goodMass.multiplying(quantity)
34
+ const totalMass = currentMass.adding(additionalMass)
35
+ return totalMass.lte(maxCapacity)
36
+ }
37
+
38
+ export function availableCapacity(currentMass: UInt64, maxCapacity: UInt64): UInt64 {
39
+ if (currentMass.gte(maxCapacity)) {
40
+ return UInt64.from(0)
41
+ }
42
+ return maxCapacity.subtracting(currentMass)
43
+ }
44
+
45
+ export function isFull(currentMass: UInt64, maxCapacity: UInt64): boolean {
46
+ return currentMass.gte(maxCapacity)
47
+ }
@@ -0,0 +1,39 @@
1
+ import {UInt32, UInt64} from '@wharfkit/antelope'
2
+ import {ServerContract} from '../contracts'
3
+ import {getGood} from '../market/goods'
4
+ import {Good} from '../types'
5
+
6
+ export class EntityInventory extends ServerContract.Types.cargo_item {
7
+ private _good?: Good
8
+
9
+ get good(): Good {
10
+ if (!this._good) {
11
+ this._good = getGood(this.good_id)
12
+ }
13
+ return this._good
14
+ }
15
+
16
+ get name(): string {
17
+ return this.good.name
18
+ }
19
+
20
+ get unitMass(): UInt32 {
21
+ return this.good.mass
22
+ }
23
+
24
+ get totalMass(): UInt64 {
25
+ return UInt64.from(this.unitMass).multiplying(this.quantity)
26
+ }
27
+
28
+ get totalCost(): UInt64 {
29
+ return this.unit_cost.multiplying(this.quantity)
30
+ }
31
+
32
+ get hasCargo(): boolean {
33
+ return UInt32.from(this.quantity).gt(UInt32.from(0))
34
+ }
35
+
36
+ get isEmpty(): boolean {
37
+ return UInt32.from(this.quantity).equals(UInt32.from(0))
38
+ }
39
+ }
@@ -0,0 +1,152 @@
1
+ import {Checksum256, Int64, UInt64} from '@wharfkit/antelope'
2
+ import {PlatformContract, ServerContract} from '../contracts'
3
+ import {EpochInfo, getCurrentEpoch, getEpochInfo} from '../scheduling/epoch'
4
+ import {hasSystem} from '../utils/system'
5
+
6
+ /**
7
+ * GameState class extends the state_row from the server contract
8
+ * with helper methods for epoch management and system generation
9
+ */
10
+ export class GameState extends ServerContract.Types.state_row {
11
+ private _game?: PlatformContract.Types.game_row
12
+
13
+ /**
14
+ * Create a GameState instance from a state_row
15
+ */
16
+ static from(
17
+ state: ServerContract.Types.state_row,
18
+ game?: PlatformContract.Types.game_row
19
+ ): GameState {
20
+ const gameState = Object.create(GameState.prototype) as GameState
21
+ Object.assign(gameState, state)
22
+ gameState._game = game
23
+ return gameState
24
+ }
25
+
26
+ /**
27
+ * Set the game configuration (needed for epoch calculations)
28
+ */
29
+ setGame(game: PlatformContract.Types.game_row): void {
30
+ this._game = game
31
+ }
32
+
33
+ /**
34
+ * Get the current epoch number from the state
35
+ */
36
+ get currentEpoch(): UInt64 {
37
+ return this.epoch
38
+ }
39
+
40
+ /**
41
+ * Get the epoch seed (used for market pricing and system generation)
42
+ */
43
+ get epochSeed(): Checksum256 {
44
+ return this.seed
45
+ }
46
+
47
+ /**
48
+ * Get the game seed (from game config, if available)
49
+ */
50
+ get gameSeed(): Checksum256 | undefined {
51
+ return this._game?.config.seed
52
+ }
53
+
54
+ /**
55
+ * Check if the game is currently enabled
56
+ */
57
+ get isEnabled(): boolean {
58
+ return this.enabled
59
+ }
60
+
61
+ /**
62
+ * Get the total number of ships in the game
63
+ */
64
+ get shipCount(): number {
65
+ return Number(this.ships)
66
+ }
67
+
68
+ /**
69
+ * Get the current salt value (used for random number generation)
70
+ */
71
+ get currentSalt(): UInt64 {
72
+ return this.salt
73
+ }
74
+
75
+ /**
76
+ * Get the commit hash for the next epoch
77
+ */
78
+ get nextEpochCommit(): Checksum256 {
79
+ return this.commit
80
+ }
81
+
82
+ /**
83
+ * Calculate the current epoch from game config (if game is set)
84
+ * This might differ from state.epoch if the blockchain hasn't advanced yet
85
+ */
86
+ get calculatedCurrentEpoch(): UInt64 | undefined {
87
+ if (!this._game) {
88
+ return undefined
89
+ }
90
+ return getCurrentEpoch(this._game)
91
+ }
92
+
93
+ /**
94
+ * Get epoch info (start/end times) for the current epoch
95
+ */
96
+ get currentEpochInfo(): EpochInfo | undefined {
97
+ if (!this._game) {
98
+ return undefined
99
+ }
100
+ return getEpochInfo(this._game, this.epoch)
101
+ }
102
+
103
+ /**
104
+ * Get epoch info for a specific epoch number
105
+ */
106
+ getEpochInfo(epoch: UInt64): EpochInfo | undefined {
107
+ if (!this._game) {
108
+ return undefined
109
+ }
110
+ return getEpochInfo(this._game, epoch)
111
+ }
112
+
113
+ /**
114
+ * Check if a system exists at given coordinates
115
+ * Requires game seed from game config
116
+ */
117
+ hasSystemAt(x: number, y: number): boolean {
118
+ if (!this._game) {
119
+ return false
120
+ }
121
+ return hasSystem(this._game.config.seed, {x: Int64.from(x), y: Int64.from(y)})
122
+ }
123
+
124
+ /**
125
+ * Check if a system exists at coordinates object
126
+ */
127
+ hasSystemAtCoords(coords: ServerContract.Types.coordinates): boolean {
128
+ if (!this._game) {
129
+ return false
130
+ }
131
+ return hasSystem(this._game.config.seed, coords)
132
+ }
133
+
134
+ /**
135
+ * Get a summary of the game state
136
+ */
137
+ get summary(): {
138
+ enabled: boolean
139
+ epoch: string
140
+ ships: number
141
+ hasSeed: boolean
142
+ hasCommit: boolean
143
+ } {
144
+ return {
145
+ enabled: this.enabled,
146
+ epoch: this.epoch.toString(),
147
+ ships: this.shipCount,
148
+ hasSeed: !this.seed.equals(Checksum256.from('0'.repeat(64))),
149
+ hasCommit: !this.commit.equals(Checksum256.from('0'.repeat(64))),
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,241 @@
1
+ import {Checksum256, Checksum256Type, UInt16, UInt16Type, UInt64} from '@wharfkit/antelope'
2
+ import {ServerContract} from '../contracts'
3
+ import {Coordinates, CoordinatesType, Distance, GoodPrice} from '../types'
4
+ import {hasSystem} from '../utils/system'
5
+ import {findNearbyPlanets} from '../travel/travel'
6
+
7
+ /**
8
+ * Location helper class for working with game coordinates.
9
+ * Provides system detection, market price caching, nearby planet finding, and supply tracking.
10
+ */
11
+ export class Location {
12
+ readonly coordinates: Coordinates
13
+ private _marketPrices?: GoodPrice[]
14
+ private _gameSeed?: Checksum256
15
+ private _hasSystem?: boolean
16
+ private _locationRows?: ServerContract.Types.location_row[]
17
+ private _epoch?: UInt64
18
+
19
+ constructor(coordinates: CoordinatesType) {
20
+ this.coordinates = Coordinates.from(coordinates)
21
+ }
22
+
23
+ /**
24
+ * Create a Location from coordinates
25
+ */
26
+ static from(coordinates: CoordinatesType): Location {
27
+ return new Location(Coordinates.from(coordinates))
28
+ }
29
+
30
+ /**
31
+ * Check if this location has a system (planet)
32
+ */
33
+ hasSystemAt(gameSeed: Checksum256Type): boolean {
34
+ const seed = Checksum256.from(gameSeed)
35
+ if (this._hasSystem === undefined || !this._gameSeed?.equals(seed)) {
36
+ this._gameSeed = seed
37
+ this._hasSystem = hasSystem(seed, this.coordinates)
38
+ }
39
+ return this._hasSystem
40
+ }
41
+
42
+ /**
43
+ * Set cached market prices for this location
44
+ */
45
+ setMarketPrices(prices: GoodPrice[]): void {
46
+ this._marketPrices = prices
47
+ }
48
+
49
+ /**
50
+ * Get cached market prices (returns undefined if not cached)
51
+ */
52
+ get marketPrices(): GoodPrice[] | undefined {
53
+ return this._marketPrices
54
+ }
55
+
56
+ /**
57
+ * Get price for a specific good (from cache)
58
+ */
59
+ getPrice(goodId: UInt16Type): GoodPrice | undefined {
60
+ if (!this._marketPrices) return undefined
61
+ return this._marketPrices.find((p) => p.id.equals(goodId))
62
+ }
63
+
64
+ /**
65
+ * Find nearby planets from this location
66
+ */
67
+ findNearby(gameSeed: Checksum256Type, maxDistance: UInt16Type = 20): Distance[] {
68
+ return findNearbyPlanets(Checksum256.from(gameSeed), this.coordinates, maxDistance)
69
+ }
70
+
71
+ /**
72
+ * Check if this location equals another location
73
+ */
74
+ equals(other: CoordinatesType | Location): boolean {
75
+ const otherCoords = other instanceof Location ? other.coordinates : Coordinates.from(other)
76
+ return this.coordinates.equals(otherCoords)
77
+ }
78
+
79
+ /**
80
+ * Set location rows (supply data) for this location
81
+ */
82
+ setLocationRows(rows: ServerContract.Types.location_row[], epoch: UInt64): void {
83
+ this._locationRows = rows
84
+ this._epoch = epoch
85
+ }
86
+
87
+ /**
88
+ * Get cached location rows (supply data)
89
+ */
90
+ get locationRows(): ServerContract.Types.location_row[] | undefined {
91
+ return this._locationRows
92
+ }
93
+
94
+ /**
95
+ * Get supply for a specific good at this location
96
+ * Returns undefined if location rows not cached or good not found
97
+ */
98
+ getSupply(goodId: UInt16Type): UInt16 | undefined {
99
+ if (!this._locationRows) return undefined
100
+ const row = this._locationRows.find(
101
+ (r) => r.good_id.equals(goodId) && this._epoch && r.epoch.equals(this._epoch)
102
+ )
103
+ return row ? row.supply : undefined
104
+ }
105
+
106
+ /**
107
+ * Get all available goods at this location (goods with supply > 0)
108
+ * Returns undefined if location rows not cached
109
+ */
110
+ get availableGoods(): ServerContract.Types.location_row[] | undefined {
111
+ if (!this._locationRows) return undefined
112
+ return this._locationRows.filter(
113
+ (r) => this._epoch && r.epoch.equals(this._epoch) && r.supply.gt(UInt16.from(0))
114
+ )
115
+ }
116
+
117
+ /**
118
+ * Check if a specific good is available (has supply)
119
+ * Returns false if location rows not cached
120
+ */
121
+ hasGood(goodId: UInt16Type): boolean {
122
+ const supply = this.getSupply(goodId)
123
+ return supply !== undefined && supply.gt(UInt16.from(0))
124
+ }
125
+
126
+ /**
127
+ * Get the epoch for cached location data
128
+ */
129
+ get epoch(): UInt64 | undefined {
130
+ return this._epoch
131
+ }
132
+
133
+ /**
134
+ * Check if cached data exists
135
+ */
136
+ get hasCachedData(): boolean {
137
+ return this._marketPrices !== undefined || this._locationRows !== undefined
138
+ }
139
+
140
+ /**
141
+ * Check if supply data is cached
142
+ */
143
+ get hasSupplyData(): boolean {
144
+ return this._locationRows !== undefined
145
+ }
146
+
147
+ /**
148
+ * Clear all cached data
149
+ */
150
+ clearCache(): void {
151
+ this._marketPrices = undefined
152
+ this._locationRows = undefined
153
+ this._epoch = undefined
154
+ }
155
+
156
+ /**
157
+ * Create optimistic Location with updated supply after purchase/sale.
158
+ * Matches contract: update_location_supply (delta can be positive or negative)
159
+ * Contract reference: market.cpp:53, 123-151
160
+ *
161
+ * @param goodId - Good ID to update supply for
162
+ * @param quantityDelta - Change in supply (negative for purchase, positive for sale)
163
+ * @returns New Location with updated supply in cached data
164
+ *
165
+ * @example
166
+ * // After buying 10 units (supply decreases)
167
+ * const newLocation = location.withUpdatedSupply(1, -10)
168
+ *
169
+ * // After selling 5 units (supply increases)
170
+ * const newLocation = location.withUpdatedSupply(1, 5)
171
+ */
172
+ withUpdatedSupply(goodId: UInt16Type, quantityDelta: number): Location {
173
+ const newLocation = Location.from(this.coordinates)
174
+
175
+ // Copy market prices if cached
176
+ if (this._marketPrices) {
177
+ newLocation._marketPrices = this._marketPrices.map((price) => {
178
+ if (price.id.equals(goodId)) {
179
+ const currentSupply = UInt16.from(price.supply)
180
+ const delta = UInt16.from(Math.abs(quantityDelta))
181
+ const newSupply =
182
+ quantityDelta < 0
183
+ ? currentSupply.gte(delta)
184
+ ? currentSupply.subtracting(delta)
185
+ : UInt16.from(0)
186
+ : currentSupply.adding(quantityDelta)
187
+
188
+ return GoodPrice.from({
189
+ id: price.id,
190
+ good: price.good,
191
+ price: price.price,
192
+ supply: newSupply,
193
+ })
194
+ }
195
+ return price
196
+ })
197
+ }
198
+
199
+ // Copy location rows if cached
200
+ if (this._locationRows && this._epoch) {
201
+ newLocation._locationRows = this._locationRows.map((row) => {
202
+ if (row.good_id.equals(goodId) && row.epoch.equals(this._epoch!)) {
203
+ const currentSupply = UInt16.from(row.supply)
204
+ const delta = UInt16.from(Math.abs(quantityDelta))
205
+ const newSupply =
206
+ quantityDelta < 0
207
+ ? currentSupply.gte(delta)
208
+ ? currentSupply.subtracting(delta)
209
+ : UInt16.from(0)
210
+ : currentSupply.adding(quantityDelta)
211
+
212
+ return ServerContract.Types.location_row.from({
213
+ id: row.id,
214
+ coordinates: row.coordinates,
215
+ epoch: row.epoch,
216
+ good_id: row.good_id,
217
+ supply: newSupply,
218
+ })
219
+ }
220
+ return row
221
+ })
222
+ newLocation._epoch = this._epoch
223
+ }
224
+
225
+ // Copy other cached data
226
+ newLocation._gameSeed = this._gameSeed
227
+ newLocation._hasSystem = this._hasSystem
228
+
229
+ return newLocation
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Helper function to convert various coordinate types to Location
235
+ */
236
+ export function toLocation(coords: CoordinatesType | Location): Location {
237
+ if (coords instanceof Location) {
238
+ return coords
239
+ }
240
+ return Location.from(coords)
241
+ }