整理文档并接入 H5 体验测试链路

This commit is contained in:
2026-03-27 15:36:27 +08:00
parent 0e025c3426
commit 0e0a724025
55 changed files with 4177 additions and 55 deletions

View File

@@ -2,7 +2,10 @@ import { lonLatToWorldTile, webMercatorToLonLat, type LonLatPoint } from './proj
import { parseOrienteeringCourseKml, type OrienteeringCourseData } from './orienteeringCourse'
import { mergeGameAudioConfig, type AudioCueKey, type GameAudioConfig, type GameAudioConfigOverrides, type PartialAudioCueConfig } from '../game/audio/audioConfig'
import { mergeTelemetryConfig, type TelemetryConfig } from '../game/telemetry/telemetryConfig'
import { type GameControlDisplayContentOverride } from '../game/core/gameDefinition'
import {
type GameContentExperienceConfigOverride,
type GameControlDisplayContentOverride,
} from '../game/core/gameDefinition'
import {
mergeGameHapticsConfig,
mergeGameUiEffectsConfig,
@@ -233,6 +236,44 @@ function parsePunchPolicy(rawValue: unknown): 'enter' | 'enter-confirm' {
return rawValue === 'enter' ? 'enter' : 'enter-confirm'
}
function parseContentExperienceOverride(
rawValue: unknown,
baseUrl: string,
): GameContentExperienceConfigOverride | undefined {
const normalized = normalizeObjectRecord(rawValue)
if (!Object.keys(normalized).length) {
return undefined
}
const typeValue = typeof normalized.type === 'string' ? normalized.type.trim().toLowerCase() : ''
if (typeValue === 'native') {
return {
type: 'native',
fallback: 'native',
}
}
if (typeValue !== 'h5') {
return undefined
}
const rawUrl = typeof normalized.url === 'string' ? normalized.url.trim() : ''
if (!rawUrl) {
return undefined
}
const bridgeValue = typeof normalized.bridge === 'string' && normalized.bridge.trim()
? normalized.bridge.trim()
: 'content-v1'
return {
type: 'h5',
url: resolveUrl(baseUrl, rawUrl),
bridge: bridgeValue,
fallback: 'native',
}
}
function parseGameMode(rawValue: unknown): 'classic-sequential' | 'score-o' {
if (typeof rawValue !== 'string') {
return 'classic-sequential'
@@ -780,19 +821,41 @@ function parseGameConfigFromJson(text: string, gameConfigUrl: string): ParsedGam
const bodyValue = typeof (item as Record<string, unknown>).body === 'string'
? ((item as Record<string, unknown>).body as string).trim()
: ''
const clickTitleValue = typeof (item as Record<string, unknown>).clickTitle === 'string'
? ((item as Record<string, unknown>).clickTitle as string).trim()
: ''
const clickBodyValue = typeof (item as Record<string, unknown>).clickBody === 'string'
? ((item as Record<string, unknown>).clickBody as string).trim()
: ''
const autoPopupValue = (item as Record<string, unknown>).autoPopup
const onceValue = (item as Record<string, unknown>).once
const priorityNumeric = Number((item as Record<string, unknown>).priority)
const contentExperienceValue = parseContentExperienceOverride((item as Record<string, unknown>).contentExperience, gameConfigUrl)
const clickExperienceValue = parseContentExperienceOverride((item as Record<string, unknown>).clickExperience, gameConfigUrl)
const hasAutoPopup = typeof autoPopupValue === 'boolean'
const hasOnce = typeof onceValue === 'boolean'
const hasPriority = Number.isFinite(priorityNumeric)
if (titleValue || bodyValue || hasAutoPopup || hasOnce || hasPriority) {
if (
titleValue
|| bodyValue
|| clickTitleValue
|| clickBodyValue
|| hasAutoPopup
|| hasOnce
|| hasPriority
|| contentExperienceValue
|| clickExperienceValue
) {
controlContentOverrides[key] = {
...(titleValue ? { title: titleValue } : {}),
...(bodyValue ? { body: bodyValue } : {}),
...(clickTitleValue ? { clickTitle: clickTitleValue } : {}),
...(clickBodyValue ? { clickBody: clickBodyValue } : {}),
...(hasAutoPopup ? { autoPopup: !!autoPopupValue } : {}),
...(hasOnce ? { once: !!onceValue } : {}),
...(hasPriority ? { priority: Math.max(0, Math.round(priorityNumeric)) } : {}),
...(contentExperienceValue ? { contentExperience: contentExperienceValue } : {}),
...(clickExperienceValue ? { clickExperience: clickExperienceValue } : {}),
}
}
}