@shipload/sdk 1.0.0-next.1 → 1.0.0-next.11
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 +618 -353
- package/lib/shipload.js +2250 -1059
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2193 -1044
- package/lib/shipload.m.js.map +1 -1
- package/package.json +2 -2
- package/src/capabilities/modules.ts +3 -0
- package/src/capabilities/storage.ts +1 -1
- package/src/contracts/platform.ts +13 -1
- package/src/contracts/server.ts +227 -282
- package/src/data/capabilities.ts +5 -330
- package/src/data/capability-formulas.ts +70 -0
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +2 -16
- package/src/data/entities.json +46 -10
- package/src/data/item-ids.ts +4 -1
- package/src/data/items.json +264 -0
- package/src/data/metadata.ts +63 -1
- package/src/data/recipes-runtime.ts +1 -0
- package/src/data/recipes.json +139 -11
- package/src/derivation/capability-mappings.ts +122 -0
- package/src/derivation/index.ts +1 -0
- package/src/derivation/resources.ts +116 -37
- package/src/derivation/stats.ts +1 -2
- package/src/entities/container.ts +25 -10
- package/src/entities/extractor.ts +144 -0
- package/src/entities/factory.ts +135 -0
- package/src/entities/gamestate.ts +0 -9
- package/src/entities/makers.ts +130 -20
- package/src/entities/nexus.ts +29 -0
- package/src/entities/ship-deploy.ts +114 -56
- package/src/entities/ship.ts +17 -0
- package/src/entities/slot-multiplier.ts +21 -0
- package/src/entities/warehouse.ts +20 -3
- package/src/errors.ts +10 -13
- package/src/index-module.ts +81 -26
- package/src/managers/actions.ts +53 -80
- package/src/managers/entities.ts +65 -17
- package/src/managers/locations.ts +2 -20
- package/src/nft/atomicdata.ts +128 -0
- package/src/nft/description.ts +41 -7
- package/src/nft/index.ts +1 -0
- package/src/resolution/resolve-item.ts +17 -9
- package/src/scheduling/accessor.ts +4 -0
- package/src/scheduling/projection.ts +10 -2
- package/src/scheduling/schedule.ts +15 -1
- package/src/scheduling/task-cargo.ts +47 -0
- package/src/subscriptions/connection.ts +50 -2
- package/src/subscriptions/manager.ts +84 -4
- package/src/subscriptions/mappers.ts +5 -1
- package/src/subscriptions/types.ts +2 -2
- package/src/travel/travel.ts +61 -2
- package/src/types/entity-traits.ts +103 -1
- package/src/types.ts +11 -1
- package/src/utils/cargo.ts +27 -0
- package/src/utils/system.ts +25 -24
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {SLOT_FORMULAS, type SlotConsumerKind} from '../data/capability-formulas'
|
|
2
|
+
import {getStatDefinitions, type StatDefinition} from './stats'
|
|
3
|
+
import {
|
|
4
|
+
getRecipe,
|
|
5
|
+
type Recipe,
|
|
6
|
+
type RecipeInput,
|
|
7
|
+
type RecipeInputCategory,
|
|
8
|
+
} from '../data/recipes-runtime'
|
|
9
|
+
import {
|
|
10
|
+
ITEM_ENGINE_T1,
|
|
11
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
12
|
+
ITEM_GENERATOR_T1,
|
|
13
|
+
ITEM_GATHERER_T1,
|
|
14
|
+
ITEM_LOADER_T1,
|
|
15
|
+
ITEM_CRAFTER_T1,
|
|
16
|
+
ITEM_STORAGE_T1,
|
|
17
|
+
ITEM_HAULER_T1,
|
|
18
|
+
ITEM_WARP_T1,
|
|
19
|
+
ITEM_SHIP_T1_PACKED,
|
|
20
|
+
ITEM_CONTAINER_T1_PACKED,
|
|
21
|
+
ITEM_WAREHOUSE_T1_PACKED,
|
|
22
|
+
ITEM_CONTAINER_T2_PACKED,
|
|
23
|
+
} from '../data/item-ids'
|
|
24
|
+
import type {StatMapping} from '../data/capabilities'
|
|
25
|
+
|
|
26
|
+
export const KIND_TO_ITEM_ID: Record<SlotConsumerKind, number> = {
|
|
27
|
+
engine: ITEM_ENGINE_T1,
|
|
28
|
+
generator: ITEM_GENERATOR_T1,
|
|
29
|
+
gatherer: ITEM_GATHERER_T1,
|
|
30
|
+
loader: ITEM_LOADER_T1,
|
|
31
|
+
crafter: ITEM_CRAFTER_T1,
|
|
32
|
+
storage: ITEM_STORAGE_T1,
|
|
33
|
+
hauler: ITEM_HAULER_T1,
|
|
34
|
+
warp: ITEM_WARP_T1,
|
|
35
|
+
'ship-t1': ITEM_SHIP_T1_PACKED,
|
|
36
|
+
'container-t1': ITEM_CONTAINER_T1_PACKED,
|
|
37
|
+
'warehouse-t1': ITEM_WAREHOUSE_T1_PACKED,
|
|
38
|
+
'extractor-t1': ITEM_EXTRACTOR_T1_PACKED,
|
|
39
|
+
'container-t2': ITEM_CONTAINER_T2_PACKED,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isCategoryInput(input: RecipeInput): input is RecipeInputCategory {
|
|
43
|
+
return 'category' in input
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Walk a recipe's slot source down to the raw category stat that ultimately
|
|
48
|
+
* lands in that slot. Returns the StatDefinition or undefined if the trace
|
|
49
|
+
* dead-ends (unknown sub-component, missing slot, etc.).
|
|
50
|
+
*
|
|
51
|
+
* Multi-source sub-slots collapse to `sources[0]`; top-level multi-source slots
|
|
52
|
+
* are expanded by the caller (`deriveStatMappings`).
|
|
53
|
+
*/
|
|
54
|
+
function traceToRawCategoryStat(
|
|
55
|
+
recipe: Recipe,
|
|
56
|
+
source: {inputIndex: number; statIndex: number},
|
|
57
|
+
visited: Set<number> = new Set()
|
|
58
|
+
): StatDefinition | undefined {
|
|
59
|
+
const input = recipe.inputs[source.inputIndex]
|
|
60
|
+
if (!input) return undefined
|
|
61
|
+
if (isCategoryInput(input)) {
|
|
62
|
+
const defs = getStatDefinitions(input.category)
|
|
63
|
+
return defs[source.statIndex]
|
|
64
|
+
}
|
|
65
|
+
if (visited.has(input.itemId)) return undefined
|
|
66
|
+
const subRecipe = getRecipe(input.itemId)
|
|
67
|
+
if (!subRecipe) return undefined
|
|
68
|
+
const subSlot = subRecipe.statSlots[source.statIndex]
|
|
69
|
+
if (!subSlot) return undefined
|
|
70
|
+
const subSource = subSlot.sources[0]
|
|
71
|
+
if (!subSource) return undefined
|
|
72
|
+
const nextVisited = new Set(visited)
|
|
73
|
+
nextVisited.add(input.itemId)
|
|
74
|
+
return traceToRawCategoryStat(subRecipe, subSource, nextVisited)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let cached: StatMapping[] | undefined
|
|
78
|
+
|
|
79
|
+
export function deriveStatMappings(): StatMapping[] {
|
|
80
|
+
if (cached) return cached
|
|
81
|
+
const out: StatMapping[] = []
|
|
82
|
+
const seen = new Set<string>()
|
|
83
|
+
for (const [kind, slots] of Object.entries(SLOT_FORMULAS) as [
|
|
84
|
+
SlotConsumerKind,
|
|
85
|
+
Record<number, {capability: string; attribute: string}>,
|
|
86
|
+
][]) {
|
|
87
|
+
const itemId = KIND_TO_ITEM_ID[kind]
|
|
88
|
+
const recipe = getRecipe(itemId)
|
|
89
|
+
if (!recipe) continue
|
|
90
|
+
for (const [slotIdxStr, consumer] of Object.entries(slots)) {
|
|
91
|
+
const slotIdx = Number(slotIdxStr)
|
|
92
|
+
const slot = recipe.statSlots[slotIdx]
|
|
93
|
+
if (!slot) continue
|
|
94
|
+
for (const source of slot.sources) {
|
|
95
|
+
const stat = traceToRawCategoryStat(recipe, source)
|
|
96
|
+
if (!stat) continue
|
|
97
|
+
const key = `${stat.label}|${consumer.capability}|${consumer.attribute}`
|
|
98
|
+
if (seen.has(key)) continue
|
|
99
|
+
seen.add(key)
|
|
100
|
+
out.push({
|
|
101
|
+
stat: stat.label,
|
|
102
|
+
capability: consumer.capability,
|
|
103
|
+
attribute: consumer.attribute,
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
cached = out
|
|
109
|
+
return out
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function getStatMappings(): StatMapping[] {
|
|
113
|
+
return deriveStatMappings()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function getStatMappingsForStat(stat: string): StatMapping[] {
|
|
117
|
+
return deriveStatMappings().filter((m) => m.stat === stat)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function getStatMappingsForCapability(capability: string): StatMapping[] {
|
|
121
|
+
return deriveStatMappings().filter((m) => m.capability === capability)
|
|
122
|
+
}
|
package/src/derivation/index.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {getItem} from '../data/catalog'
|
|
2
|
+
import {LocationType} from '../types'
|
|
2
3
|
|
|
3
4
|
export const DEPTH_THRESHOLD_T1 = 0
|
|
4
|
-
export const DEPTH_THRESHOLD_T2 =
|
|
5
|
-
export const DEPTH_THRESHOLD_T3 =
|
|
6
|
-
export const DEPTH_THRESHOLD_T4 =
|
|
7
|
-
export const DEPTH_THRESHOLD_T5 =
|
|
5
|
+
export const DEPTH_THRESHOLD_T2 = 1500
|
|
6
|
+
export const DEPTH_THRESHOLD_T3 = 5000
|
|
7
|
+
export const DEPTH_THRESHOLD_T4 = 12000
|
|
8
|
+
export const DEPTH_THRESHOLD_T5 = 22000
|
|
9
|
+
export const DEPTH_THRESHOLD_T6 = 32000
|
|
10
|
+
export const DEPTH_THRESHOLD_T7 = 42000
|
|
11
|
+
export const DEPTH_THRESHOLD_T8 = 50000
|
|
12
|
+
export const DEPTH_THRESHOLD_T9 = 57000
|
|
13
|
+
export const DEPTH_THRESHOLD_T10 = 63000
|
|
8
14
|
|
|
9
15
|
export const LOCATION_MIN_DEPTH = 500
|
|
10
16
|
export const LOCATION_MAX_DEPTH = 65535
|
|
@@ -18,19 +24,22 @@ export const PLANET_SUBTYPE_ICY = 3
|
|
|
18
24
|
export const PLANET_SUBTYPE_OCEAN = 4
|
|
19
25
|
export const PLANET_SUBTYPE_INDUSTRIAL = 5
|
|
20
26
|
|
|
27
|
+
const DEPTH_THRESHOLD_TABLE = [
|
|
28
|
+
DEPTH_THRESHOLD_T1,
|
|
29
|
+
DEPTH_THRESHOLD_T2,
|
|
30
|
+
DEPTH_THRESHOLD_T3,
|
|
31
|
+
DEPTH_THRESHOLD_T4,
|
|
32
|
+
DEPTH_THRESHOLD_T5,
|
|
33
|
+
DEPTH_THRESHOLD_T6,
|
|
34
|
+
DEPTH_THRESHOLD_T7,
|
|
35
|
+
DEPTH_THRESHOLD_T8,
|
|
36
|
+
DEPTH_THRESHOLD_T9,
|
|
37
|
+
DEPTH_THRESHOLD_T10,
|
|
38
|
+
]
|
|
39
|
+
|
|
21
40
|
export function getDepthThreshold(tier: number): number {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return DEPTH_THRESHOLD_T1
|
|
25
|
-
case 2:
|
|
26
|
-
return DEPTH_THRESHOLD_T2
|
|
27
|
-
case 3:
|
|
28
|
-
return DEPTH_THRESHOLD_T3
|
|
29
|
-
case 4:
|
|
30
|
-
return DEPTH_THRESHOLD_T4
|
|
31
|
-
default:
|
|
32
|
-
return DEPTH_THRESHOLD_T5
|
|
33
|
-
}
|
|
41
|
+
if (tier < 1 || tier > 10) return 65535
|
|
42
|
+
return DEPTH_THRESHOLD_TABLE[tier - 1]
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
export function getResourceTier(itemId: number): number {
|
|
@@ -46,9 +55,9 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
46
55
|
|
|
47
56
|
switch (tier) {
|
|
48
57
|
case 1:
|
|
49
|
-
if (stratum <
|
|
50
|
-
if (stratum <
|
|
51
|
-
if (stratum <
|
|
58
|
+
if (stratum < DEPTH_THRESHOLD_T2) return 100
|
|
59
|
+
if (stratum < DEPTH_THRESHOLD_T3) return 80
|
|
60
|
+
if (stratum < DEPTH_THRESHOLD_T4) return 50
|
|
52
61
|
return 30
|
|
53
62
|
case 2:
|
|
54
63
|
if (depthAbove < 3000) return 40
|
|
@@ -67,37 +76,107 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const ICY_RESOURCES = [101, 301, 302, 401, 403, 501, 502]
|
|
76
|
-
const OCEAN_RESOURCES = [201, 203, 301, 303, 501, 502, 503]
|
|
77
|
-
const INDUSTRIAL_RESOURCES = [101, 102, 103, 201, 203, 402, 403]
|
|
79
|
+
const RESOURCE_ORE = 0
|
|
80
|
+
const RESOURCE_GAS = 1
|
|
81
|
+
const RESOURCE_REGOLITH = 2
|
|
82
|
+
const RESOURCE_BIOMASS = 3
|
|
83
|
+
const RESOURCE_CRYSTAL = 4
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
interface LocationProfileEntry {
|
|
86
|
+
category: number
|
|
87
|
+
maxTier: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function categoryBaseId(category: number): number {
|
|
91
|
+
switch (category) {
|
|
92
|
+
case RESOURCE_ORE:
|
|
93
|
+
return 100
|
|
94
|
+
case RESOURCE_CRYSTAL:
|
|
95
|
+
return 200
|
|
96
|
+
case RESOURCE_GAS:
|
|
97
|
+
return 300
|
|
98
|
+
case RESOURCE_REGOLITH:
|
|
99
|
+
return 400
|
|
100
|
+
case RESOURCE_BIOMASS:
|
|
101
|
+
return 500
|
|
102
|
+
default:
|
|
103
|
+
return 0
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function resourceId(category: number, tier: number): number {
|
|
108
|
+
return categoryBaseId(category) + tier
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getLocationProfile(locationType: number, subtype: number): LocationProfileEntry[] {
|
|
112
|
+
if (locationType === LocationType.ASTEROID) {
|
|
113
|
+
return [
|
|
114
|
+
{category: RESOURCE_ORE, maxTier: 5},
|
|
115
|
+
{category: RESOURCE_CRYSTAL, maxTier: 5},
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
if (locationType === LocationType.NEBULA) {
|
|
119
|
+
return [
|
|
120
|
+
{category: RESOURCE_GAS, maxTier: 5},
|
|
121
|
+
{category: RESOURCE_REGOLITH, maxTier: 5},
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
if (locationType === LocationType.ICE_FIELD) {
|
|
125
|
+
return [
|
|
126
|
+
{category: RESOURCE_GAS, maxTier: 5},
|
|
127
|
+
{category: RESOURCE_BIOMASS, maxTier: 5},
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
if (locationType === LocationType.PLANET) {
|
|
83
131
|
switch (subtype) {
|
|
84
132
|
case PLANET_SUBTYPE_GAS_GIANT:
|
|
85
|
-
return
|
|
133
|
+
return [
|
|
134
|
+
{category: RESOURCE_GAS, maxTier: 10},
|
|
135
|
+
{category: RESOURCE_CRYSTAL, maxTier: 3},
|
|
136
|
+
]
|
|
86
137
|
case PLANET_SUBTYPE_ROCKY:
|
|
87
|
-
return
|
|
138
|
+
return [
|
|
139
|
+
{category: RESOURCE_REGOLITH, maxTier: 10},
|
|
140
|
+
{category: RESOURCE_ORE, maxTier: 3},
|
|
141
|
+
]
|
|
88
142
|
case PLANET_SUBTYPE_TERRESTRIAL:
|
|
89
|
-
return
|
|
143
|
+
return [
|
|
144
|
+
{category: RESOURCE_ORE, maxTier: 10},
|
|
145
|
+
{category: RESOURCE_BIOMASS, maxTier: 3},
|
|
146
|
+
]
|
|
90
147
|
case PLANET_SUBTYPE_ICY:
|
|
91
|
-
return
|
|
148
|
+
return [
|
|
149
|
+
{category: RESOURCE_CRYSTAL, maxTier: 10},
|
|
150
|
+
{category: RESOURCE_REGOLITH, maxTier: 3},
|
|
151
|
+
]
|
|
92
152
|
case PLANET_SUBTYPE_OCEAN:
|
|
93
|
-
return
|
|
153
|
+
return [
|
|
154
|
+
{category: RESOURCE_BIOMASS, maxTier: 10},
|
|
155
|
+
{category: RESOURCE_GAS, maxTier: 3},
|
|
156
|
+
]
|
|
94
157
|
case PLANET_SUBTYPE_INDUSTRIAL:
|
|
95
|
-
return
|
|
158
|
+
return [
|
|
159
|
+
{category: RESOURCE_ORE, maxTier: 3},
|
|
160
|
+
{category: RESOURCE_CRYSTAL, maxTier: 3},
|
|
161
|
+
{category: RESOURCE_REGOLITH, maxTier: 3},
|
|
162
|
+
{category: RESOURCE_BIOMASS, maxTier: 3},
|
|
163
|
+
]
|
|
96
164
|
}
|
|
97
165
|
}
|
|
98
166
|
return []
|
|
99
167
|
}
|
|
100
168
|
|
|
169
|
+
export function getLocationCandidates(locationType: number, subtype: number): number[] {
|
|
170
|
+
const profile = getLocationProfile(locationType, subtype)
|
|
171
|
+
const ids: number[] = []
|
|
172
|
+
for (const {category, maxTier} of profile) {
|
|
173
|
+
for (let tier = 1; tier <= maxTier; tier++) {
|
|
174
|
+
ids.push(resourceId(category, tier))
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return ids
|
|
178
|
+
}
|
|
179
|
+
|
|
101
180
|
export function getEligibleResources(
|
|
102
181
|
locationType: number,
|
|
103
182
|
subtype: number,
|
package/src/derivation/stats.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {UInt64, type UInt64Type} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
3
|
import type {CoordinatesType} from '../types'
|
|
4
|
+
import {type FloatPosition, getInterpolatedPosition} from '../travel/travel'
|
|
4
5
|
import {Location} from './location'
|
|
5
6
|
import {ScheduleAccessor} from '../scheduling/accessor'
|
|
6
7
|
import * as schedule from '../scheduling/schedule'
|
|
@@ -24,6 +25,14 @@ export class Container extends ServerContract.Types.entity_info {
|
|
|
24
25
|
return this.entity_name
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
get entityClass(): 'orbital' {
|
|
29
|
+
return 'orbital'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get canUndeploy(): boolean {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
get sched(): ScheduleAccessor {
|
|
28
37
|
this._sched ??= new ScheduleAccessor(this)
|
|
29
38
|
return this._sched
|
|
@@ -33,6 +42,12 @@ export class Container extends ServerContract.Types.entity_info {
|
|
|
33
42
|
return this.is_idle
|
|
34
43
|
}
|
|
35
44
|
|
|
45
|
+
interpolatedPositionAt(now: Date): FloatPosition {
|
|
46
|
+
const taskIndex = this.sched.currentTaskIndex(now)
|
|
47
|
+
const progress = this.sched.currentTaskProgressFloat(now)
|
|
48
|
+
return getInterpolatedPosition(this, taskIndex, progress)
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
isLoading(now: Date): boolean {
|
|
37
52
|
return schedule.isLoading(this, now)
|
|
38
53
|
}
|
|
@@ -75,12 +90,12 @@ export function computeContainerCapabilities(stats: Record<string, number>): {
|
|
|
75
90
|
hullmass: number
|
|
76
91
|
capacity: number
|
|
77
92
|
} {
|
|
78
|
-
const density = stats
|
|
79
|
-
const strength = stats
|
|
80
|
-
const hardness = stats
|
|
81
|
-
const saturation = stats
|
|
93
|
+
const density = stats.density
|
|
94
|
+
const strength = stats.strength
|
|
95
|
+
const hardness = stats.hardness
|
|
96
|
+
const saturation = stats.saturation
|
|
82
97
|
|
|
83
|
-
const hullmass =
|
|
98
|
+
const hullmass = 100000 - 75 * density
|
|
84
99
|
|
|
85
100
|
const statSum = strength + hardness + saturation
|
|
86
101
|
const exponent = statSum / 2997
|
|
@@ -93,12 +108,12 @@ export function computeContainerT2Capabilities(stats: Record<string, number>): {
|
|
|
93
108
|
hullmass: number
|
|
94
109
|
capacity: number
|
|
95
110
|
} {
|
|
96
|
-
const strength = stats
|
|
97
|
-
const density = stats
|
|
98
|
-
const hardness = stats
|
|
99
|
-
const saturation = stats
|
|
111
|
+
const strength = stats.strength
|
|
112
|
+
const density = stats.density
|
|
113
|
+
const hardness = stats.hardness
|
|
114
|
+
const saturation = stats.saturation
|
|
100
115
|
|
|
101
|
-
const hullmass =
|
|
116
|
+
const hullmass = 70000 - 50 * density
|
|
102
117
|
|
|
103
118
|
const statSum = strength + hardness + saturation
|
|
104
119
|
const exponent = statSum / 2500
|
|
@@ -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(): 'planetary' {
|
|
38
|
+
return 'planetary'
|
|
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
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
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_CRAFTER, MODULE_GENERATOR} from '../capabilities/modules'
|
|
11
|
+
import {computeCrafterCapabilities, computeGeneratorCapabilities} from './ship-deploy'
|
|
12
|
+
import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
|
|
13
|
+
import type {EntitySlot} from '../data/recipes-runtime'
|
|
14
|
+
|
|
15
|
+
export interface FactoryStateInput {
|
|
16
|
+
id: UInt64Type
|
|
17
|
+
owner: string
|
|
18
|
+
name: string
|
|
19
|
+
coordinates: CoordinatesType | {x: number; y: number; z?: number}
|
|
20
|
+
hullmass?: number
|
|
21
|
+
capacity?: number
|
|
22
|
+
energy?: number
|
|
23
|
+
modules?: PackedModuleInput[]
|
|
24
|
+
schedule?: ServerContract.Types.schedule
|
|
25
|
+
cargo?: ServerContract.Types.cargo_item[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Factory extends ServerContract.Types.entity_info {
|
|
29
|
+
private _sched?: ScheduleAccessor
|
|
30
|
+
private _inv?: InventoryAccessor
|
|
31
|
+
|
|
32
|
+
get name(): string {
|
|
33
|
+
return this.entity_name
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get entityClass(): 'planetary' {
|
|
37
|
+
return 'planetary'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get canDemolish(): boolean {
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get inv(): InventoryAccessor {
|
|
45
|
+
this._inv ??= new InventoryAccessor(this)
|
|
46
|
+
return this._inv
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get inventory(): EntityInventory[] {
|
|
50
|
+
return this.inv.items
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get sched(): ScheduleAccessor {
|
|
54
|
+
this._sched ??= new ScheduleAccessor(this)
|
|
55
|
+
return this._sched
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get isIdle(): boolean {
|
|
59
|
+
return this.is_idle
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get location(): Location {
|
|
63
|
+
return Location.from(this.coordinates)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get totalCargoMass(): UInt64 {
|
|
67
|
+
return this.inv.totalMass
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get maxCapacity(): UInt64 {
|
|
71
|
+
return UInt64.from(this.capacity)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get availableCapacity(): UInt64 {
|
|
75
|
+
const cargo = this.totalCargoMass
|
|
76
|
+
return cargo.gte(this.maxCapacity) ? UInt64.from(0) : this.maxCapacity.subtracting(cargo)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get isFull(): boolean {
|
|
80
|
+
return this.totalCargoMass.gte(this.maxCapacity)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get totalMass(): UInt64 {
|
|
84
|
+
const hull = this.hullmass ? UInt64.from(this.hullmass) : UInt64.from(0)
|
|
85
|
+
return hull.adding(this.totalCargoMass)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface FactoryCapabilities {
|
|
90
|
+
generator?: {capacity: number; recharge: number}
|
|
91
|
+
crafter?: {speed: number; drain: number}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function computeFactoryCapabilities(
|
|
95
|
+
modules: InstalledModule[],
|
|
96
|
+
layout: EntitySlot[]
|
|
97
|
+
): FactoryCapabilities {
|
|
98
|
+
const out: FactoryCapabilities = {}
|
|
99
|
+
|
|
100
|
+
const genModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_GENERATOR)
|
|
101
|
+
if (genModules.length > 0) {
|
|
102
|
+
let totalCapacity = 0
|
|
103
|
+
let totalRecharge = 0
|
|
104
|
+
for (const m of genModules) {
|
|
105
|
+
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
106
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
107
|
+
totalCapacity += applySlotMultiplier(caps.capacity, amp)
|
|
108
|
+
totalRecharge += applySlotMultiplier(caps.recharge, amp)
|
|
109
|
+
}
|
|
110
|
+
out.generator = {
|
|
111
|
+
capacity: clampUint16(totalCapacity),
|
|
112
|
+
recharge: clampUint16(totalRecharge),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const crafterModules = modules.filter(
|
|
117
|
+
(m) => getModuleCapabilityType(m.itemId) === MODULE_CRAFTER
|
|
118
|
+
)
|
|
119
|
+
if (crafterModules.length > 0) {
|
|
120
|
+
let totalSpeed = 0
|
|
121
|
+
let totalDrain = 0
|
|
122
|
+
for (const m of crafterModules) {
|
|
123
|
+
const caps = computeCrafterCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
124
|
+
const amp = getSlotAmp(layout, m.slotIndex)
|
|
125
|
+
totalSpeed += applySlotMultiplier(caps.speed, amp)
|
|
126
|
+
totalDrain += caps.drain
|
|
127
|
+
}
|
|
128
|
+
out.crafter = {
|
|
129
|
+
speed: clampUint16(totalSpeed),
|
|
130
|
+
drain: totalDrain,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return out
|
|
135
|
+
}
|