@shipload/sdk 1.0.0-next.4 → 1.0.0-next.5
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 +190 -91
- package/lib/shipload.js +568 -37
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +561 -37
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +54 -1
- package/src/data/colors.ts +1 -0
- package/src/data/items.json +245 -0
- package/src/data/metadata.ts +44 -1
- package/src/derivation/resources.ts +27 -19
- package/src/entities/container.ts +15 -0
- package/src/entities/ship-deploy.ts +42 -6
- package/src/entities/ship.ts +17 -0
- package/src/entities/warehouse.ts +8 -0
- package/src/index-module.ts +23 -15
- package/src/managers/actions.ts +24 -1
- package/src/nft/description.ts +21 -2
- package/src/resolution/resolve-item.ts +9 -5
- package/src/scheduling/accessor.ts +4 -0
- package/src/scheduling/projection.ts +8 -0
- package/src/scheduling/schedule.ts +15 -1
- package/src/subscriptions/manager.ts +37 -1
- package/src/travel/travel.ts +58 -1
- package/src/types.ts +3 -0
package/src/data/metadata.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface EntityMetadata {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const itemMetadata: Record<number, ItemMetadata> = {
|
|
14
|
-
// === Resources
|
|
14
|
+
// === Resources / Ore ===
|
|
15
15
|
101: {name: 'Ore', description: 'Crude metallic ore.', color: '#C26D3F'},
|
|
16
16
|
102: {name: 'Ore', description: 'Refined metallic ore with improved purity.', color: '#C26D3F'},
|
|
17
17
|
103: {
|
|
@@ -19,6 +19,15 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
19
19
|
description: 'High-grade metallic ore with exceptional density.',
|
|
20
20
|
color: '#C26D3F',
|
|
21
21
|
},
|
|
22
|
+
104: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
23
|
+
105: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
24
|
+
106: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
25
|
+
107: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
26
|
+
108: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
27
|
+
109: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
28
|
+
110: {name: 'Ore', description: '', color: '#C26D3F'},
|
|
29
|
+
|
|
30
|
+
// === Resources / Crystal ===
|
|
22
31
|
201: {name: 'Crystal', description: 'Raw resonant crystal.', color: '#4ADBFF'},
|
|
23
32
|
202: {
|
|
24
33
|
name: 'Crystal',
|
|
@@ -30,6 +39,15 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
30
39
|
description: 'High-grade resonant crystal with exceptional purity.',
|
|
31
40
|
color: '#4ADBFF',
|
|
32
41
|
},
|
|
42
|
+
204: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
43
|
+
205: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
44
|
+
206: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
45
|
+
207: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
46
|
+
208: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
47
|
+
209: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
48
|
+
210: {name: 'Crystal', description: '', color: '#4ADBFF'},
|
|
49
|
+
|
|
50
|
+
// === Resources / Gas ===
|
|
33
51
|
301: {name: 'Gas', description: 'Raw volatile gas.', color: '#B8E4A0'},
|
|
34
52
|
302: {
|
|
35
53
|
name: 'Gas',
|
|
@@ -41,6 +59,15 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
41
59
|
description: 'High-grade volatile gas with exceptional energy density.',
|
|
42
60
|
color: '#B8E4A0',
|
|
43
61
|
},
|
|
62
|
+
304: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
63
|
+
305: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
64
|
+
306: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
65
|
+
307: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
66
|
+
308: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
67
|
+
309: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
68
|
+
310: {name: 'Gas', description: '', color: '#B8E4A0'},
|
|
69
|
+
|
|
70
|
+
// === Resources / Regolith ===
|
|
44
71
|
401: {name: 'Regolith', description: 'Crude regolith dust.', color: '#C4A57B'},
|
|
45
72
|
402: {
|
|
46
73
|
name: 'Regolith',
|
|
@@ -52,6 +79,15 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
52
79
|
description: 'High-grade regolith with exceptional uniformity.',
|
|
53
80
|
color: '#C4A57B',
|
|
54
81
|
},
|
|
82
|
+
404: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
83
|
+
405: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
84
|
+
406: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
85
|
+
407: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
86
|
+
408: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
87
|
+
409: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
88
|
+
410: {name: 'Regolith', description: '', color: '#C4A57B'},
|
|
89
|
+
|
|
90
|
+
// === Resources / Biomass ===
|
|
55
91
|
501: {name: 'Biomass', description: 'Crude organic biomass.', color: '#5A8B3E'},
|
|
56
92
|
502: {
|
|
57
93
|
name: 'Biomass',
|
|
@@ -63,6 +99,13 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
63
99
|
description: 'High-grade biomass with exceptional saturation.',
|
|
64
100
|
color: '#5A8B3E',
|
|
65
101
|
},
|
|
102
|
+
504: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
103
|
+
505: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
104
|
+
506: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
105
|
+
507: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
106
|
+
508: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
107
|
+
509: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
108
|
+
510: {name: 'Biomass', description: '', color: '#5A8B3E'},
|
|
66
109
|
|
|
67
110
|
// === Components (T1) ===
|
|
68
111
|
10001: {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import {getItem} from '../data/catalog'
|
|
2
2
|
|
|
3
3
|
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 =
|
|
4
|
+
export const DEPTH_THRESHOLD_T2 = 1500
|
|
5
|
+
export const DEPTH_THRESHOLD_T3 = 5000
|
|
6
|
+
export const DEPTH_THRESHOLD_T4 = 12000
|
|
7
|
+
export const DEPTH_THRESHOLD_T5 = 22000
|
|
8
|
+
export const DEPTH_THRESHOLD_T6 = 32000
|
|
9
|
+
export const DEPTH_THRESHOLD_T7 = 42000
|
|
10
|
+
export const DEPTH_THRESHOLD_T8 = 50000
|
|
11
|
+
export const DEPTH_THRESHOLD_T9 = 57000
|
|
12
|
+
export const DEPTH_THRESHOLD_T10 = 63000
|
|
8
13
|
|
|
9
14
|
export const LOCATION_MIN_DEPTH = 500
|
|
10
15
|
export const LOCATION_MAX_DEPTH = 65535
|
|
@@ -18,19 +23,22 @@ export const PLANET_SUBTYPE_ICY = 3
|
|
|
18
23
|
export const PLANET_SUBTYPE_OCEAN = 4
|
|
19
24
|
export const PLANET_SUBTYPE_INDUSTRIAL = 5
|
|
20
25
|
|
|
26
|
+
const DEPTH_THRESHOLD_TABLE = [
|
|
27
|
+
DEPTH_THRESHOLD_T1,
|
|
28
|
+
DEPTH_THRESHOLD_T2,
|
|
29
|
+
DEPTH_THRESHOLD_T3,
|
|
30
|
+
DEPTH_THRESHOLD_T4,
|
|
31
|
+
DEPTH_THRESHOLD_T5,
|
|
32
|
+
DEPTH_THRESHOLD_T6,
|
|
33
|
+
DEPTH_THRESHOLD_T7,
|
|
34
|
+
DEPTH_THRESHOLD_T8,
|
|
35
|
+
DEPTH_THRESHOLD_T9,
|
|
36
|
+
DEPTH_THRESHOLD_T10,
|
|
37
|
+
]
|
|
38
|
+
|
|
21
39
|
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
|
-
}
|
|
40
|
+
if (tier < 1 || tier > 10) return 65535
|
|
41
|
+
return DEPTH_THRESHOLD_TABLE[tier - 1]
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
export function getResourceTier(itemId: number): number {
|
|
@@ -46,9 +54,9 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
46
54
|
|
|
47
55
|
switch (tier) {
|
|
48
56
|
case 1:
|
|
49
|
-
if (stratum <
|
|
50
|
-
if (stratum <
|
|
51
|
-
if (stratum <
|
|
57
|
+
if (stratum < DEPTH_THRESHOLD_T2) return 100
|
|
58
|
+
if (stratum < DEPTH_THRESHOLD_T3) return 80
|
|
59
|
+
if (stratum < DEPTH_THRESHOLD_T4) return 50
|
|
52
60
|
return 30
|
|
53
61
|
case 2:
|
|
54
62
|
if (depthAbove < 3000) return 40
|
|
@@ -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
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
MODULE_HAULER,
|
|
9
9
|
MODULE_LOADER,
|
|
10
10
|
} from '../capabilities/modules'
|
|
11
|
+
import {getItem} from '../data/catalog'
|
|
11
12
|
|
|
12
13
|
export function computeShipHullCapabilities(stats: Record<string, number>): {
|
|
13
14
|
hullmass: number
|
|
@@ -52,7 +53,38 @@ export function computeGeneratorCapabilities(stats: Record<string, number>): {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
export
|
|
56
|
+
export interface GathererDepthParams {
|
|
57
|
+
readonly floor: number
|
|
58
|
+
readonly slope: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const GATHERER_DEPTH_TABLE: readonly GathererDepthParams[] = [
|
|
62
|
+
{floor: 500, slope: 5},
|
|
63
|
+
{floor: 2000, slope: 11},
|
|
64
|
+
{floor: 7000, slope: 16},
|
|
65
|
+
{floor: 15000, slope: 18},
|
|
66
|
+
{floor: 25000, slope: 19},
|
|
67
|
+
{floor: 35000, slope: 16},
|
|
68
|
+
{floor: 46000, slope: 12},
|
|
69
|
+
{floor: 53500, slope: 10},
|
|
70
|
+
{floor: 60000, slope: 5},
|
|
71
|
+
{floor: 63500, slope: 2},
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
export const GATHERER_DEPTH_MAX_TIER = 10
|
|
75
|
+
|
|
76
|
+
export function gathererDepthForTier(tol: number, tier: number): number {
|
|
77
|
+
if (tier < 1 || tier > GATHERER_DEPTH_MAX_TIER) {
|
|
78
|
+
throw new Error(`gatherer tier out of range: ${tier}`)
|
|
79
|
+
}
|
|
80
|
+
const p = GATHERER_DEPTH_TABLE[tier - 1]
|
|
81
|
+
return p.floor + tol * p.slope
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function computeGathererCapabilities(
|
|
85
|
+
stats: Record<string, number>,
|
|
86
|
+
tier: number
|
|
87
|
+
): {
|
|
56
88
|
yield: number
|
|
57
89
|
drain: number
|
|
58
90
|
depth: number
|
|
@@ -66,7 +98,7 @@ export function computeGathererCapabilities(stats: Record<string, number>): {
|
|
|
66
98
|
return {
|
|
67
99
|
yield: 200 + str,
|
|
68
100
|
drain: Math.max(250, 1250 - Math.floor((con * 25) / 20)),
|
|
69
|
-
depth:
|
|
101
|
+
depth: gathererDepthForTier(tol, tier),
|
|
70
102
|
speed: 100 + Math.floor((ref * 4) / 5),
|
|
71
103
|
}
|
|
72
104
|
}
|
|
@@ -197,16 +229,20 @@ export function computeShipCapabilities(
|
|
|
197
229
|
if (gathererModules.length > 0) {
|
|
198
230
|
let totalYield = 0
|
|
199
231
|
let totalDrain = 0
|
|
200
|
-
let
|
|
232
|
+
let maxDepth = 0
|
|
201
233
|
let totalSpeed = 0
|
|
202
234
|
for (const m of gathererModules) {
|
|
203
|
-
const
|
|
235
|
+
const tier = getItem(m.itemId).tier
|
|
236
|
+
const caps = computeGathererCapabilities(
|
|
237
|
+
decodeCraftedItemStats(m.itemId, m.stats),
|
|
238
|
+
tier
|
|
239
|
+
)
|
|
204
240
|
totalYield += caps.yield
|
|
205
241
|
totalDrain += caps.drain
|
|
206
|
-
|
|
242
|
+
if (caps.depth > maxDepth) maxDepth = caps.depth
|
|
207
243
|
totalSpeed += caps.speed
|
|
208
244
|
}
|
|
209
|
-
ship.gatherer = {yield: totalYield, drain: totalDrain, depth:
|
|
245
|
+
ship.gatherer = {yield: totalYield, drain: totalDrain, depth: maxDepth, speed: totalSpeed}
|
|
210
246
|
}
|
|
211
247
|
|
|
212
248
|
const haulerModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_HAULER)
|
package/src/entities/ship.ts
CHANGED
|
@@ -2,7 +2,9 @@ import {type UInt16, type UInt16Type, UInt32, UInt64, type UInt64Type} from '@wh
|
|
|
2
2
|
import {ServerContract} from '../contracts'
|
|
3
3
|
import {Coordinates, type CoordinatesType} from '../types'
|
|
4
4
|
import {
|
|
5
|
+
type FloatPosition,
|
|
5
6
|
getDestinationLocation,
|
|
7
|
+
getInterpolatedPosition,
|
|
6
8
|
getPositionAt,
|
|
7
9
|
getFlightOrigin as travelGetFlightOrigin,
|
|
8
10
|
} from '../travel/travel'
|
|
@@ -55,6 +57,14 @@ export class Ship extends ServerContract.Types.entity_info {
|
|
|
55
57
|
return this.entity_name
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
get entityClass(): 'mobile' {
|
|
61
|
+
return 'mobile'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get canUndeploy(): boolean {
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
58
68
|
get inv(): InventoryAccessor {
|
|
59
69
|
this._inv ??= new InventoryAccessor(this)
|
|
60
70
|
return this._inv
|
|
@@ -87,12 +97,19 @@ export class Ship extends ServerContract.Types.entity_info {
|
|
|
87
97
|
return dest ? Coordinates.from(dest) : undefined
|
|
88
98
|
}
|
|
89
99
|
|
|
100
|
+
/** Chain-tile coordinates at `now`. For smooth visual position use interpolatedPositionAt. */
|
|
90
101
|
positionAt(now: Date): Coordinates {
|
|
91
102
|
const taskIndex = this.sched.currentTaskIndex(now)
|
|
92
103
|
const progress = this.sched.currentTaskProgress(now)
|
|
93
104
|
return Coordinates.from(getPositionAt(this, taskIndex, progress))
|
|
94
105
|
}
|
|
95
106
|
|
|
107
|
+
interpolatedPositionAt(now: Date): FloatPosition {
|
|
108
|
+
const taskIndex = this.sched.currentTaskIndex(now)
|
|
109
|
+
const progress = this.sched.currentTaskProgressFloat(now)
|
|
110
|
+
return getInterpolatedPosition(this, taskIndex, progress)
|
|
111
|
+
}
|
|
112
|
+
|
|
96
113
|
isInFlight(now: Date): boolean {
|
|
97
114
|
return schedule.isInFlight(this, now)
|
|
98
115
|
}
|
|
@@ -31,6 +31,14 @@ export class Warehouse extends ServerContract.Types.entity_info {
|
|
|
31
31
|
return this.entity_name
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
get entityClass(): 'building' {
|
|
35
|
+
return 'building'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get canDemolish(): boolean {
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
get inv(): InventoryAccessor {
|
|
35
43
|
this._inv ??= new InventoryAccessor(this)
|
|
36
44
|
return this._inv
|
package/src/index-module.ts
CHANGED
|
@@ -117,30 +117,35 @@ export {
|
|
|
117
117
|
distanceBetweenCoordinates,
|
|
118
118
|
distanceBetweenPoints,
|
|
119
119
|
findNearbyPlanets,
|
|
120
|
-
lerp,
|
|
121
|
-
rotation,
|
|
122
|
-
calc_ship_mass,
|
|
123
120
|
calc_acceleration,
|
|
121
|
+
calc_energyusage,
|
|
124
122
|
calc_flighttime,
|
|
125
|
-
calc_ship_flighttime,
|
|
126
|
-
calc_ship_acceleration,
|
|
127
|
-
calc_rechargetime,
|
|
128
|
-
calc_ship_rechargetime,
|
|
129
|
-
calc_loader_flighttime,
|
|
130
123
|
calc_loader_acceleration,
|
|
131
|
-
|
|
124
|
+
calc_loader_flighttime,
|
|
132
125
|
calc_orbital_altitude,
|
|
126
|
+
calc_rechargetime,
|
|
127
|
+
calc_ship_acceleration,
|
|
128
|
+
calc_ship_flighttime,
|
|
129
|
+
calc_ship_mass,
|
|
130
|
+
calc_ship_rechargetime,
|
|
133
131
|
calc_transfer_duration,
|
|
134
|
-
|
|
132
|
+
calculateFlightTime,
|
|
135
133
|
calculateLoadTimeBreakdown,
|
|
136
134
|
calculateRefuelingTime,
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
calculateTransferTime,
|
|
136
|
+
easeFlightProgress,
|
|
139
137
|
estimateDealTravelTime,
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
estimateTravelTime,
|
|
139
|
+
flightSpeedFactor,
|
|
140
|
+
type FloatPosition,
|
|
142
141
|
getDestinationLocation,
|
|
142
|
+
getFlightOrigin,
|
|
143
|
+
getInterpolatedPosition,
|
|
143
144
|
getPositionAt,
|
|
145
|
+
hasEnergyForDistance,
|
|
146
|
+
interpolateFlightPosition,
|
|
147
|
+
lerp,
|
|
148
|
+
rotation,
|
|
144
149
|
} from './travel/travel'
|
|
145
150
|
export type {
|
|
146
151
|
LoadTimeBreakdown,
|
|
@@ -246,8 +251,11 @@ export {
|
|
|
246
251
|
computeWarehouseHullCapabilities,
|
|
247
252
|
computeStorageCapabilities,
|
|
248
253
|
computeShipCapabilities,
|
|
254
|
+
GATHERER_DEPTH_TABLE,
|
|
255
|
+
GATHERER_DEPTH_MAX_TIER,
|
|
256
|
+
gathererDepthForTier,
|
|
249
257
|
} from './entities/ship-deploy'
|
|
250
|
-
export type {ShipCapabilities} from './entities/ship-deploy'
|
|
258
|
+
export type {ShipCapabilities, GathererDepthParams} from './entities/ship-deploy'
|
|
251
259
|
|
|
252
260
|
export {resolveItem} from './resolution/resolve-item'
|
|
253
261
|
export type {
|
package/src/managers/actions.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {type CoordinatesType, EntityType, type EntityTypeName} from '../types'
|
|
|
15
15
|
import {ServerContract} from '../contracts'
|
|
16
16
|
|
|
17
17
|
export type EntityRefInput = {
|
|
18
|
-
entityType:
|
|
18
|
+
entityType: NameType
|
|
19
19
|
entityId: UInt64Type
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -244,6 +244,29 @@ export class ActionsManager extends BaseManager {
|
|
|
244
244
|
})
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
undeploy(host: EntityRefInput, target: EntityRefInput): Action {
|
|
248
|
+
return this.server.action('undeploy', {
|
|
249
|
+
host_type: Name.from(host.entityType),
|
|
250
|
+
host_id: UInt64.from(host.entityId),
|
|
251
|
+
target_type: Name.from(target.entityType),
|
|
252
|
+
target_id: UInt64.from(target.entityId),
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
wrapEntity(entity: EntityRefInput): Action {
|
|
257
|
+
return this.server.action('wrapentity', {
|
|
258
|
+
entity_type: Name.from(entity.entityType),
|
|
259
|
+
entity_id: UInt64.from(entity.entityId),
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
demolish(entity: EntityRefInput): Action {
|
|
264
|
+
return this.server.action('demolish', {
|
|
265
|
+
entity_type: Name.from(entity.entityType),
|
|
266
|
+
entity_id: UInt64.from(entity.entityId),
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
247
270
|
joinGame(account: NameType, companyName: string): Action[] {
|
|
248
271
|
return [this.foundCompany(account, companyName), this.join(account)]
|
|
249
272
|
}
|
package/src/nft/description.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
MODULE_ENGINE,
|
|
5
5
|
MODULE_GATHERER,
|
|
6
6
|
MODULE_GENERATOR,
|
|
7
|
+
MODULE_HAULER,
|
|
7
8
|
MODULE_LOADER,
|
|
8
9
|
MODULE_STORAGE,
|
|
9
10
|
MODULE_WARP,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
ITEM_ENGINE_T1,
|
|
16
17
|
ITEM_GATHERER_T1,
|
|
17
18
|
ITEM_GENERATOR_T1,
|
|
19
|
+
ITEM_HAULER_T1,
|
|
18
20
|
ITEM_LOADER_T1,
|
|
19
21
|
ITEM_SHIP_T1_PACKED,
|
|
20
22
|
ITEM_STORAGE_T1,
|
|
@@ -22,6 +24,8 @@ import {
|
|
|
22
24
|
ITEM_WARP_T1,
|
|
23
25
|
} from '../data/item-ids'
|
|
24
26
|
import {decodeStat} from '../derivation/crafting'
|
|
27
|
+
import {gathererDepthForTier} from '../entities/ship-deploy'
|
|
28
|
+
import {getItem} from '../data/catalog'
|
|
25
29
|
|
|
26
30
|
function idiv(a: number, b: number): number {
|
|
27
31
|
return Math.floor(a / b)
|
|
@@ -49,12 +53,16 @@ export const computeGeneratorRech = (fin: number): number => 1 + idiv(fin * 3, 1
|
|
|
49
53
|
export const computeGathererYield = (str: number): number => 200 + str
|
|
50
54
|
export const computeGathererDrain = (con: number): number =>
|
|
51
55
|
Math.max(250, 1250 - idiv(con * 25, 20))
|
|
52
|
-
export const computeGathererDepth = (tol: number): number =>
|
|
56
|
+
export const computeGathererDepth = (tol: number, tier: number): number =>
|
|
57
|
+
gathererDepthForTier(tol, tier)
|
|
53
58
|
export const computeGathererSpeed = (ref: number): number => 100 + idiv(ref * 4, 5)
|
|
54
59
|
export const computeLoaderMass = (ins: number): number => Math.max(200, 2000 - ins * 2)
|
|
55
60
|
export const computeLoaderThrust = (pla: number): number => 1 + idiv(pla, 500)
|
|
56
61
|
export const computeCrafterSpeed = (rea: number): number => 100 + idiv(rea * 4, 5)
|
|
57
62
|
export const computeCrafterDrain = (fin: number): number => Math.max(5, 30 - idiv(fin, 33))
|
|
63
|
+
export const computeHaulerCapacity = (fin: number): number => Math.max(1, 1 + idiv(fin, 400))
|
|
64
|
+
export const computeHaulerEfficiency = (con: number): number => 2000 + con * 6
|
|
65
|
+
export const computeHaulerDrain = (com: number): number => Math.max(3, 15 - idiv(com, 80))
|
|
58
66
|
export const computeWarpRange = (stat: number): number => 100 + stat * 3
|
|
59
67
|
|
|
60
68
|
export function entityDisplayName(itemId: number): string {
|
|
@@ -86,6 +94,8 @@ export function moduleDisplayName(itemId: number): string {
|
|
|
86
94
|
return 'Crafter'
|
|
87
95
|
case ITEM_STORAGE_T1:
|
|
88
96
|
return 'Storage'
|
|
97
|
+
case ITEM_HAULER_T1:
|
|
98
|
+
return 'Hauler'
|
|
89
99
|
case ITEM_WARP_T1:
|
|
90
100
|
return 'Warp'
|
|
91
101
|
default:
|
|
@@ -121,8 +131,10 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
121
131
|
const tol = decodeStat(stats, 1)
|
|
122
132
|
const con = decodeStat(stats, 3)
|
|
123
133
|
const ref = decodeStat(stats, 4)
|
|
134
|
+
const tier = getItem(itemId).tier
|
|
124
135
|
out += ` Yield ${computeGathererYield(str)} Depth ${computeGathererDepth(
|
|
125
|
-
tol
|
|
136
|
+
tol,
|
|
137
|
+
tier
|
|
126
138
|
)} Speed ${computeGathererSpeed(ref)} Drain ${computeGathererDrain(con)}`
|
|
127
139
|
break
|
|
128
140
|
}
|
|
@@ -147,6 +159,13 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
147
159
|
out += ` +${pct}% capacity`
|
|
148
160
|
break
|
|
149
161
|
}
|
|
162
|
+
case MODULE_HAULER: {
|
|
163
|
+
const fin = decodeStat(stats, 0)
|
|
164
|
+
const con = decodeStat(stats, 1)
|
|
165
|
+
const com = decodeStat(stats, 2)
|
|
166
|
+
out += ` Capacity ${computeHaulerCapacity(fin)} Efficiency ${computeHaulerEfficiency(con)} Drain ${computeHaulerDrain(com)}`
|
|
167
|
+
break
|
|
168
|
+
}
|
|
150
169
|
case MODULE_WARP: {
|
|
151
170
|
const stat = decodeStat(stats, 0)
|
|
152
171
|
out += ` Range ${computeWarpRange(stat)}`
|
|
@@ -155,7 +155,8 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
155
155
|
|
|
156
156
|
function computeCapabilityGroup(
|
|
157
157
|
moduleType: number,
|
|
158
|
-
stats: Record<string, number
|
|
158
|
+
stats: Record<string, number>,
|
|
159
|
+
tier: number
|
|
159
160
|
): ResolvedAttributeGroup | undefined {
|
|
160
161
|
switch (moduleType) {
|
|
161
162
|
case MODULE_ENGINE: {
|
|
@@ -179,7 +180,7 @@ function computeCapabilityGroup(
|
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
case MODULE_GATHERER: {
|
|
182
|
-
const caps = computeGathererCapabilities(stats)
|
|
183
|
+
const caps = computeGathererCapabilities(stats, tier)
|
|
183
184
|
return {
|
|
184
185
|
capability: 'Gatherer',
|
|
185
186
|
attributes: [
|
|
@@ -242,7 +243,7 @@ function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
242
243
|
if (stats !== undefined) {
|
|
243
244
|
const decoded = decodeCraftedItemStats(id, toBigStats(stats))
|
|
244
245
|
const modType = getModuleCapabilityType(id)
|
|
245
|
-
const group = computeCapabilityGroup(modType, decoded)
|
|
246
|
+
const group = computeCapabilityGroup(modType, decoded, item.tier)
|
|
246
247
|
if (group) attributes = [group]
|
|
247
248
|
}
|
|
248
249
|
return {
|
|
@@ -311,13 +312,16 @@ function resolveEntity(
|
|
|
311
312
|
const modStats = BigInt(mod.installed.stats.toString())
|
|
312
313
|
const decodedStats = decodeCraftedItemStats(modItemId, modStats)
|
|
313
314
|
const modType = getModuleCapabilityType(modItemId)
|
|
314
|
-
const group = computeCapabilityGroup(modType, decodedStats)
|
|
315
315
|
let modName = 'Module'
|
|
316
|
+
let modTier = 1
|
|
316
317
|
try {
|
|
317
|
-
|
|
318
|
+
const modItem = getItem(modItemId)
|
|
319
|
+
modName = modItem.name
|
|
320
|
+
modTier = modItem.tier
|
|
318
321
|
} catch {
|
|
319
322
|
modName = itemMetadata[modItemId]?.name ?? 'Module'
|
|
320
323
|
}
|
|
324
|
+
const group = computeCapabilityGroup(modType, decodedStats, modTier)
|
|
321
325
|
return {
|
|
322
326
|
name: modName,
|
|
323
327
|
installed: true,
|
|
@@ -72,6 +72,10 @@ export class ScheduleAccessor {
|
|
|
72
72
|
return schedule.currentTaskProgress(this.entity, now)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
currentTaskProgressFloat(now: Date): number {
|
|
76
|
+
return schedule.currentTaskProgressFloat(this.entity, now)
|
|
77
|
+
}
|
|
78
|
+
|
|
75
79
|
progress(now: Date): number {
|
|
76
80
|
return schedule.scheduleProgress(this.entity, now)
|
|
77
81
|
}
|
|
@@ -267,6 +267,10 @@ function applyTask(projected: ProjectedEntity, task: ServerContract.Types.task):
|
|
|
267
267
|
case TaskType.DEPLOY:
|
|
268
268
|
applyDeployTask(projected, task)
|
|
269
269
|
break
|
|
270
|
+
case TaskType.UNDEPLOY:
|
|
271
|
+
case TaskType.WRAP_ENTITY:
|
|
272
|
+
case TaskType.DEMOLISH:
|
|
273
|
+
break
|
|
270
274
|
}
|
|
271
275
|
}
|
|
272
276
|
|
|
@@ -448,6 +452,10 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
|
|
|
448
452
|
case TaskType.DEPLOY:
|
|
449
453
|
if (taskComplete) applyDeployTask(projected, task)
|
|
450
454
|
break
|
|
455
|
+
case TaskType.UNDEPLOY:
|
|
456
|
+
case TaskType.WRAP_ENTITY:
|
|
457
|
+
case TaskType.DEMOLISH:
|
|
458
|
+
break
|
|
451
459
|
}
|
|
452
460
|
}
|
|
453
461
|
|
|
@@ -77,7 +77,7 @@ export function currentTaskIndex(entity: ScheduleData, now: Date): number {
|
|
|
77
77
|
timeAccum += taskDuration
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
return
|
|
80
|
+
return -1
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export function currentTask(entity: ScheduleData, now: Date): Task | undefined {
|
|
@@ -147,6 +147,20 @@ export function currentTaskProgress(entity: ScheduleData, now: Date): number {
|
|
|
147
147
|
return Math.min(1, elapsed / duration)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
export function currentTaskProgressFloat(entity: ScheduleData, now: Date): number {
|
|
151
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) return 0
|
|
152
|
+
const index = currentTaskIndex(entity, now)
|
|
153
|
+
if (index < 0) return 0
|
|
154
|
+
const task = entity.schedule.tasks[index]
|
|
155
|
+
const durationMs = task.duration.toNumber() * 1000
|
|
156
|
+
if (durationMs === 0) return 1
|
|
157
|
+
const startedMs = entity.schedule.started.toDate().getTime()
|
|
158
|
+
const taskStartMs = startedMs + getTaskStartTime(entity, index) * 1000
|
|
159
|
+
const elapsedMs = now.getTime() - taskStartMs
|
|
160
|
+
if (elapsedMs <= 0) return 0
|
|
161
|
+
return Math.min(1, elapsedMs / durationMs)
|
|
162
|
+
}
|
|
163
|
+
|
|
150
164
|
export function scheduleProgress(entity: ScheduleData, now: Date): number {
|
|
151
165
|
const duration = scheduleDuration(entity)
|
|
152
166
|
if (duration === 0) return hasSchedule(entity) ? 1 : 0
|
|
@@ -34,6 +34,12 @@ export interface BoundsSubscriptionHandle {
|
|
|
34
34
|
current: Map<number, EntityInstance>
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export interface OwnerSubscriptionHandle {
|
|
38
|
+
readonly subId: string
|
|
39
|
+
unsubscribe(): void
|
|
40
|
+
current: Map<number, EntityInstance>
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
export interface EntitySubscriptionHandle {
|
|
38
44
|
readonly subId: string
|
|
39
45
|
readonly entityType: SubscriptionEntityType
|
|
@@ -62,7 +68,7 @@ export class SubscriptionsManager {
|
|
|
62
68
|
onSnapshot?: (entities: EntityInstance[]) => void
|
|
63
69
|
onUpdate?: (entity: EntityInstance) => void
|
|
64
70
|
onBoundsDelta?: (entered: EntityInstance[], exited: number[]) => void
|
|
65
|
-
handle: BoundsSubscriptionHandle
|
|
71
|
+
handle: BoundsSubscriptionHandle | OwnerSubscriptionHandle
|
|
66
72
|
}
|
|
67
73
|
>()
|
|
68
74
|
private subCounter = 0
|
|
@@ -162,6 +168,36 @@ export class SubscriptionsManager {
|
|
|
162
168
|
return handle
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
subscribeOwner(
|
|
172
|
+
owner: string,
|
|
173
|
+
handlers: {
|
|
174
|
+
onSnapshot?: (entities: EntityInstance[]) => void
|
|
175
|
+
onUpdate?: (entity: EntityInstance) => void
|
|
176
|
+
} = {}
|
|
177
|
+
): OwnerSubscriptionHandle {
|
|
178
|
+
const subId = this.generateSubID('own')
|
|
179
|
+
const msg: SubscribeMessage = {
|
|
180
|
+
type: 'subscribe',
|
|
181
|
+
sub_id: subId,
|
|
182
|
+
owner,
|
|
183
|
+
}
|
|
184
|
+
const handle: OwnerSubscriptionHandle = {
|
|
185
|
+
subId,
|
|
186
|
+
unsubscribe: () => this.unsubscribeBounds(subId),
|
|
187
|
+
current: new Map(),
|
|
188
|
+
}
|
|
189
|
+
this.boundsSubs.set(subId, {
|
|
190
|
+
bounds: undefined,
|
|
191
|
+
owner,
|
|
192
|
+
prioritizeOwner: undefined,
|
|
193
|
+
onSnapshot: handlers.onSnapshot,
|
|
194
|
+
onUpdate: handlers.onUpdate,
|
|
195
|
+
handle,
|
|
196
|
+
})
|
|
197
|
+
this.sendMessage(msg)
|
|
198
|
+
return handle
|
|
199
|
+
}
|
|
200
|
+
|
|
165
201
|
private unsubscribeBounds(subId: string) {
|
|
166
202
|
this.boundsSubs.delete(subId)
|
|
167
203
|
this.sendMessage({type: 'unsubscribe', sub_id: subId})
|