@shipload/sdk 1.0.0-next.4 → 1.0.0-next.6
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 +197 -92
- package/lib/shipload.js +672 -64
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +664 -64
- 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/index.ts +1 -0
- package/src/derivation/resources.ts +116 -37
- 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 +24 -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 +4 -0
- package/src/utils/system.ts +21 -8
|
@@ -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})
|
package/src/travel/travel.ts
CHANGED
|
@@ -77,6 +77,59 @@ export function lerp(
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
export interface FloatPosition {
|
|
81
|
+
x: number
|
|
82
|
+
y: number
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function easeFlightProgress(t: number): number {
|
|
86
|
+
if (t <= 0) return 0
|
|
87
|
+
if (t >= 1) return 1
|
|
88
|
+
return t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function flightSpeedFactor(t: number): number {
|
|
92
|
+
if (t <= 0 || t >= 1) return 0
|
|
93
|
+
return t < 0.5 ? 4 * t : 4 * (1 - t)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function interpolateFlightPosition(
|
|
97
|
+
origin: {x: Int64Type | number; y: Int64Type | number},
|
|
98
|
+
destination: {x: Int64Type | number; y: Int64Type | number},
|
|
99
|
+
taskProgress: number,
|
|
100
|
+
options?: {easing?: 'physics' | 'linear'}
|
|
101
|
+
): FloatPosition {
|
|
102
|
+
const t = options?.easing === 'linear' ? taskProgress : easeFlightProgress(taskProgress)
|
|
103
|
+
return {
|
|
104
|
+
x: (1 - t) * Number(origin.x) + t * Number(destination.x),
|
|
105
|
+
y: (1 - t) * Number(origin.y) + t * Number(destination.y),
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function getInterpolatedPosition(
|
|
110
|
+
entity: HasScheduleAndLocation,
|
|
111
|
+
taskIndex: number,
|
|
112
|
+
taskProgress: number
|
|
113
|
+
): FloatPosition {
|
|
114
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) {
|
|
115
|
+
return {x: Number(entity.coordinates.x), y: Number(entity.coordinates.y)}
|
|
116
|
+
}
|
|
117
|
+
if (taskIndex < 0) {
|
|
118
|
+
const settled = getFlightOrigin(entity, entity.schedule.tasks.length)
|
|
119
|
+
return {x: Number(settled.x), y: Number(settled.y)}
|
|
120
|
+
}
|
|
121
|
+
const task = entity.schedule.tasks[taskIndex]
|
|
122
|
+
if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
|
|
123
|
+
const origin = getFlightOrigin(entity, taskIndex)
|
|
124
|
+
return {x: Number(origin.x), y: Number(origin.y)}
|
|
125
|
+
}
|
|
126
|
+
return interpolateFlightPosition(
|
|
127
|
+
getFlightOrigin(entity, taskIndex),
|
|
128
|
+
task.coordinates,
|
|
129
|
+
taskProgress
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
80
133
|
export function rotation(
|
|
81
134
|
origin: ServerContract.ActionParams.Type.coordinates,
|
|
82
135
|
destination: ServerContract.ActionParams.Type.coordinates
|
|
@@ -408,14 +461,18 @@ export function getDestinationLocation(
|
|
|
408
461
|
return undefined
|
|
409
462
|
}
|
|
410
463
|
|
|
464
|
+
/** Returns chain-tile coordinates (rounded). For visual position use getInterpolatedPosition. */
|
|
411
465
|
export function getPositionAt(
|
|
412
466
|
entity: HasScheduleAndLocation,
|
|
413
467
|
taskIndex: number,
|
|
414
468
|
taskProgress: number
|
|
415
469
|
): ServerContract.ActionParams.Type.coordinates {
|
|
416
|
-
if (!entity.schedule || entity.schedule.tasks.length === 0
|
|
470
|
+
if (!entity.schedule || entity.schedule.tasks.length === 0) {
|
|
417
471
|
return entity.coordinates
|
|
418
472
|
}
|
|
473
|
+
if (taskIndex < 0) {
|
|
474
|
+
return getFlightOrigin(entity, entity.schedule.tasks.length)
|
|
475
|
+
}
|
|
419
476
|
|
|
420
477
|
const task = entity.schedule.tasks[taskIndex]
|
|
421
478
|
|
package/src/types.ts
CHANGED
|
@@ -51,6 +51,9 @@ export enum TaskType {
|
|
|
51
51
|
DEPLOY = 8,
|
|
52
52
|
WRAP = 9,
|
|
53
53
|
UNWRAP = 10,
|
|
54
|
+
UNDEPLOY = 11,
|
|
55
|
+
WRAP_ENTITY = 12,
|
|
56
|
+
DEMOLISH = 13,
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
export enum LocationType {
|
|
@@ -58,6 +61,7 @@ export enum LocationType {
|
|
|
58
61
|
PLANET = 1,
|
|
59
62
|
ASTEROID = 2,
|
|
60
63
|
NEBULA = 3,
|
|
64
|
+
ICE_FIELD = 4,
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
export enum TaskCancelable {
|
package/src/utils/system.ts
CHANGED
|
@@ -22,12 +22,10 @@ export function getLocationType(
|
|
|
22
22
|
return LocationType.EMPTY
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
if (hashResult.array[1] < 96)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
return LocationType.NEBULA
|
|
25
|
+
if (hashResult.array[1] < 96) return LocationType.PLANET
|
|
26
|
+
if (hashResult.array[1] < 149) return LocationType.ASTEROID
|
|
27
|
+
if (hashResult.array[1] < 202) return LocationType.NEBULA
|
|
28
|
+
return LocationType.ICE_FIELD
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
export function isGatherableLocation(locationType: LocationType): boolean {
|
|
@@ -44,6 +42,8 @@ export function getLocationTypeName(type: LocationType): string {
|
|
|
44
42
|
return 'Asteroid'
|
|
45
43
|
case LocationType.NEBULA:
|
|
46
44
|
return 'Nebula'
|
|
45
|
+
case LocationType.ICE_FIELD:
|
|
46
|
+
return 'Ice Field'
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -76,6 +76,15 @@ function generateNebulaName(hashResult: Checksum512): string {
|
|
|
76
76
|
return `${nebulaAdjectives[adjIdx]} ${nebulaNouns[nounIdx]}`
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function generateIceFieldName(hashResult: Checksum512): string {
|
|
80
|
+
const A = 65
|
|
81
|
+
const letter1 = String.fromCharCode(A + (hashResult.array[0] % 26))
|
|
82
|
+
const letter2 = String.fromCharCode(A + (hashResult.array[1] % 26))
|
|
83
|
+
const subId = (hashResult.array[2] % 9) + 1
|
|
84
|
+
const num = (uint16(hashResult, 3) % 9000) + 1000
|
|
85
|
+
return `${letter1}${letter2}-${subId}/${num}`
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
export function getSystemName(gameSeed: Checksum256Type, location: CoordinatesType): string {
|
|
80
89
|
const seed = Checksum256.from(gameSeed)
|
|
81
90
|
const locationType = getLocationType(seed, location)
|
|
@@ -91,6 +100,8 @@ export function getSystemName(gameSeed: Checksum256Type, location: CoordinatesTy
|
|
|
91
100
|
return generateAsteroidName(hashResult)
|
|
92
101
|
case LocationType.NEBULA:
|
|
93
102
|
return generateNebulaName(hashResult)
|
|
103
|
+
case LocationType.ICE_FIELD:
|
|
104
|
+
return generateIceFieldName(hashResult)
|
|
94
105
|
default:
|
|
95
106
|
return generatePlanetName(hashResult)
|
|
96
107
|
}
|
|
@@ -123,10 +134,12 @@ export function deriveLocationStatic(
|
|
|
123
134
|
|
|
124
135
|
if (hashResult.array[1] < 96) {
|
|
125
136
|
loc.type = UInt8.from(LocationType.PLANET)
|
|
126
|
-
} else if (hashResult.array[1] <
|
|
137
|
+
} else if (hashResult.array[1] < 149) {
|
|
127
138
|
loc.type = UInt8.from(LocationType.ASTEROID)
|
|
128
|
-
} else {
|
|
139
|
+
} else if (hashResult.array[1] < 202) {
|
|
129
140
|
loc.type = UInt8.from(LocationType.NEBULA)
|
|
141
|
+
} else {
|
|
142
|
+
loc.type = UInt8.from(LocationType.ICE_FIELD)
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
loc.subtype = UInt8.from(
|