完善后端联调链路与模拟器多通道支持

This commit is contained in:
2026-04-01 18:48:59 +08:00
parent 94a1f0ba78
commit a70dc8d5d0
51 changed files with 4037 additions and 197 deletions

View File

@@ -387,6 +387,16 @@ export interface MapEngineGameInfoSnapshot {
export type MapEngineResultSnapshot = ResultSummarySnapshot
export interface MapEngineSessionFinishSummary {
status: 'finished' | 'failed' | 'cancelled'
finalDurationSec?: number
finalScore?: number
completedControls?: number
totalControls?: number
distanceMeters?: number
averageSpeedKmh?: number
}
const VIEW_SYNC_KEYS: Array<keyof MapEngineViewState> = [
'animationLevel',
'buildVersion',
@@ -1774,6 +1784,41 @@ export class MapEngine {
)
}
getSessionFinishSummary(statusOverride?: 'finished' | 'failed' | 'cancelled'): MapEngineSessionFinishSummary | null {
const definition = this.gameRuntime.definition
const sessionState = this.gameRuntime.state
if (!definition || !sessionState) {
return null
}
let status: 'finished' | 'failed' | 'cancelled'
if (statusOverride) {
status = statusOverride
} else if (sessionState.endReason === 'timed_out' || sessionState.status === 'failed') {
status = 'failed'
} else {
status = 'finished'
}
const endAt = sessionState.endedAt !== null ? sessionState.endedAt : Date.now()
const finalDurationSec = sessionState.startedAt !== null
? Math.max(0, Math.floor((endAt - sessionState.startedAt) / 1000))
: undefined
const totalControls = definition.controls.filter((control) => control.kind === 'control').length
return {
status,
finalDurationSec,
finalScore: this.getTotalSessionScore(),
completedControls: sessionState.completedControlIds.length,
totalControls,
distanceMeters: this.telemetryRuntime.state.distanceMeters,
averageSpeedKmh: this.telemetryRuntime.state.averageSpeedKmh === null
? undefined
: this.telemetryRuntime.state.averageSpeedKmh,
}
}
buildSessionRecoveryRuntimeSnapshot(): RecoveryRuntimeSnapshot | null {
const definition = this.gameRuntime.definition
const state = this.gameRuntime.state
@@ -3577,7 +3622,14 @@ export class MapEngine {
}
handleSetMockLocationMode(): void {
const wasListening = this.locationController.listening
if (!this.locationController.mockBridge.connected && !this.locationController.mockBridge.connecting) {
this.locationController.connectMockBridge()
}
this.locationController.setSourceMode('mock')
if (!wasListening && !this.locationController.listening) {
this.locationController.start()
}
}
handleConnectMockLocationBridge(): void {
@@ -3594,9 +3646,26 @@ export class MapEngine {
handleSetMockChannelId(channelId: string): void {
const normalized = String(channelId || '').trim() || 'default'
const shouldReconnectLocation = this.locationController.mockBridge.connected || this.locationController.mockBridge.connecting
const locationBridgeUrl = this.locationController.mockBridgeUrl
const shouldReconnectHeartRate = this.heartRateController.mockBridge.connected || this.heartRateController.mockBridge.connecting
const heartRateBridgeUrl = this.heartRateController.mockBridgeUrl
const shouldReconnectDebugLog = this.mockSimulatorDebugLogger.enabled
this.locationController.setMockChannelId(normalized)
this.heartRateController.setMockChannelId(normalized)
this.mockSimulatorDebugLogger.setChannelId(normalized)
if (shouldReconnectLocation) {
this.locationController.disconnectMockBridge()
this.locationController.connectMockBridge(locationBridgeUrl)
}
if (shouldReconnectHeartRate) {
this.heartRateController.disconnectMockBridge()
this.heartRateController.connectMockBridge(heartRateBridgeUrl)
}
if (shouldReconnectDebugLog) {
this.mockSimulatorDebugLogger.disconnect()
this.mockSimulatorDebugLogger.connect()
}
this.setState({
mockChannelIdText: normalized,
})
@@ -3663,7 +3732,14 @@ export class MapEngine {
}
handleSetMockHeartRateMode(): void {
const wasConnected = this.heartRateController.connected
if (!this.heartRateController.mockBridge.connected && !this.heartRateController.mockBridge.connecting) {
this.heartRateController.connectMockBridge()
}
this.heartRateController.setSourceMode('mock')
if (!wasConnected && !this.heartRateController.connected) {
this.heartRateController.startScanAndConnect()
}
}
handleConnectMockHeartRateBridge(): void {