@shipload/sdk 1.0.0-next.3 → 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 +203 -97
- package/lib/shipload.js +762 -419
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +752 -418
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/contracts/server.ts +54 -1
- package/src/data/capabilities.ts +5 -330
- package/src/data/capability-formulas.ts +68 -0
- package/src/data/colors.ts +1 -0
- package/src/data/items.json +245 -0
- package/src/data/metadata.ts +44 -1
- package/src/data/recipes.json +6 -16
- package/src/derivation/capability-mappings.ts +120 -0
- package/src/derivation/resources.ts +27 -19
- package/src/entities/container.ts +23 -8
- package/src/entities/ship-deploy.ts +78 -41
- package/src/entities/ship.ts +17 -0
- package/src/entities/warehouse.ts +8 -0
- package/src/index-module.ts +32 -18
- package/src/managers/actions.ts +24 -1
- package/src/nft/description.ts +25 -6
- package/src/resolution/resolve-item.ts +14 -9
- 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/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,
|
|
@@ -202,14 +207,19 @@ export type {PlanetSubtypeInfo} from './data/locations'
|
|
|
202
207
|
export {
|
|
203
208
|
capabilityNames,
|
|
204
209
|
capabilityAttributes,
|
|
205
|
-
statMappings,
|
|
206
210
|
isInvertedAttribute,
|
|
207
211
|
getCapabilityAttributes,
|
|
212
|
+
} from './data/capabilities'
|
|
213
|
+
export type {CapabilityAttribute, StatMapping} from './data/capabilities'
|
|
214
|
+
|
|
215
|
+
export {
|
|
216
|
+
deriveStatMappings,
|
|
208
217
|
getStatMappings,
|
|
209
218
|
getStatMappingsForStat,
|
|
210
219
|
getStatMappingsForCapability,
|
|
211
|
-
} from './
|
|
212
|
-
export
|
|
220
|
+
} from './derivation/capability-mappings'
|
|
221
|
+
export {SLOT_FORMULAS} from './data/capability-formulas'
|
|
222
|
+
export type {SlotConsumer, SlotConsumerKind} from './data/capability-formulas'
|
|
213
223
|
|
|
214
224
|
export {
|
|
215
225
|
encodeStats,
|
|
@@ -241,8 +251,11 @@ export {
|
|
|
241
251
|
computeWarehouseHullCapabilities,
|
|
242
252
|
computeStorageCapabilities,
|
|
243
253
|
computeShipCapabilities,
|
|
254
|
+
GATHERER_DEPTH_TABLE,
|
|
255
|
+
GATHERER_DEPTH_MAX_TIER,
|
|
256
|
+
gathererDepthForTier,
|
|
244
257
|
} from './entities/ship-deploy'
|
|
245
|
-
export type {ShipCapabilities} from './entities/ship-deploy'
|
|
258
|
+
export type {ShipCapabilities, GathererDepthParams} from './entities/ship-deploy'
|
|
246
259
|
|
|
247
260
|
export {resolveItem} from './resolution/resolve-item'
|
|
248
261
|
export type {
|
|
@@ -302,6 +315,7 @@ export {
|
|
|
302
315
|
computeLoaderThrust,
|
|
303
316
|
computeCrafterSpeed,
|
|
304
317
|
computeCrafterDrain,
|
|
318
|
+
computeWarpRange,
|
|
305
319
|
} from './nft/description'
|
|
306
320
|
|
|
307
321
|
export {
|
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)
|
|
@@ -44,17 +48,21 @@ export function computeBaseCapacityWarehouse(stats: bigint): number {
|
|
|
44
48
|
|
|
45
49
|
export const computeEngineThrust = (vol: number): number => 400 + idiv(vol * 3, 4)
|
|
46
50
|
export const computeEngineDrain = (thm: number): number => Math.max(30, 50 - idiv(thm, 70))
|
|
47
|
-
export const computeGeneratorCap = (
|
|
48
|
-
export const computeGeneratorRech = (
|
|
51
|
+
export const computeGeneratorCap = (com: number): number => 300 + idiv(com, 6)
|
|
52
|
+
export const computeGeneratorRech = (fin: number): number => 1 + idiv(fin * 3, 1000)
|
|
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
|
-
export const computeLoaderMass = (
|
|
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
|
-
export const computeCrafterDrain = (
|
|
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: [
|
|
@@ -223,10 +224,11 @@ function computeCapabilityGroup(
|
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
case MODULE_STORAGE: {
|
|
226
|
-
const str = stats.strength
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const
|
|
227
|
+
const str = stats.strength
|
|
228
|
+
const den = stats.density
|
|
229
|
+
const hrd = stats.hardness
|
|
230
|
+
const sat = stats.saturation
|
|
231
|
+
const statSum = str + den + hrd + sat
|
|
230
232
|
const pct = 10 + Math.floor((statSum * 10) / 2997)
|
|
231
233
|
return {capability: 'Storage', attributes: [{label: 'Capacity Bonus', value: pct}]}
|
|
232
234
|
}
|
|
@@ -241,7 +243,7 @@ function resolveModule(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
241
243
|
if (stats !== undefined) {
|
|
242
244
|
const decoded = decodeCraftedItemStats(id, toBigStats(stats))
|
|
243
245
|
const modType = getModuleCapabilityType(id)
|
|
244
|
-
const group = computeCapabilityGroup(modType, decoded)
|
|
246
|
+
const group = computeCapabilityGroup(modType, decoded, item.tier)
|
|
245
247
|
if (group) attributes = [group]
|
|
246
248
|
}
|
|
247
249
|
return {
|
|
@@ -310,13 +312,16 @@ function resolveEntity(
|
|
|
310
312
|
const modStats = BigInt(mod.installed.stats.toString())
|
|
311
313
|
const decodedStats = decodeCraftedItemStats(modItemId, modStats)
|
|
312
314
|
const modType = getModuleCapabilityType(modItemId)
|
|
313
|
-
const group = computeCapabilityGroup(modType, decodedStats)
|
|
314
315
|
let modName = 'Module'
|
|
316
|
+
let modTier = 1
|
|
315
317
|
try {
|
|
316
|
-
|
|
318
|
+
const modItem = getItem(modItemId)
|
|
319
|
+
modName = modItem.name
|
|
320
|
+
modTier = modItem.tier
|
|
317
321
|
} catch {
|
|
318
322
|
modName = itemMetadata[modItemId]?.name ?? 'Module'
|
|
319
323
|
}
|
|
324
|
+
const group = computeCapabilityGroup(modType, decodedStats, modTier)
|
|
320
325
|
return {
|
|
321
326
|
name: modName,
|
|
322
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
|
|