@shipload/sdk 1.0.0-next.8 → 1.0.0-next.9
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 +133 -25
- package/lib/shipload.js +497 -155
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +477 -154
- package/lib/shipload.m.js.map +1 -1
- package/package.json +2 -2
- package/src/capabilities/storage.ts +1 -1
- package/src/contracts/server.ts +62 -1
- package/src/data/capability-formulas.ts +2 -0
- package/src/data/entities.json +33 -10
- package/src/data/item-ids.ts +1 -0
- package/src/data/items.json +6 -0
- package/src/data/metadata.ts +7 -0
- package/src/data/recipes-runtime.ts +1 -0
- package/src/data/recipes.json +49 -0
- package/src/derivation/capability-mappings.ts +2 -0
- package/src/entities/extractor.ts +144 -0
- package/src/entities/makers.ts +71 -20
- package/src/entities/ship-deploy.ts +35 -14
- package/src/entities/slot-multiplier.ts +21 -0
- package/src/entities/warehouse.ts +12 -3
- package/src/index-module.ts +25 -8
- package/src/managers/actions.ts +7 -0
- package/src/nft/description.ts +5 -0
- package/src/resolution/resolve-item.ts +3 -0
- package/src/scheduling/task-cargo.ts +47 -0
- package/src/types/entity-traits.ts +21 -1
- package/src/types.ts +1 -1
- package/src/scheduling/predict-cargo.ts +0 -151
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import {UInt64, type UInt64Type} from '@wharfkit/antelope'
|
|
2
|
+
import {ServerContract} from '../contracts'
|
|
3
|
+
import type {CoordinatesType} from '../types'
|
|
4
|
+
import {Location} from './location'
|
|
5
|
+
import {ScheduleAccessor} from '../scheduling/accessor'
|
|
6
|
+
import {InventoryAccessor} from './inventory-accessor'
|
|
7
|
+
import type {EntityInventory} from './entity-inventory'
|
|
8
|
+
import type {PackedModuleInput} from './ship'
|
|
9
|
+
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
10
|
+
import {getModuleCapabilityType, MODULE_GATHERER, MODULE_GENERATOR} from '../capabilities/modules'
|
|
11
|
+
import {computeGathererCapabilities, computeGeneratorCapabilities} from './ship-deploy'
|
|
12
|
+
import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
|
|
13
|
+
import type {EntitySlot} from '../data/recipes-runtime'
|
|
14
|
+
import {getItem} from '../data/catalog'
|
|
15
|
+
|
|
16
|
+
export interface ExtractorStateInput {
|
|
17
|
+
id: UInt64Type
|
|
18
|
+
owner: string
|
|
19
|
+
name: string
|
|
20
|
+
coordinates: CoordinatesType | {x: number; y: number; z?: number}
|
|
21
|
+
hullmass?: number
|
|
22
|
+
capacity?: number
|
|
23
|
+
energy?: number
|
|
24
|
+
modules?: PackedModuleInput[]
|
|
25
|
+
schedule?: ServerContract.Types.schedule
|
|
26
|
+
cargo?: ServerContract.Types.cargo_item[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class Extractor extends ServerContract.Types.entity_info {
|
|
30
|
+
private _sched?: ScheduleAccessor
|
|
31
|
+
private _inv?: InventoryAccessor
|
|
32
|
+
|
|
33
|
+
get name(): string {
|
|
34
|
+
return this.entity_name
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get entityClass(): 'building' {
|
|
38
|
+
return 'building'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get canDemolish(): boolean {
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get inv(): InventoryAccessor {
|
|
46
|
+
this._inv ??= new InventoryAccessor(this)
|
|
47
|
+
return this._inv
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get inventory(): EntityInventory[] {
|
|
51
|
+
return this.inv.items
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get sched(): ScheduleAccessor {
|
|
55
|
+
this._sched ??= new ScheduleAccessor(this)
|
|
56
|
+
return this._sched
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get isIdle(): boolean {
|
|
60
|
+
return this.is_idle
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get location(): Location {
|
|
64
|
+
return Location.from(this.coordinates)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get totalCargoMass(): UInt64 {
|
|
68
|
+
return this.inv.totalMass
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get maxCapacity(): UInt64 {
|
|
72
|
+
return UInt64.from(this.capacity)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get availableCapacity(): UInt64 {
|
|
76
|
+
const cargo = this.totalCargoMass
|
|
77
|
+
return cargo.gte(this.maxCapacity) ? UInt64.from(0) : this.maxCapacity.subtracting(cargo)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get isFull(): boolean {
|
|
81
|
+
return this.totalCargoMass.gte(this.maxCapacity)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get totalMass(): UInt64 {
|
|
85
|
+
const hull = this.hullmass ? UInt64.from(this.hullmass) : UInt64.from(0)
|
|
86
|
+
return hull.adding(this.totalCargoMass)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ExtractorCapabilities {
|
|
91
|
+
generator?: {capacity: number; recharge: number}
|
|
92
|
+
gatherer?: {yield: number; drain: number; depth: number; speed: number}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function computeExtractorCapabilities(
|
|
96
|
+
modules: InstalledModule[],
|
|
97
|
+
layout: EntitySlot[]
|
|
98
|
+
): ExtractorCapabilities {
|
|
99
|
+
const out: ExtractorCapabilities = {}
|
|
100
|
+
|
|
101
|
+
const genModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_GENERATOR)
|
|
102
|
+
if (genModules.length > 0) {
|
|
103
|
+
let totalCapacity = 0
|
|
104
|
+
let totalRecharge = 0
|
|
105
|
+
for (const m of genModules) {
|
|
106
|
+
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
107
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
108
|
+
totalCapacity += applySlotMultiplier(caps.capacity, amp)
|
|
109
|
+
totalRecharge += applySlotMultiplier(caps.recharge, amp)
|
|
110
|
+
}
|
|
111
|
+
out.generator = {
|
|
112
|
+
capacity: clampUint16(totalCapacity),
|
|
113
|
+
recharge: clampUint16(totalRecharge),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const gathModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_GATHERER)
|
|
118
|
+
if (gathModules.length > 0) {
|
|
119
|
+
let totalYield = 0
|
|
120
|
+
let totalDrain = 0
|
|
121
|
+
let maxDepth = 0
|
|
122
|
+
let totalSpeed = 0
|
|
123
|
+
for (const m of gathModules) {
|
|
124
|
+
const tier = getItem(m.itemId).tier
|
|
125
|
+
const caps = computeGathererCapabilities(
|
|
126
|
+
decodeCraftedItemStats(m.itemId, m.stats),
|
|
127
|
+
tier
|
|
128
|
+
)
|
|
129
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
130
|
+
totalYield += applySlotMultiplier(caps.yield, amp)
|
|
131
|
+
totalDrain += caps.drain
|
|
132
|
+
if (caps.depth > maxDepth) maxDepth = caps.depth
|
|
133
|
+
totalSpeed += applySlotMultiplier(caps.speed, amp)
|
|
134
|
+
}
|
|
135
|
+
out.gatherer = {
|
|
136
|
+
yield: clampUint16(totalYield),
|
|
137
|
+
drain: totalDrain,
|
|
138
|
+
depth: maxDepth,
|
|
139
|
+
speed: clampUint16(totalSpeed),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return out
|
|
144
|
+
}
|
package/src/entities/makers.ts
CHANGED
|
@@ -3,8 +3,13 @@ import {ServerContract} from '../contracts'
|
|
|
3
3
|
import {type PackedModuleInput, Ship, type ShipStateInput} from './ship'
|
|
4
4
|
import {computeWarehouseCapabilities, Warehouse, type WarehouseStateInput} from './warehouse'
|
|
5
5
|
import {Container, type ContainerStateInput} from './container'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import {Extractor, computeExtractorCapabilities, type ExtractorStateInput} from './extractor'
|
|
7
|
+
import {
|
|
8
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
9
|
+
ITEM_SHIP_T1_PACKED,
|
|
10
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
11
|
+
} from '../data/item-ids'
|
|
12
|
+
import {getEntityLayout, type EntitySlot} from '../data/recipes-runtime'
|
|
8
13
|
import {itemMetadata} from '../data/metadata'
|
|
9
14
|
import {getItem} from '../data/catalog'
|
|
10
15
|
import {
|
|
@@ -14,6 +19,7 @@ import {
|
|
|
14
19
|
moduleSlotTypeToCode,
|
|
15
20
|
} from '../capabilities/modules'
|
|
16
21
|
import {computeShipCapabilities, computeStorageCapabilities} from './ship-deploy'
|
|
22
|
+
import type {InstalledModule} from './slot-multiplier'
|
|
17
23
|
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
18
24
|
|
|
19
25
|
function assignModulesToSlots(
|
|
@@ -56,19 +62,22 @@ function assignModulesToSlots(
|
|
|
56
62
|
)
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
function toInstalledModules(entries: ServerContract.Types.module_entry[]): InstalledModule[] {
|
|
66
|
+
const installed: InstalledModule[] = []
|
|
67
|
+
entries.forEach((entry, slotIndex) => {
|
|
68
|
+
if (!entry.installed) return
|
|
69
|
+
installed.push({
|
|
70
|
+
slotIndex,
|
|
71
|
+
itemId: Number(UInt16.from(entry.installed.item_id).value.toString()),
|
|
72
|
+
stats: BigInt(UInt64.from(entry.installed.stats).toString()),
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
return installed
|
|
64
76
|
}
|
|
65
77
|
|
|
66
|
-
function computeStorageBonus(
|
|
67
|
-
decoded: {itemId: number; stats: bigint}[],
|
|
68
|
-
baseCapacity: number
|
|
69
|
-
): number {
|
|
78
|
+
function computeStorageBonus(modules: InstalledModule[], baseCapacity: number): number {
|
|
70
79
|
let totalBonus = 0
|
|
71
|
-
for (const m of
|
|
80
|
+
for (const m of modules) {
|
|
72
81
|
if (getModuleCapabilityType(m.itemId) !== MODULE_STORAGE) continue
|
|
73
82
|
const stats = decodeCraftedItemStats(m.itemId, m.stats)
|
|
74
83
|
const {capacityBonus} = computeStorageCapabilities(stats, baseCapacity)
|
|
@@ -78,15 +87,16 @@ function computeStorageBonus(
|
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
function deriveShipFromModules(
|
|
81
|
-
|
|
90
|
+
moduleEntries: ServerContract.Types.module_entry[],
|
|
91
|
+
layout: EntitySlot[],
|
|
82
92
|
baseCapacity: number
|
|
83
93
|
): {
|
|
84
94
|
capabilities: ReturnType<typeof computeShipCapabilities>
|
|
85
95
|
finalCapacity: number
|
|
86
96
|
} {
|
|
87
|
-
const
|
|
88
|
-
const capabilities = computeShipCapabilities(
|
|
89
|
-
const totalBonus = computeStorageBonus(
|
|
97
|
+
const installed = toInstalledModules(moduleEntries)
|
|
98
|
+
const capabilities = computeShipCapabilities(installed, layout)
|
|
99
|
+
const totalBonus = computeStorageBonus(installed, baseCapacity)
|
|
90
100
|
return {capabilities, finalCapacity: baseCapacity + totalBonus}
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -109,10 +119,12 @@ export function makeShip(state: ShipStateInput): Ship {
|
|
|
109
119
|
if (state.schedule) info.schedule = state.schedule
|
|
110
120
|
|
|
111
121
|
let moduleEntries: ServerContract.Types.module_entry[] = []
|
|
122
|
+
const shipLayout = getEntityLayout(ITEM_SHIP_T1_PACKED)?.slots ?? []
|
|
112
123
|
if (state.modules && state.modules.length > 0) {
|
|
113
124
|
moduleEntries = assignModulesToSlots(ITEM_SHIP_T1_PACKED, state.modules, 'Ship T1')
|
|
114
125
|
const {capabilities, finalCapacity} = deriveShipFromModules(
|
|
115
|
-
|
|
126
|
+
moduleEntries,
|
|
127
|
+
shipLayout,
|
|
116
128
|
state.capacity ?? 0
|
|
117
129
|
)
|
|
118
130
|
if (capabilities.engines) info.engines = capabilities.engines
|
|
@@ -152,17 +164,18 @@ export function makeWarehouse(state: WarehouseStateInput): Warehouse {
|
|
|
152
164
|
if (state.schedule) info.schedule = state.schedule
|
|
153
165
|
|
|
154
166
|
let moduleEntries: ServerContract.Types.module_entry[] = []
|
|
167
|
+
const warehouseLayout = getEntityLayout(ITEM_WAREHOUSE_T1_PACKED)?.slots ?? []
|
|
155
168
|
if (state.modules && state.modules.length > 0) {
|
|
156
169
|
moduleEntries = assignModulesToSlots(
|
|
157
170
|
ITEM_WAREHOUSE_T1_PACKED,
|
|
158
171
|
state.modules,
|
|
159
172
|
'Warehouse T1'
|
|
160
173
|
)
|
|
161
|
-
const
|
|
162
|
-
const capabilities = computeWarehouseCapabilities(
|
|
174
|
+
const installed = toInstalledModules(moduleEntries)
|
|
175
|
+
const capabilities = computeWarehouseCapabilities(installed, warehouseLayout)
|
|
163
176
|
if (capabilities.loaders) info.loaders = capabilities.loaders
|
|
164
177
|
|
|
165
|
-
const totalBonus = computeStorageBonus(
|
|
178
|
+
const totalBonus = computeStorageBonus(installed, state.capacity)
|
|
166
179
|
info.capacity = UInt32.from(state.capacity + totalBonus)
|
|
167
180
|
} else {
|
|
168
181
|
moduleEntries = assignModulesToSlots(ITEM_WAREHOUSE_T1_PACKED, [], 'Warehouse T1')
|
|
@@ -174,6 +187,44 @@ export function makeWarehouse(state: WarehouseStateInput): Warehouse {
|
|
|
174
187
|
return new Warehouse(entityInfo)
|
|
175
188
|
}
|
|
176
189
|
|
|
190
|
+
export function makeExtractor(state: ExtractorStateInput): Extractor {
|
|
191
|
+
const info: Record<string, unknown> = {
|
|
192
|
+
type: Name.from('extractor'),
|
|
193
|
+
id: UInt64.from(state.id),
|
|
194
|
+
owner: Name.from(state.owner),
|
|
195
|
+
entity_name: state.name,
|
|
196
|
+
coordinates: ServerContract.Types.coordinates.from(state.coordinates),
|
|
197
|
+
cargomass: UInt32.from(0),
|
|
198
|
+
cargo: state.cargo || [],
|
|
199
|
+
is_idle: !state.schedule,
|
|
200
|
+
current_task_elapsed: UInt32.from(0),
|
|
201
|
+
current_task_remaining: UInt32.from(0),
|
|
202
|
+
pending_tasks: [],
|
|
203
|
+
}
|
|
204
|
+
if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
|
|
205
|
+
if (state.energy !== undefined) info.energy = UInt16.from(state.energy)
|
|
206
|
+
if (state.schedule) info.schedule = state.schedule
|
|
207
|
+
if (state.capacity !== undefined) info.capacity = UInt32.from(state.capacity)
|
|
208
|
+
|
|
209
|
+
const moduleEntries = assignModulesToSlots(
|
|
210
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
211
|
+
state.modules ?? [],
|
|
212
|
+
'Extractor T1'
|
|
213
|
+
)
|
|
214
|
+
if (state.modules && state.modules.length > 0) {
|
|
215
|
+
const layout = getEntityLayout(ITEM_EXTRACTOR_T1_PACKED)?.slots ?? []
|
|
216
|
+
const installed = toInstalledModules(moduleEntries)
|
|
217
|
+
const capabilities = computeExtractorCapabilities(installed, layout)
|
|
218
|
+
if (capabilities.generator) info.generator = capabilities.generator
|
|
219
|
+
if (capabilities.gatherer) info.gatherer = capabilities.gatherer
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
info.modules = moduleEntries
|
|
223
|
+
|
|
224
|
+
const entityInfo = ServerContract.Types.entity_info.from(info)
|
|
225
|
+
return new Extractor(entityInfo)
|
|
226
|
+
}
|
|
227
|
+
|
|
177
228
|
export function makeContainer(state: ContainerStateInput): Container {
|
|
178
229
|
const entityInfo = ServerContract.Types.entity_info.from({
|
|
179
230
|
type: Name.from('container'),
|
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
MODULE_LOADER,
|
|
10
10
|
} from '../capabilities/modules'
|
|
11
11
|
import {getItem} from '../data/catalog'
|
|
12
|
+
import type {EntitySlot} from '../data/recipes-runtime'
|
|
13
|
+
import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
|
|
14
|
+
|
|
15
|
+
export type {InstalledModule}
|
|
12
16
|
|
|
13
17
|
export function computeShipHullCapabilities(stats: Record<string, number>): {
|
|
14
18
|
hullmass: number
|
|
@@ -193,7 +197,8 @@ export interface ShipCapabilities {
|
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
export function computeShipCapabilities(
|
|
196
|
-
modules:
|
|
200
|
+
modules: InstalledModule[],
|
|
201
|
+
layout: EntitySlot[]
|
|
197
202
|
): ShipCapabilities {
|
|
198
203
|
const ship: ShipCapabilities = {}
|
|
199
204
|
|
|
@@ -203,7 +208,7 @@ export function computeShipCapabilities(
|
|
|
203
208
|
let totalDrain = 0
|
|
204
209
|
for (const m of engineModules) {
|
|
205
210
|
const caps = computeEngineCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
206
|
-
totalThrust += caps.thrust
|
|
211
|
+
totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
|
|
207
212
|
totalDrain += caps.drain
|
|
208
213
|
}
|
|
209
214
|
ship.engines = {thrust: totalThrust, drain: totalDrain}
|
|
@@ -217,10 +222,14 @@ export function computeShipCapabilities(
|
|
|
217
222
|
let totalRecharge = 0
|
|
218
223
|
for (const m of generatorModules) {
|
|
219
224
|
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
220
|
-
|
|
221
|
-
|
|
225
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
226
|
+
totalCapacity += applySlotMultiplier(caps.capacity, amp)
|
|
227
|
+
totalRecharge += applySlotMultiplier(caps.recharge, amp)
|
|
228
|
+
}
|
|
229
|
+
ship.generator = {
|
|
230
|
+
capacity: clampUint16(totalCapacity),
|
|
231
|
+
recharge: clampUint16(totalRecharge),
|
|
222
232
|
}
|
|
223
|
-
ship.generator = {capacity: totalCapacity, recharge: totalRecharge}
|
|
224
233
|
}
|
|
225
234
|
|
|
226
235
|
const gathererModules = modules.filter(
|
|
@@ -237,12 +246,18 @@ export function computeShipCapabilities(
|
|
|
237
246
|
decodeCraftedItemStats(m.itemId, m.stats),
|
|
238
247
|
tier
|
|
239
248
|
)
|
|
240
|
-
|
|
249
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
250
|
+
totalYield += applySlotMultiplier(caps.yield, amp)
|
|
241
251
|
totalDrain += caps.drain
|
|
242
252
|
if (caps.depth > maxDepth) maxDepth = caps.depth
|
|
243
|
-
totalSpeed += caps.speed
|
|
253
|
+
totalSpeed += applySlotMultiplier(caps.speed, amp)
|
|
254
|
+
}
|
|
255
|
+
ship.gatherer = {
|
|
256
|
+
yield: clampUint16(totalYield),
|
|
257
|
+
drain: totalDrain,
|
|
258
|
+
depth: maxDepth,
|
|
259
|
+
speed: clampUint16(totalSpeed),
|
|
244
260
|
}
|
|
245
|
-
ship.gatherer = {yield: totalYield, drain: totalDrain, depth: maxDepth, speed: totalSpeed}
|
|
246
261
|
}
|
|
247
262
|
|
|
248
263
|
const haulerModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_HAULER)
|
|
@@ -252,13 +267,15 @@ export function computeShipCapabilities(
|
|
|
252
267
|
let totalDrain = 0
|
|
253
268
|
for (const m of haulerModules) {
|
|
254
269
|
const caps = computeHaulerCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
270
|
+
const eff = applySlotMultiplier(caps.efficiency, getSlotAmp(layout, m.slotIndex))
|
|
255
271
|
totalCapacity += caps.capacity
|
|
256
|
-
weightedEffNum +=
|
|
272
|
+
weightedEffNum += eff * caps.capacity
|
|
257
273
|
totalDrain += caps.drain
|
|
258
274
|
}
|
|
275
|
+
const efficiency = totalCapacity > 0 ? Math.floor(weightedEffNum / totalCapacity) : 0
|
|
259
276
|
ship.hauler = {
|
|
260
277
|
capacity: totalCapacity,
|
|
261
|
-
efficiency:
|
|
278
|
+
efficiency: clampUint16(efficiency),
|
|
262
279
|
drain: totalDrain,
|
|
263
280
|
}
|
|
264
281
|
}
|
|
@@ -271,10 +288,14 @@ export function computeShipCapabilities(
|
|
|
271
288
|
for (const m of loaderModules) {
|
|
272
289
|
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
273
290
|
totalMass += caps.mass
|
|
274
|
-
totalThrust += caps.thrust
|
|
291
|
+
totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
|
|
275
292
|
totalQuantity += caps.quantity
|
|
276
293
|
}
|
|
277
|
-
ship.loaders = {
|
|
294
|
+
ship.loaders = {
|
|
295
|
+
mass: totalMass,
|
|
296
|
+
thrust: clampUint16(totalThrust),
|
|
297
|
+
quantity: totalQuantity,
|
|
298
|
+
}
|
|
278
299
|
}
|
|
279
300
|
|
|
280
301
|
const crafterModules = modules.filter(
|
|
@@ -285,10 +306,10 @@ export function computeShipCapabilities(
|
|
|
285
306
|
let totalDrain = 0
|
|
286
307
|
for (const m of crafterModules) {
|
|
287
308
|
const caps = computeCrafterCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
288
|
-
totalSpeed += caps.speed
|
|
309
|
+
totalSpeed += applySlotMultiplier(caps.speed, getSlotAmp(layout, m.slotIndex))
|
|
289
310
|
totalDrain += caps.drain
|
|
290
311
|
}
|
|
291
|
-
ship.crafter = {speed: totalSpeed, drain: totalDrain}
|
|
312
|
+
ship.crafter = {speed: clampUint16(totalSpeed), drain: totalDrain}
|
|
292
313
|
}
|
|
293
314
|
|
|
294
315
|
return ship
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type {EntitySlot} from '../data/recipes-runtime'
|
|
2
|
+
|
|
3
|
+
export const U16_MAX = 65535
|
|
4
|
+
|
|
5
|
+
export interface InstalledModule {
|
|
6
|
+
slotIndex: number
|
|
7
|
+
itemId: number
|
|
8
|
+
stats: bigint
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function clampUint16(value: number): number {
|
|
12
|
+
return Math.min(value, U16_MAX)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function applySlotMultiplier(value: number, outputPct: number): number {
|
|
16
|
+
return clampUint16(Math.floor((value * outputPct) / 100))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getSlotAmp(layout: EntitySlot[], slotIndex: number): number {
|
|
20
|
+
return layout[slotIndex]?.outputPct ?? 100
|
|
21
|
+
}
|
|
@@ -10,6 +10,8 @@ import type {PackedModuleInput} from './ship'
|
|
|
10
10
|
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
11
11
|
import {getModuleCapabilityType, MODULE_LOADER} from '../capabilities/modules'
|
|
12
12
|
import {computeLoaderCapabilities} from './ship-deploy'
|
|
13
|
+
import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
|
|
14
|
+
import type {EntitySlot} from '../data/recipes-runtime'
|
|
13
15
|
|
|
14
16
|
export interface WarehouseStateInput {
|
|
15
17
|
id: UInt64Type
|
|
@@ -104,7 +106,10 @@ export class Warehouse extends ServerContract.Types.entity_info {
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
export function computeWarehouseCapabilities(
|
|
109
|
+
export function computeWarehouseCapabilities(
|
|
110
|
+
modules: InstalledModule[],
|
|
111
|
+
layout: EntitySlot[]
|
|
112
|
+
): {
|
|
108
113
|
loaders?: {mass: number; thrust: number; quantity: number}
|
|
109
114
|
} {
|
|
110
115
|
const warehouse: {loaders?: {mass: number; thrust: number; quantity: number}} = {}
|
|
@@ -117,10 +122,14 @@ export function computeWarehouseCapabilities(modules: {itemId: number; stats: bi
|
|
|
117
122
|
for (const m of loaderModules) {
|
|
118
123
|
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
119
124
|
totalMass += caps.mass
|
|
120
|
-
totalThrust += caps.thrust
|
|
125
|
+
totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
|
|
121
126
|
totalQuantity += caps.quantity
|
|
122
127
|
}
|
|
123
|
-
warehouse.loaders = {
|
|
128
|
+
warehouse.loaders = {
|
|
129
|
+
mass: totalMass,
|
|
130
|
+
thrust: clampUint16(totalThrust),
|
|
131
|
+
quantity: totalQuantity,
|
|
132
|
+
}
|
|
124
133
|
}
|
|
125
134
|
|
|
126
135
|
return warehouse
|
package/src/index-module.ts
CHANGED
|
@@ -16,9 +16,11 @@ export {Ship} from './entities/ship'
|
|
|
16
16
|
export type {ShipStateInput, PackedModuleInput} from './entities/ship'
|
|
17
17
|
export {Warehouse, computeWarehouseCapabilities} from './entities/warehouse'
|
|
18
18
|
export type {WarehouseStateInput} from './entities/warehouse'
|
|
19
|
+
export {Extractor, computeExtractorCapabilities} from './entities/extractor'
|
|
20
|
+
export type {ExtractorStateInput, ExtractorCapabilities} from './entities/extractor'
|
|
19
21
|
export {Container} from './entities/container'
|
|
20
22
|
export type {ContainerStateInput} from './entities/container'
|
|
21
|
-
export {makeShip, makeWarehouse, makeContainer} from './entities/makers'
|
|
23
|
+
export {makeShip, makeWarehouse, makeExtractor, makeContainer} from './entities/makers'
|
|
22
24
|
|
|
23
25
|
export type movement_stats = ServerContract.Types.movement_stats
|
|
24
26
|
export type energy_stats = ServerContract.Types.energy_stats
|
|
@@ -180,16 +182,29 @@ export type {
|
|
|
180
182
|
ProjectionOptions,
|
|
181
183
|
} from './scheduling/projection'
|
|
182
184
|
|
|
183
|
-
export {
|
|
184
|
-
export type {
|
|
185
|
-
PredictedCargoAddition,
|
|
186
|
-
PredictedCargoTarget,
|
|
187
|
-
TaskCargoEffect,
|
|
188
|
-
} from './scheduling/predict-cargo'
|
|
185
|
+
export {taskCargoChanges} from './scheduling/task-cargo'
|
|
186
|
+
export type {TaskCargoChange, TaskCargoDirection} from './scheduling/task-cargo'
|
|
189
187
|
|
|
190
188
|
export * from './types/capabilities'
|
|
191
189
|
export * from './types/entity'
|
|
192
|
-
export {
|
|
190
|
+
export {
|
|
191
|
+
EntityClass,
|
|
192
|
+
ENTITY_SHIP,
|
|
193
|
+
ENTITY_WAREHOUSE,
|
|
194
|
+
ENTITY_EXTRACTOR,
|
|
195
|
+
ENTITY_CONTAINER,
|
|
196
|
+
shipTraits,
|
|
197
|
+
warehouseTraits,
|
|
198
|
+
extractorTraits,
|
|
199
|
+
containerTraits,
|
|
200
|
+
getEntityClass,
|
|
201
|
+
getPackedEntityType,
|
|
202
|
+
getEntityTraits,
|
|
203
|
+
isShip,
|
|
204
|
+
isWarehouse,
|
|
205
|
+
isExtractor,
|
|
206
|
+
isContainer,
|
|
207
|
+
} from './types/entity-traits'
|
|
193
208
|
export * from './capabilities'
|
|
194
209
|
|
|
195
210
|
export {
|
|
@@ -323,6 +338,8 @@ export {
|
|
|
323
338
|
computeLoaderThrust,
|
|
324
339
|
computeCrafterSpeed,
|
|
325
340
|
computeCrafterDrain,
|
|
341
|
+
computeHaulerCapacity,
|
|
342
|
+
computeHaulerEfficiency,
|
|
326
343
|
computeWarpRange,
|
|
327
344
|
} from './nft/description'
|
|
328
345
|
|
package/src/managers/actions.ts
CHANGED
|
@@ -85,6 +85,13 @@ export class ActionsManager extends BaseManager {
|
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
refrshentity(entityType: NameType, entityId: UInt64Type): Action {
|
|
89
|
+
return this.server.action('refrshentity', {
|
|
90
|
+
entity_type: Name.from(entityType),
|
|
91
|
+
entity_id: UInt64.from(entityId),
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
88
95
|
transfer(
|
|
89
96
|
sourceType: EntityTypeName,
|
|
90
97
|
sourceId: UInt64Type,
|
package/src/nft/description.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
ITEM_CONTAINER_T2_PACKED,
|
|
15
15
|
ITEM_CRAFTER_T1,
|
|
16
16
|
ITEM_ENGINE_T1,
|
|
17
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
17
18
|
ITEM_GATHERER_T1,
|
|
18
19
|
ITEM_GENERATOR_T1,
|
|
19
20
|
ITEM_HAULER_T1,
|
|
@@ -71,6 +72,8 @@ export function entityDisplayName(itemId: number): string {
|
|
|
71
72
|
return 'Ship'
|
|
72
73
|
case ITEM_WAREHOUSE_T1_PACKED:
|
|
73
74
|
return 'Warehouse'
|
|
75
|
+
case ITEM_EXTRACTOR_T1_PACKED:
|
|
76
|
+
return 'Extractor'
|
|
74
77
|
case ITEM_CONTAINER_T1_PACKED:
|
|
75
78
|
return 'Container'
|
|
76
79
|
case ITEM_CONTAINER_T2_PACKED:
|
|
@@ -187,6 +190,8 @@ export function buildEntityDescription(
|
|
|
187
190
|
baseCapacity = computeBaseCapacityShip(hullStats)
|
|
188
191
|
} else if (itemId === ITEM_WAREHOUSE_T1_PACKED) {
|
|
189
192
|
baseCapacity = computeBaseCapacityWarehouse(hullStats)
|
|
193
|
+
} else if (itemId === ITEM_EXTRACTOR_T1_PACKED) {
|
|
194
|
+
baseCapacity = computeBaseCapacityShip(hullStats)
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
let out = entityDisplayName(itemId)
|
|
@@ -39,6 +39,7 @@ import type {ServerContract} from '../contracts'
|
|
|
39
39
|
import {
|
|
40
40
|
ITEM_CONTAINER_T1_PACKED,
|
|
41
41
|
ITEM_CONTAINER_T2_PACKED,
|
|
42
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
42
43
|
ITEM_SHIP_T1_PACKED,
|
|
43
44
|
ITEM_WAREHOUSE_T1_PACKED,
|
|
44
45
|
} from '../data/item-ids'
|
|
@@ -270,6 +271,8 @@ function hullCapsForEntity(
|
|
|
270
271
|
return computeShipHullCapabilities(decoded)
|
|
271
272
|
case ITEM_WAREHOUSE_T1_PACKED:
|
|
272
273
|
return computeWarehouseHullCapabilities(decoded)
|
|
274
|
+
case ITEM_EXTRACTOR_T1_PACKED:
|
|
275
|
+
return computeShipHullCapabilities(decoded)
|
|
273
276
|
case ITEM_CONTAINER_T1_PACKED:
|
|
274
277
|
return computeContainerCapabilities(decoded)
|
|
275
278
|
case ITEM_CONTAINER_T2_PACKED:
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {ServerContract} from '../contracts'
|
|
2
|
+
import {TaskType} from '../types'
|
|
3
|
+
|
|
4
|
+
export type TaskCargoDirection = 'in' | 'out'
|
|
5
|
+
|
|
6
|
+
export interface TaskCargoChange {
|
|
7
|
+
direction: TaskCargoDirection
|
|
8
|
+
item_id: number
|
|
9
|
+
stats: bigint
|
|
10
|
+
modules: ServerContract.Types.module_entry[]
|
|
11
|
+
quantity: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function toChange(
|
|
15
|
+
item: ServerContract.Types.cargo_item,
|
|
16
|
+
direction: TaskCargoDirection
|
|
17
|
+
): TaskCargoChange {
|
|
18
|
+
return {
|
|
19
|
+
direction,
|
|
20
|
+
item_id: Number(item.item_id),
|
|
21
|
+
stats: BigInt(item.stats.toString()),
|
|
22
|
+
modules: item.modules ?? [],
|
|
23
|
+
quantity: Number(item.quantity),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function taskCargoChanges(task: ServerContract.Types.task): TaskCargoChange[] {
|
|
28
|
+
const items = task.cargo ?? []
|
|
29
|
+
if (items.length === 0) return []
|
|
30
|
+
switch (Number(task.type)) {
|
|
31
|
+
case TaskType.LOAD:
|
|
32
|
+
case TaskType.UNWRAP:
|
|
33
|
+
return items.map((i) => toChange(i, 'in'))
|
|
34
|
+
case TaskType.GATHER:
|
|
35
|
+
return task.entitytarget ? [] : items.map((i) => toChange(i, 'in'))
|
|
36
|
+
case TaskType.UNLOAD:
|
|
37
|
+
case TaskType.WRAP:
|
|
38
|
+
return items.map((i) => toChange(i, 'out'))
|
|
39
|
+
case TaskType.CRAFT:
|
|
40
|
+
return [
|
|
41
|
+
...items.slice(0, -1).map((i) => toChange(i, 'out')),
|
|
42
|
+
toChange(items[items.length - 1], 'in'),
|
|
43
|
+
]
|
|
44
|
+
default:
|
|
45
|
+
return []
|
|
46
|
+
}
|
|
47
|
+
}
|