完善后端联调链路与模拟器多通道支持
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user