完善多赛道联调与全局产品架构
This commit is contained in:
@@ -71,6 +71,7 @@ type MapPageData = MapEngineViewState & {
|
||||
showGameInfoPanel: boolean
|
||||
showResultScene: boolean
|
||||
showSystemSettingsPanel: boolean
|
||||
showHeartRateDevicePicker: boolean
|
||||
showCenterScaleRuler: boolean
|
||||
showPunchHintBanner: boolean
|
||||
punchHintFxClass: string
|
||||
@@ -92,6 +93,7 @@ type MapPageData = MapEngineViewState & {
|
||||
resultSceneHeroLabel: string
|
||||
resultSceneHeroValue: string
|
||||
resultSceneRows: MapEngineGameInfoRow[]
|
||||
resultSceneCountdownText: string
|
||||
panelTimerText: string
|
||||
panelTimerMode: 'elapsed' | 'countdown'
|
||||
panelMileageText: string
|
||||
@@ -157,6 +159,7 @@ const PUNCH_HINT_AUTO_HIDE_MS = 30000
|
||||
const PUNCH_HINT_FX_DURATION_MS = 420
|
||||
const PUNCH_HINT_HAPTIC_GAP_MS = 2400
|
||||
const SESSION_RECOVERY_PERSIST_INTERVAL_MS = 5000
|
||||
const RESULT_EXIT_REDIRECT_DELAY_MS = 3000
|
||||
let currentGameLaunchEnvelope: GameLaunchEnvelope = getDemoGameLaunchEnvelope()
|
||||
let mapEngine: MapEngine | null = null
|
||||
let stageCanvasAttached = false
|
||||
@@ -172,6 +175,8 @@ let panelMileageFxTimer = 0
|
||||
let panelSpeedFxTimer = 0
|
||||
let panelHeartRateFxTimer = 0
|
||||
let sessionRecoveryPersistTimer = 0
|
||||
let resultExitRedirectTimer = 0
|
||||
let resultExitCountdownTimer = 0
|
||||
let lastPunchHintHapticAt = 0
|
||||
let currentSystemSettingsConfig: SystemSettingsConfig | undefined
|
||||
let currentRemoteMapConfig: RemoteMapConfig | undefined
|
||||
@@ -179,6 +184,8 @@ let systemSettingsLockLifetimeActive = false
|
||||
let syncedBackendSessionStartId = ''
|
||||
let syncedBackendSessionFinishId = ''
|
||||
let shouldAutoRestoreRecoverySnapshot = false
|
||||
let redirectedToResultPage = false
|
||||
let pendingHeartRateSwitchDeviceName: string | null = null
|
||||
const DEBUG_MOCK_CHANNEL_ID_STORAGE_KEY = 'cmr.debug.mockChannelId.v1'
|
||||
const DEBUG_MOCK_AUTO_CONNECT_STORAGE_KEY = 'cmr.debug.autoConnectMockSources.v1'
|
||||
let lastCenterScaleRulerStablePatch: Pick<
|
||||
@@ -469,6 +476,34 @@ function clearSessionRecoveryPersistTimer() {
|
||||
}
|
||||
}
|
||||
|
||||
function clearResultExitRedirectTimer() {
|
||||
if (resultExitRedirectTimer) {
|
||||
clearTimeout(resultExitRedirectTimer)
|
||||
resultExitRedirectTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
function clearResultExitCountdownTimer() {
|
||||
if (resultExitCountdownTimer) {
|
||||
clearInterval(resultExitCountdownTimer)
|
||||
resultExitCountdownTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
function navigateAwayFromMapAfterCancel() {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
wx.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.redirectTo({
|
||||
url: '/pages/home/home',
|
||||
})
|
||||
}
|
||||
|
||||
function hasExplicitLaunchOptions(options?: MapPageLaunchOptions | null): boolean {
|
||||
if (!options) {
|
||||
return false
|
||||
@@ -776,11 +811,12 @@ function buildEmptyResultSceneSnapshot(): MapEngineResultSnapshot {
|
||||
|
||||
Page({
|
||||
data: {
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showResultScene: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: false,
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showResultScene: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showHeartRateDevicePicker: false,
|
||||
showCenterScaleRuler: false,
|
||||
statusBarHeight: 0,
|
||||
topInsetHeight: 12,
|
||||
hudPanelIndex: 0,
|
||||
@@ -798,6 +834,7 @@ Page({
|
||||
resultSceneHeroLabel: '本局用时',
|
||||
resultSceneHeroValue: '--',
|
||||
resultSceneRows: buildEmptyResultSceneSnapshot().rows,
|
||||
resultSceneCountdownText: '',
|
||||
panelTimerText: '00:00:00',
|
||||
panelTimerMode: 'elapsed',
|
||||
panelMileageText: '0m',
|
||||
@@ -927,8 +964,11 @@ Page({
|
||||
|
||||
onLoad(options: MapPageLaunchOptions) {
|
||||
clearSessionRecoveryPersistTimer()
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
syncedBackendSessionStartId = ''
|
||||
syncedBackendSessionFinishId = ''
|
||||
redirectedToResultPage = false
|
||||
shouldAutoRestoreRecoverySnapshot = options && options.recoverSession === '1'
|
||||
currentGameLaunchEnvelope = resolveGameLaunchEnvelope(options)
|
||||
if (!hasExplicitLaunchOptions(options)) {
|
||||
@@ -959,6 +999,7 @@ Page({
|
||||
const includeRulerFields = this.data.showCenterScaleRuler
|
||||
let shouldSyncRuntimeSystemSettings = false
|
||||
let nextLockLifetimeActive = isSystemSettingsLockLifetimeActive()
|
||||
let heartRateSwitchToastText = ''
|
||||
const nextData: Partial<MapPageData> = filterDebugOnlyPatch({
|
||||
...nextPatch,
|
||||
}, includeDebugFields, includeRulerFields)
|
||||
@@ -1054,6 +1095,8 @@ Page({
|
||||
: this.data.animationLevel
|
||||
let shouldSyncBackendSessionStart = false
|
||||
let backendSessionFinishStatus: 'finished' | 'failed' | null = null
|
||||
let shouldOpenResultExitPrompt = false
|
||||
let resultPageSnapshot: MapEngineResultSnapshot | null = null
|
||||
|
||||
if (nextAnimationLevel === 'lite') {
|
||||
clearHudFxTimer('timer')
|
||||
@@ -1112,13 +1155,24 @@ Page({
|
||||
shouldSyncRuntimeSystemSettings = true
|
||||
clearSessionRecoverySnapshot()
|
||||
clearSessionRecoveryPersistTimer()
|
||||
this.syncResultSceneSnapshot()
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
resultPageSnapshot = mapEngine ? mapEngine.getResultSceneSnapshot() : null
|
||||
nextData.showResultScene = true
|
||||
nextData.showDebugPanel = false
|
||||
nextData.showGameInfoPanel = false
|
||||
nextData.showSystemSettingsPanel = false
|
||||
clearGameInfoPanelSyncTimer()
|
||||
backendSessionFinishStatus = nextPatch.gameSessionStatus === 'finished' ? 'finished' : 'failed'
|
||||
shouldOpenResultExitPrompt = true
|
||||
if (resultPageSnapshot) {
|
||||
nextData.resultSceneTitle = resultPageSnapshot.title
|
||||
nextData.resultSceneSubtitle = resultPageSnapshot.subtitle
|
||||
nextData.resultSceneHeroLabel = resultPageSnapshot.heroLabel
|
||||
nextData.resultSceneHeroValue = resultPageSnapshot.heroValue
|
||||
nextData.resultSceneRows = resultPageSnapshot.rows
|
||||
}
|
||||
nextData.resultSceneCountdownText = '3 秒后自动进入成绩页'
|
||||
} else if (
|
||||
nextPatch.gameSessionStatus !== this.data.gameSessionStatus
|
||||
&& nextPatch.gameSessionStatus === 'idle'
|
||||
@@ -1128,6 +1182,8 @@ Page({
|
||||
shouldSyncRuntimeSystemSettings = true
|
||||
clearSessionRecoverySnapshot()
|
||||
clearSessionRecoveryPersistTimer()
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
} else if (
|
||||
nextPatch.gameSessionStatus !== this.data.gameSessionStatus
|
||||
&& nextPatch.gameSessionStatus === 'running'
|
||||
@@ -1138,6 +1194,19 @@ Page({
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
pendingHeartRateSwitchDeviceName
|
||||
&& nextPatch.heartRateConnected === true
|
||||
&& typeof nextPatch.heartRateDeviceText === 'string'
|
||||
) {
|
||||
const connectedDeviceName = nextPatch.heartRateDeviceText.trim()
|
||||
if (connectedDeviceName && connectedDeviceName === pendingHeartRateSwitchDeviceName) {
|
||||
heartRateSwitchToastText = `已切换到 ${connectedDeviceName}`
|
||||
nextData.statusText = `已切换心率带:${connectedDeviceName}`
|
||||
pendingHeartRateSwitchDeviceName = null
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(nextData).length || Object.keys(derivedPatch).length) {
|
||||
this.setData({
|
||||
...nextData,
|
||||
@@ -1152,9 +1221,20 @@ Page({
|
||||
if (backendSessionFinishStatus) {
|
||||
this.syncBackendSessionFinish(backendSessionFinishStatus)
|
||||
}
|
||||
if (shouldSyncRuntimeSystemSettings) {
|
||||
this.applyRuntimeSystemSettings(nextLockLifetimeActive)
|
||||
}
|
||||
if (shouldOpenResultExitPrompt && resultPageSnapshot) {
|
||||
this.stashPendingResultSnapshot(resultPageSnapshot)
|
||||
this.presentResultExitPrompt()
|
||||
}
|
||||
if (heartRateSwitchToastText) {
|
||||
wx.showToast({
|
||||
title: `${heartRateSwitchToastText},并设为首选设备`,
|
||||
icon: 'none',
|
||||
duration: 1800,
|
||||
})
|
||||
}
|
||||
if (shouldSyncRuntimeSystemSettings) {
|
||||
this.applyRuntimeSystemSettings(nextLockLifetimeActive)
|
||||
}
|
||||
if (this.data.showGameInfoPanel) {
|
||||
this.scheduleGameInfoPanelSnapshotSync()
|
||||
}
|
||||
@@ -1169,6 +1249,10 @@ Page({
|
||||
if (backendSessionFinishStatus) {
|
||||
this.syncBackendSessionFinish(backendSessionFinishStatus)
|
||||
}
|
||||
if (shouldOpenResultExitPrompt && resultPageSnapshot) {
|
||||
this.stashPendingResultSnapshot(resultPageSnapshot)
|
||||
this.presentResultExitPrompt()
|
||||
}
|
||||
if (shouldSyncRuntimeSystemSettings) {
|
||||
this.applyRuntimeSystemSettings(nextLockLifetimeActive)
|
||||
}
|
||||
@@ -1209,6 +1293,7 @@ Page({
|
||||
...buildResolvedSystemSettingsPatch(systemSettingsState),
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showResultScene: false,
|
||||
showSystemSettingsPanel: false,
|
||||
statusBarHeight,
|
||||
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
||||
@@ -1218,6 +1303,12 @@ Page({
|
||||
gameInfoSubtitle: '未开始',
|
||||
gameInfoLocalRows: [],
|
||||
gameInfoGlobalRows: buildEmptyGameInfoSnapshot().globalRows,
|
||||
resultSceneTitle: '本局结果',
|
||||
resultSceneSubtitle: '未开始',
|
||||
resultSceneHeroLabel: '本局用时',
|
||||
resultSceneHeroValue: '--',
|
||||
resultSceneRows: buildEmptyResultSceneSnapshot().rows,
|
||||
resultSceneCountdownText: '',
|
||||
panelTimerText: '00:00:00',
|
||||
panelTimerMode: 'elapsed',
|
||||
panelTimerFxClass: '',
|
||||
@@ -1349,6 +1440,18 @@ Page({
|
||||
stageCanvasAttached = false
|
||||
this.measureStageAndCanvas()
|
||||
this.loadGameLaunchEnvelope(currentGameLaunchEnvelope)
|
||||
const app = getApp<IAppOption>()
|
||||
const pendingHeartRateAutoConnect = app.globalData ? app.globalData.pendingHeartRateAutoConnect : null
|
||||
if (pendingHeartRateAutoConnect && pendingHeartRateAutoConnect.enabled && mapEngine) {
|
||||
const pendingDeviceName = pendingHeartRateAutoConnect.deviceName || '心率带'
|
||||
app.globalData.pendingHeartRateAutoConnect = null
|
||||
mapEngine.handleConnectHeartRate()
|
||||
this.setData({
|
||||
statusText: `正在自动连接局前设备:${pendingDeviceName}`,
|
||||
heartRateStatusText: `正在自动连接 ${pendingDeviceName}`,
|
||||
heartRateDeviceText: pendingDeviceName,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
@@ -1360,6 +1463,8 @@ Page({
|
||||
|
||||
onHide() {
|
||||
this.persistSessionRecoverySnapshot()
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
if (mapEngine) {
|
||||
mapEngine.handleAppHide()
|
||||
}
|
||||
@@ -1368,6 +1473,8 @@ Page({
|
||||
onUnload() {
|
||||
this.persistSessionRecoverySnapshot()
|
||||
clearSessionRecoveryPersistTimer()
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
syncedBackendSessionStartId = ''
|
||||
syncedBackendSessionFinishId = ''
|
||||
clearGameInfoPanelSyncTimer()
|
||||
@@ -1388,6 +1495,7 @@ Page({
|
||||
systemSettingsLockLifetimeActive = false
|
||||
currentGameLaunchEnvelope = getDemoGameLaunchEnvelope()
|
||||
shouldAutoRestoreRecoverySnapshot = false
|
||||
redirectedToResultPage = false
|
||||
stageCanvasAttached = false
|
||||
},
|
||||
|
||||
@@ -1528,6 +1636,57 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
stashPendingResultSnapshot(snapshot: MapEngineResultSnapshot) {
|
||||
const app = getApp<IAppOption>()
|
||||
if (app.globalData) {
|
||||
app.globalData.pendingResultSnapshot = snapshot
|
||||
}
|
||||
},
|
||||
|
||||
redirectToResultPage() {
|
||||
if (redirectedToResultPage) {
|
||||
return
|
||||
}
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
redirectedToResultPage = true
|
||||
const sessionContext = getCurrentBackendSessionContext()
|
||||
const resultUrl = sessionContext
|
||||
? `/pages/result/result?sessionId=${encodeURIComponent(sessionContext.sessionId)}`
|
||||
: '/pages/result/result'
|
||||
wx.redirectTo({
|
||||
url: resultUrl,
|
||||
})
|
||||
},
|
||||
|
||||
presentResultExitPrompt() {
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
|
||||
let remainingSeconds = Math.ceil(RESULT_EXIT_REDIRECT_DELAY_MS / 1000)
|
||||
this.setData({
|
||||
showResultScene: true,
|
||||
resultSceneCountdownText: `${remainingSeconds} 秒后自动进入成绩页`,
|
||||
})
|
||||
|
||||
resultExitCountdownTimer = setInterval(() => {
|
||||
remainingSeconds -= 1
|
||||
if (remainingSeconds <= 0) {
|
||||
clearResultExitCountdownTimer()
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
resultSceneCountdownText: `${remainingSeconds} 秒后自动进入成绩页`,
|
||||
})
|
||||
}, 1000) as unknown as number
|
||||
|
||||
resultExitRedirectTimer = setTimeout(() => {
|
||||
resultExitRedirectTimer = 0
|
||||
this.redirectToResultPage()
|
||||
}, RESULT_EXIT_REDIRECT_DELAY_MS) as unknown as number
|
||||
},
|
||||
|
||||
restoreRecoverySnapshot(snapshot: SessionRecoverySnapshot) {
|
||||
systemSettingsLockLifetimeActive = true
|
||||
this.applyRuntimeSystemSettings(true)
|
||||
@@ -2052,20 +2211,53 @@ Page({
|
||||
},
|
||||
|
||||
handleConnectHeartRate() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleConnectHeartRate()
|
||||
}
|
||||
},
|
||||
|
||||
handleDisconnectHeartRate() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleDisconnectHeartRate()
|
||||
if (this.data.lockHeartRateDevice || this.data.heartRateSourceMode !== 'real') {
|
||||
return
|
||||
}
|
||||
if (mapEngine) {
|
||||
mapEngine.handleConnectHeartRate()
|
||||
}
|
||||
},
|
||||
|
||||
handleOpenHeartRateDevicePicker() {
|
||||
if (this.data.lockHeartRateDevice || this.data.heartRateSourceMode !== 'real') {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
showHeartRateDevicePicker: true,
|
||||
})
|
||||
if (mapEngine) {
|
||||
mapEngine.handleConnectHeartRate()
|
||||
}
|
||||
},
|
||||
|
||||
handleCloseHeartRateDevicePicker() {
|
||||
this.setData({
|
||||
showHeartRateDevicePicker: false,
|
||||
})
|
||||
},
|
||||
|
||||
handleDisconnectHeartRate() {
|
||||
if (this.data.lockHeartRateDevice || this.data.heartRateSourceMode !== 'real') {
|
||||
return
|
||||
}
|
||||
if (mapEngine) {
|
||||
mapEngine.handleDisconnectHeartRate()
|
||||
}
|
||||
},
|
||||
|
||||
handleConnectHeartRateDevice(event: WechatMiniprogram.BaseEvent<{ deviceId?: string }>) {
|
||||
if (mapEngine && event.currentTarget && event.currentTarget.dataset && event.currentTarget.dataset.deviceId) {
|
||||
mapEngine.handleConnectHeartRateDevice(event.currentTarget.dataset.deviceId)
|
||||
const targetDeviceId = event.currentTarget.dataset.deviceId
|
||||
const targetDevice = this.data.heartRateDiscoveredDevices.find((item) => item.deviceId === targetDeviceId)
|
||||
pendingHeartRateSwitchDeviceName = targetDevice ? targetDevice.name : null
|
||||
mapEngine.handleConnectHeartRateDevice(targetDeviceId)
|
||||
this.setData({
|
||||
showHeartRateDevicePicker: false,
|
||||
statusText: targetDevice
|
||||
? `正在切换到 ${targetDevice.name}`
|
||||
: '正在切换心率带设备',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2174,9 +2366,21 @@ Page({
|
||||
cancelText: '取消',
|
||||
success: (result) => {
|
||||
if (result.confirm && mapEngine) {
|
||||
clearResultExitRedirectTimer()
|
||||
clearResultExitCountdownTimer()
|
||||
this.syncBackendSessionFinish('cancelled')
|
||||
clearSessionRecoverySnapshot()
|
||||
clearSessionRecoveryPersistTimer()
|
||||
systemSettingsLockLifetimeActive = false
|
||||
mapEngine.handleForceExitGame()
|
||||
wx.showToast({
|
||||
title: '已退出当前对局',
|
||||
icon: 'none',
|
||||
duration: 1000,
|
||||
})
|
||||
setTimeout(() => {
|
||||
navigateAwayFromMapAfterCancel()
|
||||
}, 180)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -2312,24 +2516,11 @@ Page({
|
||||
handleResultSceneTap() {},
|
||||
|
||||
handleCloseResultScene() {
|
||||
this.setData({
|
||||
showResultScene: false,
|
||||
})
|
||||
this.redirectToResultPage()
|
||||
},
|
||||
|
||||
handleRestartFromResult() {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
showResultScene: false,
|
||||
}, () => {
|
||||
if (mapEngine) {
|
||||
systemSettingsLockLifetimeActive = true
|
||||
this.applyRuntimeSystemSettings(true)
|
||||
mapEngine.handleStartGame()
|
||||
}
|
||||
})
|
||||
this.redirectToResultPage()
|
||||
},
|
||||
|
||||
handleOpenSystemSettingsPanel() {
|
||||
|
||||
Reference in New Issue
Block a user