@shipload/sdk 0.7.1 → 2.0.0-rc2

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 (62) hide show
  1. package/README.md +349 -1
  2. package/lib/shipload.d.ts +2016 -230
  3. package/lib/shipload.js +5733 -2094
  4. package/lib/shipload.js.map +1 -1
  5. package/lib/shipload.m.js +5425 -2012
  6. package/lib/shipload.m.js.map +1 -1
  7. package/package.json +5 -5
  8. package/src/capabilities/extraction.ts +37 -0
  9. package/src/capabilities/guards.ts +43 -0
  10. package/src/capabilities/index.ts +5 -0
  11. package/src/capabilities/loading.ts +8 -0
  12. package/src/capabilities/movement.ts +29 -0
  13. package/src/capabilities/storage.ts +67 -0
  14. package/src/contracts/server.ts +788 -202
  15. package/src/data/goods.json +23 -0
  16. package/src/data/syllables.json +1184 -0
  17. package/src/entities/cargo-utils.ts +142 -0
  18. package/src/entities/container.ts +70 -0
  19. package/src/entities/entity-inventory.ts +39 -0
  20. package/src/entities/gamestate.ts +152 -0
  21. package/src/entities/inventory-accessor.ts +46 -0
  22. package/src/entities/location.ts +255 -0
  23. package/src/entities/makers.ts +69 -0
  24. package/src/entities/player.ts +288 -0
  25. package/src/entities/ship.ts +208 -0
  26. package/src/entities/warehouse.ts +89 -0
  27. package/src/errors.ts +46 -9
  28. package/src/index-module.ts +152 -7
  29. package/src/managers/actions.ts +200 -0
  30. package/src/managers/base.ts +25 -0
  31. package/src/managers/context.ts +104 -0
  32. package/src/managers/entities.ts +103 -0
  33. package/src/managers/epochs.ts +47 -0
  34. package/src/managers/index.ts +9 -0
  35. package/src/managers/locations.ts +122 -0
  36. package/src/managers/players.ts +13 -0
  37. package/src/managers/trades.ts +119 -0
  38. package/src/market/goods.ts +31 -0
  39. package/src/{market.ts → market/market.ts} +31 -37
  40. package/src/{rolls.ts → market/rolls.ts} +3 -3
  41. package/src/scheduling/accessor.ts +82 -0
  42. package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
  43. package/src/scheduling/projection.ts +290 -0
  44. package/src/scheduling/schedule.ts +179 -0
  45. package/src/shipload.ts +39 -157
  46. package/src/trading/collect.ts +938 -0
  47. package/src/trading/deal.ts +207 -0
  48. package/src/trading/trade.ts +203 -0
  49. package/src/travel/travel.ts +486 -0
  50. package/src/types/capabilities.ts +79 -0
  51. package/src/types/entity-traits.ts +70 -0
  52. package/src/types/entity.ts +36 -0
  53. package/src/types/index.ts +3 -0
  54. package/src/types.ts +127 -25
  55. package/src/{hash.ts → utils/hash.ts} +1 -1
  56. package/src/utils/system.ts +155 -0
  57. package/src/goods.ts +0 -124
  58. package/src/ship.ts +0 -36
  59. package/src/state.ts +0 -0
  60. package/src/syllables.ts +0 -1184
  61. package/src/system.ts +0 -37
  62. package/src/travel.ts +0 -259
