@shipload/sdk 1.0.0-next.6 → 1.0.0-next.8
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 +105 -62
- package/lib/shipload.js +322 -182
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +316 -181
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +71 -67
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +0 -16
- package/src/index-module.ts +11 -4
- package/src/managers/actions.ts +14 -20
- package/src/scheduling/predict-cargo.ts +151 -0
- package/src/travel/travel.ts +3 -1
- package/src/types/entity-traits.ts +38 -0
- package/src/types.ts +6 -0
- package/src/utils/cargo.ts +27 -0
- package/src/utils/system.ts +4 -16
package/src/managers/actions.ts
CHANGED
|
@@ -90,18 +90,15 @@ export class ActionsManager extends BaseManager {
|
|
|
90
90
|
sourceId: UInt64Type,
|
|
91
91
|
destType: EntityTypeName,
|
|
92
92
|
destId: UInt64Type,
|
|
93
|
-
|
|
94
|
-
stats: UInt64Type,
|
|
95
|
-
quantity: UInt64Type
|
|
93
|
+
items: ServerContract.ActionParams.Type.cargo_item[]
|
|
96
94
|
): Action {
|
|
95
|
+
const cargoItems = items.map((i) => ServerContract.Types.cargo_item.from(i))
|
|
97
96
|
return this.server.action('transfer', {
|
|
98
97
|
source_type: sourceType,
|
|
99
98
|
source_id: UInt64.from(sourceId),
|
|
100
99
|
dest_type: destType,
|
|
101
100
|
dest_id: UInt64.from(destId),
|
|
102
|
-
|
|
103
|
-
stats: UInt64.from(stats),
|
|
104
|
-
quantity: UInt32.from(quantity),
|
|
101
|
+
items: cargoItems,
|
|
105
102
|
})
|
|
106
103
|
}
|
|
107
104
|
|
|
@@ -187,14 +184,12 @@ export class ActionsManager extends BaseManager {
|
|
|
187
184
|
deploy(
|
|
188
185
|
entityType: EntityTypeName,
|
|
189
186
|
entityId: UInt64Type,
|
|
190
|
-
|
|
191
|
-
stats: bigint
|
|
187
|
+
ref: ServerContract.ActionParams.Type.cargo_ref
|
|
192
188
|
): Action {
|
|
193
189
|
return this.server.action('deploy', {
|
|
194
190
|
entity_type: entityType,
|
|
195
191
|
id: UInt64.from(entityId),
|
|
196
|
-
|
|
197
|
-
stats: UInt64.from(stats),
|
|
192
|
+
ref: ServerContract.Types.cargo_ref.from(ref),
|
|
198
193
|
})
|
|
199
194
|
}
|
|
200
195
|
|
|
@@ -202,15 +197,15 @@ export class ActionsManager extends BaseManager {
|
|
|
202
197
|
entityType: EntityTypeName,
|
|
203
198
|
entityId: UInt64Type,
|
|
204
199
|
moduleIndex: number,
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
moduleRef: ServerContract.ActionParams.Type.cargo_ref,
|
|
201
|
+
targetRef: ServerContract.ActionParams.Type.cargo_ref | null = null
|
|
207
202
|
): Action {
|
|
208
203
|
return this.server.action('addmodule', {
|
|
209
204
|
entity_type: entityType,
|
|
210
205
|
entity_id: UInt64.from(entityId),
|
|
211
206
|
module_index: moduleIndex,
|
|
212
|
-
|
|
213
|
-
|
|
207
|
+
module_ref: ServerContract.Types.cargo_ref.from(moduleRef),
|
|
208
|
+
target_ref: targetRef ? ServerContract.Types.cargo_ref.from(targetRef) : null,
|
|
214
209
|
})
|
|
215
210
|
}
|
|
216
211
|
|
|
@@ -218,13 +213,13 @@ export class ActionsManager extends BaseManager {
|
|
|
218
213
|
entityType: EntityTypeName,
|
|
219
214
|
entityId: UInt64Type,
|
|
220
215
|
moduleIndex: number,
|
|
221
|
-
|
|
216
|
+
targetRef: ServerContract.ActionParams.Type.cargo_ref | null = null
|
|
222
217
|
): Action {
|
|
223
218
|
return this.server.action('rmmodule', {
|
|
224
219
|
entity_type: entityType,
|
|
225
220
|
entity_id: UInt64.from(entityId),
|
|
226
221
|
module_index: moduleIndex,
|
|
227
|
-
|
|
222
|
+
target_ref: targetRef ? ServerContract.Types.cargo_ref.from(targetRef) : null,
|
|
228
223
|
})
|
|
229
224
|
}
|
|
230
225
|
|
|
@@ -232,15 +227,14 @@ export class ActionsManager extends BaseManager {
|
|
|
232
227
|
owner: NameType,
|
|
233
228
|
entityType: EntityTypeName,
|
|
234
229
|
entityId: UInt64Type,
|
|
235
|
-
|
|
236
|
-
quantity: UInt64Type
|
|
230
|
+
items: ServerContract.ActionParams.Type.cargo_item[]
|
|
237
231
|
): Action {
|
|
232
|
+
const cargoItems = items.map((i) => ServerContract.Types.cargo_item.from(i))
|
|
238
233
|
return this.server.action('wrap', {
|
|
239
234
|
owner: Name.from(owner),
|
|
240
235
|
entity_type: entityType,
|
|
241
236
|
entity_id: UInt64.from(entityId),
|
|
242
|
-
|
|
243
|
-
quantity: UInt64.from(quantity),
|
|
237
|
+
items: cargoItems,
|
|
244
238
|
})
|
|
245
239
|
}
|
|
246
240
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type {ServerContract} from '../contracts'
|
|
2
|
+
import {TaskType} from '../types'
|
|
3
|
+
|
|
4
|
+
export type PredictedCargoTarget = {kind: 'existing'; rowId: bigint} | {kind: 'new'; label: string}
|
|
5
|
+
|
|
6
|
+
export interface PredictedCargoAddition {
|
|
7
|
+
item_id: number
|
|
8
|
+
stats: bigint
|
|
9
|
+
modules: ServerContract.Types.module_entry[]
|
|
10
|
+
quantity: number
|
|
11
|
+
target: PredictedCargoTarget
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TaskCargoEffect {
|
|
15
|
+
additions: PredictedCargoAddition[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface StackState {
|
|
19
|
+
item_id: number
|
|
20
|
+
stats: bigint
|
|
21
|
+
modules: ServerContract.Types.module_entry[]
|
|
22
|
+
quantity: number
|
|
23
|
+
target: PredictedCargoTarget
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function modulesEqual(
|
|
27
|
+
a: ServerContract.Types.module_entry[],
|
|
28
|
+
b: ServerContract.Types.module_entry[]
|
|
29
|
+
): boolean {
|
|
30
|
+
if (a.length !== b.length) return false
|
|
31
|
+
for (let i = 0; i < a.length; i++) {
|
|
32
|
+
const ai = a[i]
|
|
33
|
+
const bi = b[i]
|
|
34
|
+
if (Number(ai.type) !== Number(bi.type)) return false
|
|
35
|
+
const aInst = ai.installed
|
|
36
|
+
const bInst = bi.installed
|
|
37
|
+
if (!aInst && !bInst) continue
|
|
38
|
+
if (!aInst || !bInst) return false
|
|
39
|
+
if (Number(aInst.item_id) !== Number(bInst.item_id)) return false
|
|
40
|
+
if (BigInt(aInst.stats.toString()) !== BigInt(bInst.stats.toString())) return false
|
|
41
|
+
}
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function findStack(
|
|
46
|
+
state: StackState[],
|
|
47
|
+
item_id: number,
|
|
48
|
+
stats: bigint,
|
|
49
|
+
modules: ServerContract.Types.module_entry[]
|
|
50
|
+
): number {
|
|
51
|
+
for (let i = 0; i < state.length; i++) {
|
|
52
|
+
const s = state[i]
|
|
53
|
+
if (s.item_id !== item_id) continue
|
|
54
|
+
if (s.stats !== stats) continue
|
|
55
|
+
if (!modulesEqual(s.modules, modules)) continue
|
|
56
|
+
return i
|
|
57
|
+
}
|
|
58
|
+
return -1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function applyAddition(
|
|
62
|
+
state: StackState[],
|
|
63
|
+
item: ServerContract.Types.cargo_item,
|
|
64
|
+
nextNewLabel: () => string
|
|
65
|
+
): PredictedCargoAddition {
|
|
66
|
+
const item_id = Number(item.item_id)
|
|
67
|
+
const stats = BigInt(item.stats.toString())
|
|
68
|
+
const modules = item.modules ?? []
|
|
69
|
+
const quantity = Number(item.quantity)
|
|
70
|
+
|
|
71
|
+
const idx = findStack(state, item_id, stats, modules)
|
|
72
|
+
if (idx === -1) {
|
|
73
|
+
const target: PredictedCargoTarget = {kind: 'new', label: nextNewLabel()}
|
|
74
|
+
state.push({item_id, stats, modules, quantity, target})
|
|
75
|
+
return {item_id, stats, modules, quantity, target}
|
|
76
|
+
}
|
|
77
|
+
state[idx].quantity += quantity
|
|
78
|
+
return {item_id, stats, modules, quantity, target: state[idx].target}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function applyRemoval(state: StackState[], item: ServerContract.Types.cargo_item): void {
|
|
82
|
+
const item_id = Number(item.item_id)
|
|
83
|
+
const stats = BigInt(item.stats.toString())
|
|
84
|
+
const modules = item.modules ?? []
|
|
85
|
+
const quantity = Number(item.quantity)
|
|
86
|
+
|
|
87
|
+
const idx = findStack(state, item_id, stats, modules)
|
|
88
|
+
if (idx === -1) return
|
|
89
|
+
state[idx].quantity -= quantity
|
|
90
|
+
if (state[idx].quantity <= 0) state.splice(idx, 1)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function predictTaskCargoEffects(
|
|
94
|
+
cargo: readonly ServerContract.Types.cargo_view[],
|
|
95
|
+
tasks: readonly ServerContract.Types.task[]
|
|
96
|
+
): TaskCargoEffect[] {
|
|
97
|
+
const state: StackState[] = cargo.map((c) => ({
|
|
98
|
+
item_id: Number(c.item_id),
|
|
99
|
+
stats: BigInt(c.stats.toString()),
|
|
100
|
+
modules: c.modules ?? [],
|
|
101
|
+
quantity: Number(c.quantity),
|
|
102
|
+
target: {kind: 'existing', rowId: BigInt(c.id.toString())},
|
|
103
|
+
}))
|
|
104
|
+
|
|
105
|
+
let newCounter = 0
|
|
106
|
+
const nextNewLabel = () => {
|
|
107
|
+
newCounter += 1
|
|
108
|
+
return `new#${newCounter}`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const effects: TaskCargoEffect[] = []
|
|
112
|
+
|
|
113
|
+
for (const task of tasks) {
|
|
114
|
+
const type = Number(task.type)
|
|
115
|
+
const items = task.cargo ?? []
|
|
116
|
+
const additions: PredictedCargoAddition[] = []
|
|
117
|
+
|
|
118
|
+
switch (type) {
|
|
119
|
+
case TaskType.LOAD:
|
|
120
|
+
case TaskType.UNWRAP: {
|
|
121
|
+
for (const item of items) additions.push(applyAddition(state, item, nextNewLabel))
|
|
122
|
+
break
|
|
123
|
+
}
|
|
124
|
+
case TaskType.GATHER: {
|
|
125
|
+
if (!task.entitytarget) {
|
|
126
|
+
for (const item of items)
|
|
127
|
+
additions.push(applyAddition(state, item, nextNewLabel))
|
|
128
|
+
}
|
|
129
|
+
break
|
|
130
|
+
}
|
|
131
|
+
case TaskType.UNLOAD:
|
|
132
|
+
case TaskType.WRAP: {
|
|
133
|
+
for (const item of items) applyRemoval(state, item)
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
case TaskType.CRAFT: {
|
|
137
|
+
if (items.length > 0) {
|
|
138
|
+
for (let i = 0; i < items.length - 1; i++) applyRemoval(state, items[i])
|
|
139
|
+
additions.push(applyAddition(state, items[items.length - 1], nextNewLabel))
|
|
140
|
+
}
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
default:
|
|
144
|
+
break
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
effects.push({additions})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return effects
|
|
151
|
+
}
|
package/src/travel/travel.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
type Distance,
|
|
29
29
|
MAX_ORBITAL_ALTITUDE,
|
|
30
30
|
MIN_ORBITAL_ALTITUDE,
|
|
31
|
+
MIN_TRANSFER_DISTANCE,
|
|
31
32
|
PRECISION,
|
|
32
33
|
type ShipLike,
|
|
33
34
|
TaskType,
|
|
@@ -547,7 +548,8 @@ export function calc_transfer_duration(
|
|
|
547
548
|
: (source.location.z?.toNumber() ?? 0)
|
|
548
549
|
const destZ =
|
|
549
550
|
typeof dest.location.z === 'number' ? dest.location.z : (dest.location.z?.toNumber() ?? 0)
|
|
550
|
-
const
|
|
551
|
+
const rawDistance = Math.abs(sourceZ - destZ)
|
|
552
|
+
const distance = rawDistance < MIN_TRANSFER_DISTANCE ? MIN_TRANSFER_DISTANCE : rawDistance
|
|
551
553
|
|
|
552
554
|
const totalMass = cargoMass + totalLoaderMass
|
|
553
555
|
const acceleration = calc_acceleration(totalThrust, totalMass)
|
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
import {Name} from '@wharfkit/antelope'
|
|
2
|
+
import {
|
|
3
|
+
ITEM_CONTAINER_T1_PACKED,
|
|
4
|
+
ITEM_CONTAINER_T2_PACKED,
|
|
5
|
+
ITEM_SHIP_T1_PACKED,
|
|
6
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
7
|
+
} from '../data/item-ids'
|
|
2
8
|
|
|
3
9
|
export const ENTITY_SHIP = Name.from('ship')
|
|
4
10
|
export const ENTITY_WAREHOUSE = Name.from('warehouse')
|
|
5
11
|
export const ENTITY_CONTAINER = Name.from('container')
|
|
6
12
|
|
|
13
|
+
export enum EntityClass {
|
|
14
|
+
OrbitalVessel = 0,
|
|
15
|
+
PlanetaryStructure = 1,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getEntityClass(entityType: Name | EntityTypeName): EntityClass {
|
|
19
|
+
const typeName = typeof entityType === 'string' ? entityType : entityType.toString()
|
|
20
|
+
switch (typeName) {
|
|
21
|
+
case 'ship':
|
|
22
|
+
case 'container':
|
|
23
|
+
return EntityClass.OrbitalVessel
|
|
24
|
+
case 'warehouse':
|
|
25
|
+
return EntityClass.PlanetaryStructure
|
|
26
|
+
default:
|
|
27
|
+
throw new Error(`Entity type has no class: ${typeName}`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getPackedEntityType(itemId: number): Name | null {
|
|
32
|
+
switch (itemId) {
|
|
33
|
+
case ITEM_SHIP_T1_PACKED:
|
|
34
|
+
return ENTITY_SHIP
|
|
35
|
+
case ITEM_CONTAINER_T1_PACKED:
|
|
36
|
+
case ITEM_CONTAINER_T2_PACKED:
|
|
37
|
+
return ENTITY_CONTAINER
|
|
38
|
+
case ITEM_WAREHOUSE_T1_PACKED:
|
|
39
|
+
return ENTITY_WAREHOUSE
|
|
40
|
+
default:
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
7
45
|
export type EntityTypeName = 'ship' | 'warehouse' | 'container'
|
|
8
46
|
|
|
9
47
|
export interface EntityTraits {
|
package/src/types.ts
CHANGED
|
@@ -23,6 +23,8 @@ export const MAX_ORBITAL_ALTITUDE = 3000
|
|
|
23
23
|
|
|
24
24
|
export const BASE_ORBITAL_MASS = 100000
|
|
25
25
|
|
|
26
|
+
export const MIN_TRANSFER_DISTANCE = 100
|
|
27
|
+
|
|
26
28
|
export interface ShipLike {
|
|
27
29
|
coordinates: ServerContract.Types.coordinates
|
|
28
30
|
hullmass?: UInt32
|
|
@@ -163,3 +165,7 @@ export interface Item {
|
|
|
163
165
|
export function formatTier(tier: number): string {
|
|
164
166
|
return 'T' + tier
|
|
165
167
|
}
|
|
168
|
+
|
|
169
|
+
export function tierAdjective(tier: number): string {
|
|
170
|
+
return TIER_ADJECTIVES[tier] ?? `T${tier}`
|
|
171
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type {ServerContract} from '../contracts'
|
|
2
|
+
|
|
3
|
+
export function cargoRef(src: {
|
|
4
|
+
item_id: number
|
|
5
|
+
stats: bigint | number
|
|
6
|
+
modules?: ServerContract.Types.module_entry[]
|
|
7
|
+
}): ServerContract.ActionParams.Type.cargo_ref {
|
|
8
|
+
return {
|
|
9
|
+
item_id: src.item_id,
|
|
10
|
+
stats: src.stats,
|
|
11
|
+
modules: src.modules ?? [],
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function cargoItem(
|
|
16
|
+
src: {
|
|
17
|
+
item_id: number
|
|
18
|
+
stats: bigint | number
|
|
19
|
+
modules?: ServerContract.Types.module_entry[]
|
|
20
|
+
},
|
|
21
|
+
quantity: bigint | number
|
|
22
|
+
): ServerContract.ActionParams.Type.cargo_item {
|
|
23
|
+
return {
|
|
24
|
+
...cargoRef(src),
|
|
25
|
+
quantity,
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/utils/system.ts
CHANGED
|
@@ -8,7 +8,6 @@ import nebulaAdjectives from '../data/nebula-adjectives.json'
|
|
|
8
8
|
import nebulaNouns from '../data/nebula-nouns.json'
|
|
9
9
|
|
|
10
10
|
const LOCATION_EXISTS_THRESHOLD = 0x10
|
|
11
|
-
const LOCATION_ACTIVE_THRESHOLD = 0x80
|
|
12
11
|
|
|
13
12
|
export function getLocationType(
|
|
14
13
|
gameSeed: Checksum256Type,
|
|
@@ -151,31 +150,20 @@ export function deriveLocationStatic(
|
|
|
151
150
|
return loc
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
export function
|
|
155
|
-
|
|
153
|
+
export function isLocationBuildable(
|
|
154
|
+
gameSeed: Checksum256Type,
|
|
156
155
|
coordinates: CoordinatesType
|
|
157
|
-
):
|
|
158
|
-
|
|
159
|
-
const coords = Coordinates.from(coordinates)
|
|
160
|
-
const str = `system-epoch-${coords.x}-${coords.y}`
|
|
161
|
-
const hashResult = hash512(seed, str)
|
|
162
|
-
|
|
163
|
-
return ServerContract.Types.location_epoch.from({
|
|
164
|
-
active: hashResult.array[0] < LOCATION_ACTIVE_THRESHOLD,
|
|
165
|
-
seed0: hashResult.array[1],
|
|
166
|
-
seed1: hashResult.array[2],
|
|
167
|
-
})
|
|
156
|
+
): boolean {
|
|
157
|
+
return getLocationType(gameSeed, coordinates) === LocationType.PLANET
|
|
168
158
|
}
|
|
169
159
|
|
|
170
160
|
export function deriveLocation(
|
|
171
161
|
gameSeed: Checksum256Type,
|
|
172
|
-
epochSeed: Checksum256Type,
|
|
173
162
|
coordinates: CoordinatesType
|
|
174
163
|
): ServerContract.Types.location_derived {
|
|
175
164
|
const staticProps = deriveLocationStatic(gameSeed, coordinates)
|
|
176
165
|
return ServerContract.Types.location_derived.from({
|
|
177
166
|
static_props: staticProps,
|
|
178
|
-
epoch_props: deriveLocationEpoch(epochSeed, coordinates),
|
|
179
167
|
size: deriveLocationSize(staticProps),
|
|
180
168
|
})
|
|
181
169
|
}
|