@shipload/sdk 1.0.0-next.0 → 1.0.0-next.10
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 +512 -320
- package/lib/shipload.js +1960 -1060
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +1920 -1056
- package/lib/shipload.m.js.map +1 -1
- package/package.json +8 -3
- 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 +33 -10
- package/src/data/item-ids.ts +3 -1
- package/src/data/items.json +258 -0
- package/src/data/metadata.ts +57 -1
- package/src/data/recipes-runtime.ts +1 -0
- package/src/data/recipes.json +82 -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/gamestate.ts +0 -9
- package/src/entities/makers.ts +71 -20
- 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/index-module.ts +67 -26
- package/src/managers/actions.ts +53 -80
- package/src/managers/entities.ts +31 -17
- package/src/managers/locations.ts +2 -20
- package/src/nft/atomicdata.ts +125 -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 +8 -0
- 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 +81 -2
- package/src/travel/travel.ts +61 -2
- package/src/types/entity-traits.ts +64 -1
- package/src/types.ts +11 -1
- package/src/utils/cargo.ts +27 -0
- package/src/utils/system.ts +25 -24
|
@@ -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(): 'mobile' {
|
|
29
|
+
return 'mobile'
|
|
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(): '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
|
+
}
|
|
@@ -58,13 +58,6 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
58
58
|
return this.enabled
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/**
|
|
62
|
-
* Get the total number of ships in the game
|
|
63
|
-
*/
|
|
64
|
-
get shipCount(): number {
|
|
65
|
-
return Number(this.ships)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
61
|
/**
|
|
69
62
|
* Get the current salt value (used for random number generation)
|
|
70
63
|
*/
|
|
@@ -137,14 +130,12 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
137
130
|
get summary(): {
|
|
138
131
|
enabled: boolean
|
|
139
132
|
epoch: string
|
|
140
|
-
ships: number
|
|
141
133
|
hasSeed: boolean
|
|
142
134
|
hasCommit: boolean
|
|
143
135
|
} {
|
|
144
136
|
return {
|
|
145
137
|
enabled: this.enabled,
|
|
146
138
|
epoch: this.epoch.toString(),
|
|
147
|
-
ships: this.shipCount,
|
|
148
139
|
hasSeed: !this.seed.equals(Checksum256.from('0'.repeat(64))),
|
|
149
140
|
hasCommit: !this.commit.equals(Checksum256.from('0'.repeat(64))),
|
|
150
141
|
}
|
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'),
|