@@ -0,0 +1,290 @@
1
+ import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
2
+ import {ServerContract} from '../contracts'
3
+ import {Coordinates, PRECISION, TaskType} from '../types'
4
+ import {
5
+ capsHasLoaders,
6
+ capsHasMovement,
7
+ capsHasStorage,
8
+ EntityCapabilities,
9
+ EntityState,
10
+ } from '../types/capabilities'
11
+ import {distanceBetweenCoordinates, lerp} from '../travel/travel'
12
+ import {calcCargoMass} from '../capabilities/storage'
13
+ import {getGood} from '../market/goods'
14
+ import * as schedule from './schedule'
15
+ import {ScheduleData} from './schedule'
16
+
17
+ export interface ProjectedEntity {
18
+ location: Coordinates
19
+ energy: UInt16
20
+ cargoMass: UInt64
21
+ shipMass: UInt32
22
+ capacity?: UInt64
23
+ engines?: ServerContract.Types.movement_stats
24
+ loaders?: ServerContract.Types.loader_stats
25
+ generator?: ServerContract.Types.energy_stats
26
+ trade?: ServerContract.Types.trade_stats
27
+ readonly totalMass: UInt64
28
+
29
+ hasMovement(): boolean
30
+ hasStorage(): boolean
31
+ hasLoaders(): boolean
32
+ hasTrade(): boolean
33
+
34
+ capabilities(): EntityCapabilities
35
+ state(): EntityState
36
+ }
37
+
38
+ export interface Projectable extends ScheduleData {
39
+ coordinates: Coordinates | ServerContract.Types.coordinates
40
+ energy?: UInt16
41
+ hullmass?: UInt32
42
+ generator?: ServerContract.Types.energy_stats
43
+ engines?: ServerContract.Types.movement_stats
44
+ loaders?: ServerContract.Types.loader_stats
45
+ trade?: ServerContract.Types.trade_stats
46
+ capacity?: UInt32
47
+ cargo: ServerContract.Types.cargo_item[]
48
+ cargomass: UInt32
49
+ owner?: Name
50
+ }
51
+
52
+ function getHullMass(entity: Projectable): UInt32 {
53
+ return UInt32.from(entity.hullmass ?? 0)
54
+ }
55
+
56
+ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
57
+ const cargoMass = calcCargoMass(entity)
58
+ const shipMass = getHullMass(entity)
59
+ const loaders = entity.loaders
60
+ const engines = entity.engines
61
+ const generator = entity.generator
62
+ const trade = entity.trade
63
+ const capacity = entity.capacity
64
+
65
+ const projected: ProjectedEntity = {
66
+ location: Coordinates.from(entity.coordinates),
67
+ energy: UInt16.from(entity.energy ?? 0),
68
+ cargoMass,
69
+ shipMass,
70
+ capacity: capacity ? UInt64.from(capacity) : undefined,
71
+ engines,
72
+ generator,
73
+ loaders,
74
+ trade,
75
+
76
+ get totalMass() {
77
+ let mass = UInt64.from(this.shipMass).adding(this.cargoMass)
78
+ if (this.loaders) {
79
+ mass = mass.adding(this.loaders.mass.multiplying(this.loaders.quantity))
80
+ }
81
+ return mass
82
+ },
83
+
84
+ hasMovement() {
85
+ return capsHasMovement(this.capabilities())
86
+ },
87
+
88
+ hasStorage() {
89
+ return capsHasStorage(this.capabilities())
90
+ },
91
+
92
+ hasLoaders() {
93
+ return capsHasLoaders(this.capabilities())
94
+ },
95
+
96
+ hasTrade() {
97
+ return this.trade !== undefined
98
+ },
99
+
100
+ capabilities(): EntityCapabilities {
101
+ return {
102
+ hullmass: this.shipMass,
103
+ capacity: this.capacity ? UInt32.from(this.capacity) : undefined,
104
+ engines: this.engines,
105
+ generator: this.generator,
106
+ loaders: this.loaders,
107
+ trade: this.trade,
108
+ }
109
+ },
110
+
111
+ state(): EntityState {
112
+ return {
113
+ owner: entity.owner ?? Name.from(''),
114
+ location: ServerContract.Types.coordinates.from(this.location),
115
+ energy: this.energy,
116
+ cargomass: UInt32.from(this.cargoMass),
117
+ cargo: entity.cargo,
118
+ }
119
+ },
120
+ }
121
+
122
+ return projected
123
+ }
124
+
125
+ function applyRechargeTask(
126
+ projected: ProjectedEntity,
127
+ _task: ServerContract.Types.task,
128
+ options: {complete: boolean; progress?: number}
129
+ ): void {
130
+ if (!projected.generator) return
131
+
132
+ if (options.complete) {
133
+ projected.energy = UInt16.from(projected.generator.capacity)
134
+ } else if (options.progress !== undefined) {
135
+ const capacity = Number(projected.generator.capacity)
136
+ const currentEnergy = Number(projected.energy)
137
+ const rechargeAmount = (capacity - currentEnergy) * options.progress
138
+ projected.energy = UInt16.from(Math.min(capacity, currentEnergy + rechargeAmount))
139
+ }
140
+ }
141
+
142
+ function applyFlightTask(
143
+ projected: ProjectedEntity,
144
+ task: ServerContract.Types.task,
145
+ options: {complete: boolean; progress?: number}
146
+ ): void {
147
+ if (!task.coordinates || !projected.engines) return
148
+
149
+ const origin = projected.location
150
+ const destination = Coordinates.from(task.coordinates)
151
+ const distance = distanceBetweenCoordinates(origin, task.coordinates)
152
+ const energyUsage = distance.dividing(PRECISION).multiplying(projected.engines.drain)
153
+
154
+ if (options.complete) {
155
+ projected.energy = projected.energy.gt(energyUsage)
156
+ ? UInt16.from(projected.energy.subtracting(energyUsage))
157
+ : UInt16.from(0)
158
+ projected.location = destination
159
+ } else if (options.progress !== undefined) {
160
+ const interpolated = lerp(origin, destination, options.progress)
161
+ projected.location = Coordinates.from({
162
+ x: Math.round(interpolated.x),
163
+ y: Math.round(interpolated.y),
164
+ })
165
+ const partialEnergy = UInt64.from(Math.floor(Number(energyUsage) * options.progress))
166
+ projected.energy = projected.energy.gt(partialEnergy)
167
+ ? UInt16.from(projected.energy.subtracting(partialEnergy))
168
+ : UInt16.from(0)
169
+ }
170
+ }
171
+
172
+ function getGoodMass(good_id: UInt16 | number): UInt32 {
173
+ const good = getGood(good_id)
174
+ return good.mass
175
+ }
176
+
177
+ function applyLoadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
178
+ for (const item of task.cargo) {
179
+ const good_mass = getGoodMass(item.good_id)
180
+ projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
181
+ }
182
+ }
183
+
184
+ function applyUnloadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
185
+ for (const item of task.cargo) {
186
+ const good_mass = getGoodMass(item.good_id)
187
+ const cargoMass = good_mass.multiplying(item.quantity)
188
+ projected.cargoMass = projected.cargoMass.gt(cargoMass)
189
+ ? projected.cargoMass.subtracting(cargoMass)
190
+ : UInt64.from(0)
191
+ }
192
+ }
193
+
194
+ function applyExtractTask(
195
+ projected: ProjectedEntity,
196
+ task: ServerContract.Types.task,
197
+ options: {complete: boolean}
198
+ ): void {
199
+ if (!options.complete) return
200
+
201
+ if (task.energy_cost) {
202
+ const energyCost = UInt16.from(task.energy_cost)
203
+ projected.energy = projected.energy.gt(energyCost)
204
+ ? UInt16.from(projected.energy.subtracting(energyCost))
205
+ : UInt16.from(0)
206
+ }
207
+
208
+ for (const item of task.cargo) {
209
+ const good_mass = getGoodMass(item.good_id)
210
+ projected.cargoMass = projected.cargoMass.adding(good_mass.multiplying(item.quantity))
211
+ }
212
+ }
213
+
214
+ export function projectEntity(entity: Projectable): ProjectedEntity {
215
+ const projected = createProjectedEntity(entity)
216
+
217
+ if (!entity.schedule) {
218
+ return projected
219
+ }
220
+
221
+ for (const task of entity.schedule.tasks) {
222
+ switch (task.type.toNumber()) {
223
+ case TaskType.RECHARGE:
224
+ applyRechargeTask(projected, task, {complete: true})
225
+ break
226
+ case TaskType.TRAVEL:
227
+ applyFlightTask(projected, task, {complete: true})
228
+ break
229
+ case TaskType.LOAD:
230
+ applyLoadTask(projected, task)
231
+ break
232
+ case TaskType.UNLOAD:
233
+ applyUnloadTask(projected, task)
234
+ break
235
+ case TaskType.EXTRACT:
236
+ applyExtractTask(projected, task, {complete: true})
237
+ break
238
+ }
239
+ }
240
+
241
+ return projected
242
+ }
243
+
244
+ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity {
245
+ const projected = createProjectedEntity(entity)
246
+
247
+ if (!entity.schedule || entity.schedule.tasks.length === 0) {
248
+ return projected
249
+ }
250
+
251
+ for (let i = 0; i < entity.schedule.tasks.length; i++) {
252
+ const task = entity.schedule.tasks[i]
253
+ const taskComplete = schedule.isTaskComplete(entity, i, now)
254
+ const taskInProgress = schedule.isTaskInProgress(entity, i, now)
255
+
256
+ if (!taskComplete && !taskInProgress) {
257
+ break
258
+ }
259
+
260
+ const progress = taskInProgress
261
+ ? schedule.getTaskElapsed(entity, i, now) / task.duration.toNumber()
262
+ : undefined
263
+
264
+ switch (task.type.toNumber()) {
265
+ case TaskType.RECHARGE:
266
+ applyRechargeTask(projected, task, {complete: taskComplete, progress})
267
+ break
268
+ case TaskType.TRAVEL:
269
+ applyFlightTask(projected, task, {complete: taskComplete, progress})
270
+ break
271
+ case TaskType.LOAD:
272
+ if (taskComplete) {
273
+ applyLoadTask(projected, task)
274
+ }
275
+ break
276
+ case TaskType.UNLOAD:
277
+ if (taskComplete) {
278
+ applyUnloadTask(projected, task)
279
+ }
280
+ break
281
+ case TaskType.EXTRACT:
282
+ if (taskComplete) {
283
+ applyExtractTask(projected, task, {complete: true})
284
+ }
285
+ break
286
+ }
287
+ }
288
+
289
+ return projected
290
+ }
@@ -0,0 +1,179 @@
1
+ import {ServerContract} from '../contracts'
2
+ import {TaskType} from '../types'
3
+
4
+ type Schedule = ServerContract.Types.schedule
5
+ type Task = ServerContract.Types.task
6
+
7
+ export interface ScheduleData {
8
+ schedule?: Schedule
9
+ }
10
+
11
+ export interface Scheduleable extends ScheduleData {
12
+ hasSchedule: boolean
13
+ isIdle: boolean
14
+ tasks: Task[]
15
+ scheduleDuration(): number
16
+ scheduleElapsed(now: Date): number
17
+ scheduleRemaining(now: Date): number
18
+ scheduleComplete(now: Date): boolean
19
+ currentTaskIndex(now: Date): number
20
+ currentTask(now: Date): Task | undefined
21
+ currentTaskType(now: Date): TaskType | undefined
22
+ getTaskStartTime(index: number): number
23
+ getTaskElapsed(index: number, now: Date): number
24
+ getTaskRemaining(index: number, now: Date): number
25
+ isTaskComplete(index: number, now: Date): boolean
26
+ isTaskInProgress(index: number, now: Date): boolean
27
+ currentTaskProgress(now: Date): number
28
+ scheduleProgress(now: Date): number
29
+ }
30
+
31
+ export function hasSchedule(entity: ScheduleData): boolean {
32
+ return !!entity.schedule && entity.schedule.tasks.length > 0
33
+ }
34
+
35
+ export function isIdle(entity: ScheduleData): boolean {
36
+ return !hasSchedule(entity)
37
+ }
38
+
39
+ export function getTasks(entity: ScheduleData): Task[] {
40
+ return entity.schedule?.tasks || []
41
+ }
42
+
43
+ export function scheduleDuration(entity: ScheduleData): number {
44
+ if (!entity.schedule) return 0
45
+ return entity.schedule.tasks.reduce((sum, task) => sum + task.duration.toNumber(), 0)
46
+ }
47
+
48
+ export function scheduleElapsed(entity: ScheduleData, now: Date): number {
49
+ if (!entity.schedule) return 0
50
+ const started = entity.schedule.started.toDate()
51
+ const elapsed = Math.floor((now.getTime() - started.getTime()) / 1000)
52
+ return Math.max(0, elapsed)
53
+ }
54
+
55
+ export function scheduleRemaining(entity: ScheduleData, now: Date): number {
56
+ if (!entity.schedule) return 0
57
+ const duration = scheduleDuration(entity)
58
+ const elapsed = scheduleElapsed(entity, now)
59
+ return Math.max(0, duration - elapsed)
60
+ }
61
+
62
+ export function scheduleComplete(entity: ScheduleData, now: Date): boolean {
63
+ return hasSchedule(entity) && scheduleRemaining(entity, now) === 0
64
+ }
65
+
66
+ export function currentTaskIndex(entity: ScheduleData, now: Date): number {
67
+ if (!entity.schedule || entity.schedule.tasks.length === 0) return -1
68
+
69
+ const elapsed = scheduleElapsed(entity, now)
70
+ let timeAccum = 0
71
+
72
+ for (let i = 0; i < entity.schedule.tasks.length; i++) {
73
+ const taskDuration = entity.schedule.tasks[i].duration.toNumber()
74
+ if (elapsed < timeAccum + taskDuration) {
75
+ return i
76
+ }
77
+ timeAccum += taskDuration
78
+ }
79
+
80
+ return entity.schedule.tasks.length - 1
81
+ }
82
+
83
+ export function currentTask(entity: ScheduleData, now: Date): Task | undefined {
84
+ const index = currentTaskIndex(entity, now)
85
+ if (index < 0 || !entity.schedule) return undefined
86
+ return entity.schedule.tasks[index]
87
+ }
88
+
89
+ export function currentTaskType(entity: ScheduleData, now: Date): TaskType | undefined {
90
+ const task = currentTask(entity, now)
91
+ if (!task) return undefined
92
+ return task.type.toNumber() as TaskType
93
+ }
94
+
95
+ export function getTaskStartTime(entity: ScheduleData, index: number): number {
96
+ if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
97
+ let timeAccum = 0
98
+ for (let i = 0; i < index; i++) {
99
+ timeAccum += entity.schedule.tasks[i].duration.toNumber()
100
+ }
101
+ return timeAccum
102
+ }
103
+
104
+ export function getTaskElapsed(entity: ScheduleData, index: number, now: Date): number {
105
+ if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
106
+
107
+ const elapsed = scheduleElapsed(entity, now)
108
+ const taskStart = getTaskStartTime(entity, index)
109
+ const taskDuration = entity.schedule.tasks[index].duration.toNumber()
110
+
111
+ if (elapsed <= taskStart) return 0
112
+ const elapsedInTask = elapsed - taskStart
113
+ return Math.min(elapsedInTask, taskDuration)
114
+ }
115
+
116
+ export function getTaskRemaining(entity: ScheduleData, index: number, now: Date): number {
117
+ if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return 0
118
+
119
+ const taskDuration = entity.schedule.tasks[index].duration.toNumber()
120
+ const taskElapsed = getTaskElapsed(entity, index, now)
121
+ return Math.max(0, taskDuration - taskElapsed)
122
+ }
123
+
124
+ export function isTaskComplete(entity: ScheduleData, index: number, now: Date): boolean {
125
+ if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return false
126
+
127
+ const taskDuration = entity.schedule.tasks[index].duration.toNumber()
128
+ const taskElapsed = getTaskElapsed(entity, index, now)
129
+ return taskElapsed >= taskDuration
130
+ }
131
+
132
+ export function isTaskInProgress(entity: ScheduleData, index: number, now: Date): boolean {
133
+ if (!entity.schedule || index < 0 || index >= entity.schedule.tasks.length) return false
134
+
135
+ const taskElapsed = getTaskElapsed(entity, index, now)
136
+ const taskDuration = entity.schedule.tasks[index].duration.toNumber()
137
+ return taskElapsed > 0 && taskElapsed < taskDuration
138
+ }
139
+
140
+ export function currentTaskProgress(entity: ScheduleData, now: Date): number {
141
+ const task = currentTask(entity, now)
142
+ if (!task) return 0
143
+ const index = currentTaskIndex(entity, now)
144
+ const elapsed = getTaskElapsed(entity, index, now)
145
+ const duration = task.duration.toNumber()
146
+ if (duration === 0) return 1
147
+ return Math.min(1, elapsed / duration)
148
+ }
149
+
150
+ export function scheduleProgress(entity: ScheduleData, now: Date): number {
151
+ const duration = scheduleDuration(entity)
152
+ if (duration === 0) return hasSchedule(entity) ? 1 : 0
153
+ const elapsed = scheduleElapsed(entity, now)
154
+ return Math.min(1, elapsed / duration)
155
+ }
156
+
157
+ export function isTaskType(entity: ScheduleData, taskType: TaskType, now: Date): boolean {
158
+ return currentTaskType(entity, now) === taskType
159
+ }
160
+
161
+ export function isInFlight(entity: ScheduleData, now: Date): boolean {
162
+ return isTaskType(entity, TaskType.TRAVEL, now)
163
+ }
164
+
165
+ export function isRecharging(entity: ScheduleData, now: Date): boolean {
166
+ return isTaskType(entity, TaskType.RECHARGE, now)
167
+ }
168
+
169
+ export function isLoading(entity: ScheduleData, now: Date): boolean {
170
+ return isTaskType(entity, TaskType.LOAD, now)
171
+ }
172
+
173
+ export function isUnloading(entity: ScheduleData, now: Date): boolean {
174
+ return isTaskType(entity, TaskType.UNLOAD, now)
175
+ }
176
+
177
+ export function isExtracting(entity: ScheduleData, now: Date): boolean {
178
+ return isTaskType(entity, TaskType.EXTRACT, now)
179
+ }