@shipload/sdk 2.0.0-rc12 → 2.0.0-rc14
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 +137 -57
- package/lib/shipload.js +636 -335
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +626 -334
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/modules.ts +3 -3
- package/src/capabilities/storage.ts +6 -9
- package/src/contracts/server.ts +37 -34
- package/src/data/colors.ts +19 -1
- package/src/data/recipes.ts +3 -3
- package/src/derivation/crafting.ts +46 -32
- package/src/derivation/stratum.ts +12 -0
- package/src/entities/container.ts +1 -0
- package/src/entities/makers.ts +126 -11
- package/src/entities/ship-deploy.ts +9 -14
- package/src/entities/ship.ts +16 -4
- package/src/entities/warehouse.ts +36 -1
- package/src/index-module.ts +22 -5
- package/src/managers/actions.ts +48 -8
- package/src/nft/description.ts +31 -30
- package/src/nft/deserializers.ts +8 -8
- package/src/resolution/describe-module.ts +165 -0
- package/src/resolution/resolve-item.ts +60 -37
- package/src/scheduling/projection.ts +17 -4
- package/src/types/capabilities.ts +5 -0
|
@@ -22,27 +22,27 @@ export interface CategoryStacks {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function encodeStats(values: number[]): bigint {
|
|
25
|
-
let
|
|
25
|
+
let stats = 0n
|
|
26
26
|
for (let i = 0; i < values.length && i < 6; i++) {
|
|
27
|
-
|
|
27
|
+
stats |= BigInt(values[i] & 0x3ff) << BigInt(i * 10)
|
|
28
28
|
}
|
|
29
|
-
return
|
|
29
|
+
return stats
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function decodeStat(
|
|
33
|
-
return Number((
|
|
32
|
+
export function decodeStat(stats: bigint, index: number): number {
|
|
33
|
+
return Number((stats >> BigInt(index * 10)) & 0x3ffn)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export function decodeStats(
|
|
37
|
-
const
|
|
36
|
+
export function decodeStats(stats: bigint, count: number): number[] {
|
|
37
|
+
const result: number[] = []
|
|
38
38
|
for (let i = 0; i < count; i++) {
|
|
39
|
-
|
|
39
|
+
result.push(decodeStat(stats, i))
|
|
40
40
|
}
|
|
41
|
-
return
|
|
41
|
+
return result
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function mapStatsToKeys(
|
|
45
|
-
const values = decodeStats(
|
|
44
|
+
function mapStatsToKeys(stats: bigint, statDefs: {key: string}[]): Record<string, number> {
|
|
45
|
+
const values = decodeStats(stats, statDefs.length)
|
|
46
46
|
const result: Record<string, number> = {}
|
|
47
47
|
for (let i = 0; i < statDefs.length; i++) {
|
|
48
48
|
result[statDefs[i].key] = values[i]
|
|
@@ -50,15 +50,15 @@ function mapStatsToKeys(seed: bigint, statDefs: {key: string}[]): Record<string,
|
|
|
50
50
|
return result
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function decodeCraftedItemStats(itemId: number,
|
|
53
|
+
export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
|
|
54
54
|
const comp = getComponentById(itemId)
|
|
55
|
-
if (comp) return mapStatsToKeys(
|
|
55
|
+
if (comp) return mapStatsToKeys(stats, comp.stats)
|
|
56
56
|
|
|
57
57
|
const entityRecipe = entityRecipes.find((r) => r.packedItemId === itemId)
|
|
58
|
-
if (entityRecipe) return mapStatsToKeys(
|
|
58
|
+
if (entityRecipe) return mapStatsToKeys(stats, entityRecipe.stats)
|
|
59
59
|
|
|
60
60
|
const moduleRecipe = moduleRecipes.find((r) => r.itemId === itemId)
|
|
61
|
-
if (moduleRecipe) return mapStatsToKeys(
|
|
61
|
+
if (moduleRecipe) return mapStatsToKeys(stats, moduleRecipe.stats)
|
|
62
62
|
|
|
63
63
|
return {}
|
|
64
64
|
}
|
|
@@ -126,12 +126,12 @@ export function computeEntityStats(
|
|
|
126
126
|
})
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
function decodeStackStats(itemId: number,
|
|
129
|
+
function decodeStackStats(itemId: number, stats: UInt64): Record<string, number> {
|
|
130
130
|
if (itemId >= 10000) {
|
|
131
|
-
return decodeCraftedItemStats(itemId, BigInt(
|
|
131
|
+
return decodeCraftedItemStats(itemId, BigInt(stats.toString()))
|
|
132
132
|
}
|
|
133
|
-
const
|
|
134
|
-
return {stat1:
|
|
133
|
+
const s = BigInt(stats.toString())
|
|
134
|
+
return {stat1: decodeStat(s, 0), stat2: decodeStat(s, 1), stat3: decodeStat(s, 2)}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
export const categoryItemMass: Record<string, number> = {
|
|
@@ -187,11 +187,11 @@ export function blendCrossGroup(sources: {value: number; weight: number}[]): num
|
|
|
187
187
|
|
|
188
188
|
export function blendCargoStacks(
|
|
189
189
|
itemId: number,
|
|
190
|
-
stacks: {quantity: number;
|
|
190
|
+
stacks: {quantity: number; stats: UInt64}[]
|
|
191
191
|
): UInt64 {
|
|
192
192
|
const decoded = stacks.map((s) => ({
|
|
193
193
|
quantity: s.quantity,
|
|
194
|
-
stats: decodeStackStats(itemId, s.
|
|
194
|
+
stats: decodeStackStats(itemId, s.stats),
|
|
195
195
|
}))
|
|
196
196
|
const allKeys = Object.keys(decoded[0]?.stats ?? {})
|
|
197
197
|
const blended = allKeys.map((key) => Math.max(1, Math.min(999, blendStacks(decoded, key))))
|
|
@@ -201,23 +201,22 @@ export function blendCargoStacks(
|
|
|
201
201
|
export interface RecipeSlotInput {
|
|
202
202
|
itemId: number
|
|
203
203
|
category: ResourceCategory | undefined
|
|
204
|
-
stacks: {quantity: number;
|
|
204
|
+
stacks: {quantity: number; stats: bigint}[]
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
function decodeRawStackToCategoryStats(
|
|
208
|
-
|
|
208
|
+
stats: bigint,
|
|
209
209
|
category: ResourceCategory
|
|
210
210
|
): Record<string, number> {
|
|
211
|
-
const raw = deriveResourceStats(seed)
|
|
212
211
|
const defs = getStatDefinitions(category)
|
|
213
212
|
const result: Record<string, number> = {}
|
|
214
|
-
if (defs[0]) result[defs[0].key] =
|
|
215
|
-
if (defs[1]) result[defs[1].key] =
|
|
216
|
-
if (defs[2]) result[defs[2].key] =
|
|
213
|
+
if (defs[0]) result[defs[0].key] = decodeStat(stats, 0)
|
|
214
|
+
if (defs[1]) result[defs[1].key] = decodeStat(stats, 1)
|
|
215
|
+
if (defs[2]) result[defs[2].key] = decodeStat(stats, 2)
|
|
217
216
|
return result
|
|
218
217
|
}
|
|
219
218
|
|
|
220
|
-
export function
|
|
219
|
+
export function computeCraftedOutputStats(
|
|
221
220
|
outputItemId: number,
|
|
222
221
|
slotInputs: RecipeSlotInput[]
|
|
223
222
|
): UInt64 {
|
|
@@ -230,8 +229,8 @@ export function computeCraftedOutputSeed(
|
|
|
230
229
|
const stacks: StackInput[] = slot.stacks.map((s) => ({
|
|
231
230
|
quantity: s.quantity,
|
|
232
231
|
stats: slotIsComponent
|
|
233
|
-
? decodeCraftedItemStats(slot.itemId, s.
|
|
234
|
-
: decodeRawStackToCategoryStats(s.
|
|
232
|
+
? decodeCraftedItemStats(slot.itemId, s.stats)
|
|
233
|
+
: decodeRawStackToCategoryStats(s.stats, slot.category!),
|
|
235
234
|
}))
|
|
236
235
|
categoryStacks.push({category: slot.category, stacks})
|
|
237
236
|
}
|
|
@@ -257,7 +256,7 @@ export function computeCraftedOutputSeed(
|
|
|
257
256
|
for (const s of slot.stacks) {
|
|
258
257
|
list.push({
|
|
259
258
|
quantity: s.quantity,
|
|
260
|
-
stats: decodeCraftedItemStats(slot.itemId, s.
|
|
259
|
+
stats: decodeCraftedItemStats(slot.itemId, s.stats),
|
|
261
260
|
})
|
|
262
261
|
}
|
|
263
262
|
}
|
|
@@ -269,5 +268,20 @@ export function computeCraftedOutputSeed(
|
|
|
269
268
|
return UInt64.from(encodeStats(ordered))
|
|
270
269
|
}
|
|
271
270
|
|
|
272
|
-
throw new Error(`
|
|
271
|
+
throw new Error(`computeCraftedOutputStats: no recipe found for outputItemId=${outputItemId}`)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Mirrors the contract's gather-time transform. Takes a deposit's entropy
|
|
276
|
+
* seed (bigint from deriveStratum), derives stats via weibull hashing, and
|
|
277
|
+
* returns a UInt64 whose bit-packed form matches what the contract writes
|
|
278
|
+
* to cargo_item.stats on gather.
|
|
279
|
+
*
|
|
280
|
+
* Use this whenever off-chain code simulates a gather (testmap, player
|
|
281
|
+
* scanners that project cargo outcomes) and needs a value that matches
|
|
282
|
+
* what on-chain cargo would carry.
|
|
283
|
+
*/
|
|
284
|
+
export function encodeGatheredCargoStats(depositSeed: bigint): UInt64 {
|
|
285
|
+
const raw = deriveResourceStats(depositSeed)
|
|
286
|
+
return UInt64.from(encodeStats([raw.stat1, raw.stat2, raw.stat3]))
|
|
273
287
|
}
|
|
@@ -89,6 +89,18 @@ export function deriveStratum(
|
|
|
89
89
|
return {itemId: selectedItemId, seed: seedBigInt, richness, reserve}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Derives the three stat values for a raw resource from a deposit's
|
|
94
|
+
* entropy seed (hash-based, weibull-transformed).
|
|
95
|
+
*
|
|
96
|
+
* **Use only on deposit seeds** — the bigint returned by `deriveStratum`
|
|
97
|
+
* or carried on a `MassDeposit`. Do NOT call this on a cargo item's
|
|
98
|
+
* `stats` field; cargo stats are bit-packed and must be read via
|
|
99
|
+
* `decodeStat` (or `decodeStackStats` for category-mapped output).
|
|
100
|
+
*
|
|
101
|
+
* Passing a cargo `stats` value here produces meaningless output
|
|
102
|
+
* (hash of the packed bits, unrelated to the actual stats).
|
|
103
|
+
*/
|
|
92
104
|
export function deriveResourceStats(seed: bigint): ResourceStats {
|
|
93
105
|
const seedBytes = new Uint8Array(8)
|
|
94
106
|
for (let i = 0; i < 8; i++) {
|
package/src/entities/makers.ts
CHANGED
|
@@ -1,8 +1,86 @@
|
|
|
1
|
-
import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
|
|
1
|
+
import {Name, UInt16, UInt32, UInt64, UInt8} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
|
-
import {Ship, ShipStateInput} from './ship'
|
|
4
|
-
import {Warehouse, WarehouseStateInput} from './warehouse'
|
|
3
|
+
import {PackedModuleInput, Ship, ShipStateInput} from './ship'
|
|
4
|
+
import {computeWarehouseCapabilities, Warehouse, WarehouseStateInput} from './warehouse'
|
|
5
5
|
import {Container, ContainerStateInput} from './container'
|
|
6
|
+
import {
|
|
7
|
+
getEntitySlotLayout,
|
|
8
|
+
getModuleRecipeByItemId,
|
|
9
|
+
ITEM_SHIP_T1_PACKED,
|
|
10
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
11
|
+
} from '../data/recipes'
|
|
12
|
+
import {getModuleCapabilityType, MODULE_STORAGE, moduleAccepts} from '../capabilities/modules'
|
|
13
|
+
import {computeShipCapabilities, computeStorageCapabilities} from './ship-deploy'
|
|
14
|
+
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
15
|
+
|
|
16
|
+
function assignModulesToSlots(
|
|
17
|
+
packedEntityItemId: number,
|
|
18
|
+
modules: PackedModuleInput[],
|
|
19
|
+
entityLabel: string
|
|
20
|
+
): ServerContract.Types.module_entry[] {
|
|
21
|
+
const slots = getEntitySlotLayout(packedEntityItemId)
|
|
22
|
+
const result: Array<{type: number; installed?: ServerContract.Types.packed_module}> = slots.map(
|
|
23
|
+
(s) => ({type: s.type, installed: undefined})
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
for (const mod of modules) {
|
|
27
|
+
const itemId = Number(UInt16.from(mod.itemId).value.toString())
|
|
28
|
+
const modType = getModuleCapabilityType(itemId)
|
|
29
|
+
const slotIdx = result.findIndex((r) => !r.installed && moduleAccepts(r.type, modType))
|
|
30
|
+
if (slotIdx === -1) {
|
|
31
|
+
const recipe = getModuleRecipeByItemId(itemId)
|
|
32
|
+
const modName = recipe?.name ?? `item ${itemId}`
|
|
33
|
+
throw new Error(
|
|
34
|
+
`No compatible slot for module ${modName} (type ${modType}) on ${entityLabel}`
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
result[slotIdx].installed = ServerContract.Types.packed_module.from({
|
|
38
|
+
item_id: UInt16.from(mod.itemId),
|
|
39
|
+
stats: UInt64.from(mod.stats),
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result.map((r) =>
|
|
44
|
+
ServerContract.Types.module_entry.from({
|
|
45
|
+
type: UInt8.from(r.type),
|
|
46
|
+
installed: r.installed,
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function decodePackedInput(m: PackedModuleInput): {itemId: number; stats: bigint} {
|
|
52
|
+
return {
|
|
53
|
+
itemId: Number(UInt16.from(m.itemId).value.toString()),
|
|
54
|
+
stats: BigInt(UInt64.from(m.stats).toString()),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function computeStorageBonus(
|
|
59
|
+
decoded: {itemId: number; stats: bigint}[],
|
|
60
|
+
baseCapacity: number
|
|
61
|
+
): number {
|
|
62
|
+
let totalBonus = 0
|
|
63
|
+
for (const m of decoded) {
|
|
64
|
+
if (getModuleCapabilityType(m.itemId) !== MODULE_STORAGE) continue
|
|
65
|
+
const stats = decodeCraftedItemStats(m.itemId, m.stats)
|
|
66
|
+
const {capacityBonus} = computeStorageCapabilities(stats, baseCapacity)
|
|
67
|
+
totalBonus += capacityBonus
|
|
68
|
+
}
|
|
69
|
+
return totalBonus
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function deriveShipFromModules(
|
|
73
|
+
modules: PackedModuleInput[],
|
|
74
|
+
baseCapacity: number
|
|
75
|
+
): {
|
|
76
|
+
capabilities: ReturnType<typeof computeShipCapabilities>
|
|
77
|
+
finalCapacity: number
|
|
78
|
+
} {
|
|
79
|
+
const decoded = modules.map(decodePackedInput)
|
|
80
|
+
const capabilities = computeShipCapabilities(decoded)
|
|
81
|
+
const totalBonus = computeStorageBonus(decoded, baseCapacity)
|
|
82
|
+
return {capabilities, finalCapacity: baseCapacity + totalBonus}
|
|
83
|
+
}
|
|
6
84
|
|
|
7
85
|
export function makeShip(state: ShipStateInput): Ship {
|
|
8
86
|
const info: Record<string, unknown> = {
|
|
@@ -19,14 +97,32 @@ export function makeShip(state: ShipStateInput): Ship {
|
|
|
19
97
|
pending_tasks: [],
|
|
20
98
|
}
|
|
21
99
|
if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
|
|
22
|
-
if (state.capacity !== undefined) info.capacity = UInt32.from(state.capacity)
|
|
23
100
|
if (state.energy !== undefined) info.energy = UInt16.from(state.energy)
|
|
24
|
-
if (state.engines) info.engines = state.engines
|
|
25
|
-
if (state.generator) info.generator = state.generator
|
|
26
|
-
if (state.loaders) info.loaders = state.loaders
|
|
27
101
|
if (state.schedule) info.schedule = state.schedule
|
|
102
|
+
|
|
103
|
+
let moduleEntries: ServerContract.Types.module_entry[] = []
|
|
104
|
+
if (state.modules && state.modules.length > 0) {
|
|
105
|
+
moduleEntries = assignModulesToSlots(ITEM_SHIP_T1_PACKED, state.modules, 'Ship T1')
|
|
106
|
+
const {capabilities, finalCapacity} = deriveShipFromModules(
|
|
107
|
+
state.modules,
|
|
108
|
+
state.capacity ?? 0
|
|
109
|
+
)
|
|
110
|
+
if (capabilities.engines) info.engines = capabilities.engines
|
|
111
|
+
if (capabilities.generator) info.generator = capabilities.generator
|
|
112
|
+
if (capabilities.gatherer) info.gatherer = capabilities.gatherer
|
|
113
|
+
if (capabilities.hauler) info.hauler = capabilities.hauler
|
|
114
|
+
if (capabilities.loaders) info.loaders = capabilities.loaders
|
|
115
|
+
if (capabilities.crafter) info.crafter = capabilities.crafter
|
|
116
|
+
if (state.capacity !== undefined) info.capacity = UInt32.from(finalCapacity)
|
|
117
|
+
} else {
|
|
118
|
+
moduleEntries = assignModulesToSlots(ITEM_SHIP_T1_PACKED, [], 'Ship T1')
|
|
119
|
+
if (state.capacity !== undefined) info.capacity = UInt32.from(state.capacity)
|
|
120
|
+
}
|
|
121
|
+
|
|
28
122
|
const entityInfo = ServerContract.Types.entity_info.from(info)
|
|
29
|
-
|
|
123
|
+
const ship = new Ship(entityInfo)
|
|
124
|
+
ship.setModules(moduleEntries)
|
|
125
|
+
return ship
|
|
30
126
|
}
|
|
31
127
|
|
|
32
128
|
export function makeWarehouse(state: WarehouseStateInput): Warehouse {
|
|
@@ -45,10 +141,29 @@ export function makeWarehouse(state: WarehouseStateInput): Warehouse {
|
|
|
45
141
|
pending_tasks: [],
|
|
46
142
|
}
|
|
47
143
|
if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
|
|
48
|
-
if (state.loaders) info.loaders = state.loaders
|
|
49
144
|
if (state.schedule) info.schedule = state.schedule
|
|
145
|
+
|
|
146
|
+
let moduleEntries: ServerContract.Types.module_entry[] = []
|
|
147
|
+
if (state.modules && state.modules.length > 0) {
|
|
148
|
+
moduleEntries = assignModulesToSlots(
|
|
149
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
150
|
+
state.modules,
|
|
151
|
+
'Warehouse T1'
|
|
152
|
+
)
|
|
153
|
+
const decoded = state.modules.map(decodePackedInput)
|
|
154
|
+
const capabilities = computeWarehouseCapabilities(decoded)
|
|
155
|
+
if (capabilities.loaders) info.loaders = capabilities.loaders
|
|
156
|
+
|
|
157
|
+
const totalBonus = computeStorageBonus(decoded, state.capacity)
|
|
158
|
+
info.capacity = UInt32.from(state.capacity + totalBonus)
|
|
159
|
+
} else {
|
|
160
|
+
moduleEntries = assignModulesToSlots(ITEM_WAREHOUSE_T1_PACKED, [], 'Warehouse T1')
|
|
161
|
+
}
|
|
162
|
+
|
|
50
163
|
const entityInfo = ServerContract.Types.entity_info.from(info)
|
|
51
|
-
|
|
164
|
+
const warehouse = new Warehouse(entityInfo)
|
|
165
|
+
warehouse.setModules(moduleEntries)
|
|
166
|
+
return warehouse
|
|
52
167
|
}
|
|
53
168
|
|
|
54
169
|
export function makeContainer(state: ContainerStateInput): Container {
|
|
@@ -61,7 +176,7 @@ export function makeContainer(state: ContainerStateInput): Container {
|
|
|
61
176
|
hullmass: UInt32.from(state.hullmass),
|
|
62
177
|
capacity: UInt32.from(state.capacity),
|
|
63
178
|
cargomass: UInt32.from(state.cargomass || 0),
|
|
64
|
-
cargo: [],
|
|
179
|
+
cargo: state.cargo || [],
|
|
65
180
|
is_idle: !state.schedule,
|
|
66
181
|
current_task_elapsed: UInt32.from(0),
|
|
67
182
|
current_task_remaining: UInt32.from(0),
|
|
@@ -48,7 +48,7 @@ export function computeGeneratorCapabilities(stats: Record<string, number>): {
|
|
|
48
48
|
|
|
49
49
|
return {
|
|
50
50
|
capacity: 300 + Math.floor(res / 6),
|
|
51
|
-
recharge:
|
|
51
|
+
recharge: 1 + Math.floor((clr * 3) / 1000),
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -65,7 +65,7 @@ export function computeGathererCapabilities(stats: Record<string, number>): {
|
|
|
65
65
|
|
|
66
66
|
return {
|
|
67
67
|
yield: 200 + str,
|
|
68
|
-
drain: Math.max(
|
|
68
|
+
drain: Math.max(250, 1250 - Math.floor((con * 25) / 20)),
|
|
69
69
|
depth: 200 + Math.floor((tol * 3) / 2),
|
|
70
70
|
speed: 100 + Math.floor((ref * 4) / 5),
|
|
71
71
|
}
|
|
@@ -160,7 +160,7 @@ export interface ShipCapabilities {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
export function computeShipCapabilities(
|
|
163
|
-
modules: {itemId: number;
|
|
163
|
+
modules: {itemId: number; stats: bigint}[]
|
|
164
164
|
): ShipCapabilities {
|
|
165
165
|
const ship: ShipCapabilities = {}
|
|
166
166
|
|
|
@@ -169,7 +169,7 @@ export function computeShipCapabilities(
|
|
|
169
169
|
let totalThrust = 0
|
|
170
170
|
let totalDrain = 0
|
|
171
171
|
for (const m of engineModules) {
|
|
172
|
-
const caps = computeEngineCapabilities(decodeCraftedItemStats(m.itemId, m.
|
|
172
|
+
const caps = computeEngineCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
173
173
|
totalThrust += caps.thrust
|
|
174
174
|
totalDrain += caps.drain
|
|
175
175
|
}
|
|
@@ -183,7 +183,7 @@ export function computeShipCapabilities(
|
|
|
183
183
|
let totalCapacity = 0
|
|
184
184
|
let totalRecharge = 0
|
|
185
185
|
for (const m of generatorModules) {
|
|
186
|
-
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.
|
|
186
|
+
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
187
187
|
totalCapacity += caps.capacity
|
|
188
188
|
totalRecharge += caps.recharge
|
|
189
189
|
}
|
|
@@ -199,7 +199,7 @@ export function computeShipCapabilities(
|
|
|
199
199
|
let totalDepth = 0
|
|
200
200
|
let totalSpeed = 0
|
|
201
201
|
for (const m of gathererModules) {
|
|
202
|
-
const caps = computeGathererCapabilities(decodeCraftedItemStats(m.itemId, m.
|
|
202
|
+
const caps = computeGathererCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
203
203
|
totalYield += caps.yield
|
|
204
204
|
totalDrain += caps.drain
|
|
205
205
|
totalDepth += caps.depth
|
|
@@ -214,12 +214,7 @@ export function computeShipCapabilities(
|
|
|
214
214
|
let weightedEffNum = 0
|
|
215
215
|
let totalDrain = 0
|
|
216
216
|
for (const m of haulerModules) {
|
|
217
|
-
const
|
|
218
|
-
const caps = computeHaulerCapabilities({
|
|
219
|
-
resonance: decoded.capacity,
|
|
220
|
-
conductivity: decoded.efficiency,
|
|
221
|
-
clarity: decoded.drain,
|
|
222
|
-
})
|
|
217
|
+
const caps = computeHaulerCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
223
218
|
totalCapacity += caps.capacity
|
|
224
219
|
weightedEffNum += caps.efficiency * caps.capacity
|
|
225
220
|
totalDrain += caps.drain
|
|
@@ -237,7 +232,7 @@ export function computeShipCapabilities(
|
|
|
237
232
|
let totalThrust = 0
|
|
238
233
|
let totalQuantity = 0
|
|
239
234
|
for (const m of loaderModules) {
|
|
240
|
-
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.
|
|
235
|
+
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
241
236
|
totalMass += caps.mass
|
|
242
237
|
totalThrust += caps.thrust
|
|
243
238
|
totalQuantity += caps.quantity
|
|
@@ -252,7 +247,7 @@ export function computeShipCapabilities(
|
|
|
252
247
|
let totalSpeed = 0
|
|
253
248
|
let totalDrain = 0
|
|
254
249
|
for (const m of crafterModules) {
|
|
255
|
-
const caps = computeManufacturingCapabilities(decodeCraftedItemStats(m.itemId, m.
|
|
250
|
+
const caps = computeManufacturingCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
256
251
|
totalSpeed += caps.speed
|
|
257
252
|
totalDrain += caps.drain
|
|
258
253
|
}
|
package/src/entities/ship.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {UInt16, UInt32, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
1
|
+
import {UInt16, UInt16Type, UInt32, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
3
|
import {Coordinates, CoordinatesType} from '../types'
|
|
4
4
|
import {
|
|
@@ -23,6 +23,11 @@ import {
|
|
|
23
23
|
} from '../capabilities/movement'
|
|
24
24
|
import * as schedule from '../scheduling/schedule'
|
|
25
25
|
|
|
26
|
+
export interface PackedModuleInput {
|
|
27
|
+
itemId: UInt16Type
|
|
28
|
+
stats: UInt64Type
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
export interface ShipStateInput {
|
|
27
32
|
id: UInt64Type
|
|
28
33
|
owner: string
|
|
@@ -31,9 +36,7 @@ export interface ShipStateInput {
|
|
|
31
36
|
hullmass?: number
|
|
32
37
|
capacity?: number
|
|
33
38
|
energy?: number
|
|
34
|
-
|
|
35
|
-
generator?: ServerContract.Types.energy_stats
|
|
36
|
-
loaders?: ServerContract.Types.loader_stats
|
|
39
|
+
modules?: PackedModuleInput[]
|
|
37
40
|
schedule?: ServerContract.Types.schedule
|
|
38
41
|
cargo?: ServerContract.Types.cargo_item[]
|
|
39
42
|
}
|
|
@@ -47,11 +50,20 @@ type MovementEntity = {
|
|
|
47
50
|
export class Ship extends ServerContract.Types.entity_info {
|
|
48
51
|
private _sched?: ScheduleAccessor
|
|
49
52
|
private _inv?: InventoryAccessor
|
|
53
|
+
private _modules: ServerContract.Types.module_entry[] = []
|
|
50
54
|
|
|
51
55
|
get name(): string {
|
|
52
56
|
return this.entity_name
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
get modules(): ServerContract.Types.module_entry[] {
|
|
60
|
+
return this._modules
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setModules(modules: ServerContract.Types.module_entry[]): void {
|
|
64
|
+
this._modules = modules
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
get inv(): InventoryAccessor {
|
|
56
68
|
return (this._inv ??= new InventoryAccessor(this))
|
|
57
69
|
}
|
|
@@ -6,6 +6,10 @@ import {ScheduleAccessor} from '../scheduling/accessor'
|
|
|
6
6
|
import {InventoryAccessor} from './inventory-accessor'
|
|
7
7
|
import {EntityInventory} from './entity-inventory'
|
|
8
8
|
import * as schedule from '../scheduling/schedule'
|
|
9
|
+
import type {PackedModuleInput} from './ship'
|
|
10
|
+
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
11
|
+
import {getModuleCapabilityType, MODULE_LOADER} from '../capabilities/modules'
|
|
12
|
+
import {computeLoaderCapabilities} from './ship-deploy'
|
|
9
13
|
|
|
10
14
|
export interface WarehouseStateInput {
|
|
11
15
|
id: UInt64Type
|
|
@@ -14,7 +18,7 @@ export interface WarehouseStateInput {
|
|
|
14
18
|
coordinates: CoordinatesType | {x: number; y: number; z?: number}
|
|
15
19
|
hullmass?: number
|
|
16
20
|
capacity: number
|
|
17
|
-
|
|
21
|
+
modules?: PackedModuleInput[]
|
|
18
22
|
schedule?: ServerContract.Types.schedule
|
|
19
23
|
cargo?: ServerContract.Types.cargo_item[]
|
|
20
24
|
}
|
|
@@ -22,11 +26,20 @@ export interface WarehouseStateInput {
|
|
|
22
26
|
export class Warehouse extends ServerContract.Types.entity_info {
|
|
23
27
|
private _sched?: ScheduleAccessor
|
|
24
28
|
private _inv?: InventoryAccessor
|
|
29
|
+
private _modules: ServerContract.Types.module_entry[] = []
|
|
25
30
|
|
|
26
31
|
get name(): string {
|
|
27
32
|
return this.entity_name
|
|
28
33
|
}
|
|
29
34
|
|
|
35
|
+
get modules(): ServerContract.Types.module_entry[] {
|
|
36
|
+
return this._modules
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setModules(modules: ServerContract.Types.module_entry[]): void {
|
|
40
|
+
this._modules = modules
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
get inv(): InventoryAccessor {
|
|
31
44
|
return (this._inv ??= new InventoryAccessor(this))
|
|
32
45
|
}
|
|
@@ -89,3 +102,25 @@ export class Warehouse extends ServerContract.Types.entity_info {
|
|
|
89
102
|
return hull.adding(this.totalCargoMass)
|
|
90
103
|
}
|
|
91
104
|
}
|
|
105
|
+
|
|
106
|
+
export function computeWarehouseCapabilities(modules: {itemId: number; stats: bigint}[]): {
|
|
107
|
+
loaders?: {mass: number; thrust: number; quantity: number}
|
|
108
|
+
} {
|
|
109
|
+
const warehouse: {loaders?: {mass: number; thrust: number; quantity: number}} = {}
|
|
110
|
+
|
|
111
|
+
const loaderModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_LOADER)
|
|
112
|
+
if (loaderModules.length > 0) {
|
|
113
|
+
let totalMass = 0
|
|
114
|
+
let totalThrust = 0
|
|
115
|
+
let totalQuantity = 0
|
|
116
|
+
for (const m of loaderModules) {
|
|
117
|
+
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
118
|
+
totalMass += caps.mass
|
|
119
|
+
totalThrust += caps.thrust
|
|
120
|
+
totalQuantity += caps.quantity
|
|
121
|
+
}
|
|
122
|
+
warehouse.loaders = {mass: totalMass, thrust: totalThrust, quantity: totalQuantity}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return warehouse
|
|
126
|
+
}
|
package/src/index-module.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {ServerContract} from './contracts'
|
|
|
6
6
|
|
|
7
7
|
export {Shipload} from './shipload'
|
|
8
8
|
export {Ship} from './entities/ship'
|
|
9
|
-
export type {ShipStateInput} from './entities/ship'
|
|
10
|
-
export {Warehouse} from './entities/warehouse'
|
|
9
|
+
export type {ShipStateInput, PackedModuleInput} from './entities/ship'
|
|
10
|
+
export {Warehouse, computeWarehouseCapabilities} from './entities/warehouse'
|
|
11
11
|
export type {WarehouseStateInput} from './entities/warehouse'
|
|
12
12
|
export {Container} from './entities/container'
|
|
13
13
|
export type {ContainerStateInput} from './entities/container'
|
|
@@ -143,7 +143,7 @@ export {
|
|
|
143
143
|
projectEntityAt,
|
|
144
144
|
validateSchedule,
|
|
145
145
|
} from './scheduling/projection'
|
|
146
|
-
export type {Projectable, ProjectedEntity} from './scheduling/projection'
|
|
146
|
+
export type {Projectable, ProjectedEntity, ProjectionOptions} from './scheduling/projection'
|
|
147
147
|
|
|
148
148
|
export * from './types/capabilities'
|
|
149
149
|
export * from './types/entity'
|
|
@@ -152,11 +152,14 @@ export * from './capabilities'
|
|
|
152
152
|
export {
|
|
153
153
|
categoryColors,
|
|
154
154
|
tierColors,
|
|
155
|
+
tierLabels,
|
|
155
156
|
categoryIcons,
|
|
157
|
+
categoryIconShapes,
|
|
156
158
|
componentIcon,
|
|
157
159
|
moduleIcon,
|
|
158
|
-
|
|
160
|
+
itemAbbreviations,
|
|
159
161
|
} from './data/colors'
|
|
162
|
+
export type {CategoryIconShape} from './data/colors'
|
|
160
163
|
|
|
161
164
|
export {itemTier, itemOffset, itemCategory, isRelatedItem, isCraftedItem} from './data/tiers'
|
|
162
165
|
export type {CraftedItemCategory} from './data/tiers'
|
|
@@ -226,6 +229,7 @@ export type {
|
|
|
226
229
|
|
|
227
230
|
export {
|
|
228
231
|
encodeStats,
|
|
232
|
+
encodeGatheredCargoStats,
|
|
229
233
|
decodeStat,
|
|
230
234
|
decodeStats,
|
|
231
235
|
decodeCraftedItemStats,
|
|
@@ -237,7 +241,7 @@ export {
|
|
|
237
241
|
blendCrossGroup,
|
|
238
242
|
categoryItemMass,
|
|
239
243
|
computeInputMass,
|
|
240
|
-
|
|
244
|
+
computeCraftedOutputStats,
|
|
241
245
|
} from './derivation/crafting'
|
|
242
246
|
export type {StackInput, CategoryStacks, RecipeSlotInput} from './derivation/crafting'
|
|
243
247
|
|
|
@@ -266,6 +270,19 @@ export type {
|
|
|
266
270
|
ResolvedItemType,
|
|
267
271
|
} from './resolution/resolve-item'
|
|
268
272
|
|
|
273
|
+
export {
|
|
274
|
+
describeModule,
|
|
275
|
+
describeModuleForItem,
|
|
276
|
+
describeModuleForSlot,
|
|
277
|
+
renderDescription,
|
|
278
|
+
} from './resolution/describe-module'
|
|
279
|
+
export type {
|
|
280
|
+
TextSpan,
|
|
281
|
+
CapabilityInput,
|
|
282
|
+
ModuleDescription,
|
|
283
|
+
RenderDescriptionOptions,
|
|
284
|
+
} from './resolution/describe-module'
|
|
285
|
+
|
|
269
286
|
export * as NFT from './nft'
|
|
270
287
|
export {
|
|
271
288
|
deserializeAsset,
|