1
This commit is contained in:
@@ -5,7 +5,9 @@ import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/p
|
||||
import {
|
||||
advanceLocalPuzzleLevel,
|
||||
dragLocalPuzzlePiece,
|
||||
isLocalPuzzleRun,
|
||||
startLocalPuzzleRun,
|
||||
submitLocalPuzzleLeaderboard,
|
||||
swapLocalPuzzlePieces,
|
||||
} from './puzzleLocalRuntime';
|
||||
|
||||
@@ -314,4 +316,25 @@ describe('puzzleLocalRuntime', () => {
|
||||
expect(hasAnyOriginalNeighborPair(secondRun.currentLevel?.board.pieces ?? [])).toBe(false);
|
||||
expect(hasAnyOriginalNeighborPair(thirdRun.currentLevel?.board.pieces ?? [])).toBe(false);
|
||||
});
|
||||
|
||||
test('本地 run 通关后用本地排行榜兜底,不再依赖后端 runId', () => {
|
||||
const clearedRun = solveCurrentLevel(startLocalPuzzleRun(baseWork));
|
||||
|
||||
expect(isLocalPuzzleRun(clearedRun)).toBe(true);
|
||||
expect(clearedRun.currentLevel?.leaderboardEntries).toEqual([]);
|
||||
|
||||
const leaderboardRun = submitLocalPuzzleLeaderboard(clearedRun, '本地玩家');
|
||||
|
||||
expect(leaderboardRun.leaderboardEntries).toEqual([
|
||||
{
|
||||
rank: 1,
|
||||
nickname: '本地玩家',
|
||||
elapsedMs: clearedRun.currentLevel?.elapsedMs ?? 0,
|
||||
isCurrentPlayer: true,
|
||||
},
|
||||
]);
|
||||
expect(leaderboardRun.currentLevel?.leaderboardEntries).toEqual(
|
||||
leaderboardRun.leaderboardEntries,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
PuzzleBoardSnapshot,
|
||||
PuzzleCellPosition,
|
||||
PuzzleGridSize,
|
||||
PuzzleLeaderboardEntry,
|
||||
PuzzleMergedGroupState,
|
||||
PuzzlePieceState,
|
||||
PuzzleRunSnapshot,
|
||||
@@ -10,6 +11,8 @@ import type {
|
||||
} from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
|
||||
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||
|
||||
const LOCAL_PUZZLE_RUN_ID_PREFIX = 'local-puzzle-run-';
|
||||
|
||||
function resolvePuzzleGridSize(clearedLevelCount: number): PuzzleGridSize {
|
||||
return clearedLevelCount >= 3 ? 4 : 3;
|
||||
}
|
||||
@@ -399,6 +402,20 @@ function buildLocalNextProfileId(entryProfileId: string, levelIndex: number) {
|
||||
return `${entryProfileId}::local-level-${levelIndex}`;
|
||||
}
|
||||
|
||||
function buildLocalLeaderboardEntries(
|
||||
nickname: string,
|
||||
elapsedMs: number,
|
||||
): PuzzleLeaderboardEntry[] {
|
||||
return [
|
||||
{
|
||||
rank: 1,
|
||||
nickname,
|
||||
elapsedMs,
|
||||
isCurrentPlayer: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// 第一版单机兜底没有后端推荐池时,才沿用当前作品图片生成可推进的临时关卡名。
|
||||
function buildLocalLevelName(previousLevelName: string, levelIndex: number) {
|
||||
return `${previousLevelName.replace(/ · 第 \d+ 关$/, '')} · 第 ${levelIndex} 关`;
|
||||
@@ -447,7 +464,7 @@ function buildFallbackLocalLevel(run: PuzzleRunSnapshot): PuzzleRunSnapshot {
|
||||
|
||||
export function startLocalPuzzleRun(item: PuzzleWorkSummary): PuzzleRunSnapshot {
|
||||
const gridSize = resolvePuzzleGridSize(0);
|
||||
const runId = `local-puzzle-run-${item.profileId}-${Date.now()}`;
|
||||
const runId = `${LOCAL_PUZZLE_RUN_ID_PREFIX}${item.profileId}-${Date.now()}`;
|
||||
const startedAtMs = Date.now();
|
||||
return {
|
||||
runId,
|
||||
@@ -658,3 +675,45 @@ export function dragLocalPuzzlePiece(
|
||||
export function advanceLocalPuzzleLevel(run: PuzzleRunSnapshot): PuzzleRunSnapshot {
|
||||
return buildFallbackLocalLevel(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前拼图运行态是否为前端本地兜底 run。
|
||||
* 这类 run 没有后端持久化记录,不能再调用依赖真实 runId 的排行榜接口。
|
||||
*/
|
||||
export function isLocalPuzzleRun(run: PuzzleRunSnapshot | null | undefined) {
|
||||
return Boolean(run?.runId?.startsWith(LOCAL_PUZZLE_RUN_ID_PREFIX));
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地拼图 run 的排行榜兜底。
|
||||
* 当前版本只写入当前玩家成绩,避免结算阶段继续请求后端导致“run 不存在”。
|
||||
*/
|
||||
export function submitLocalPuzzleLeaderboard(
|
||||
run: PuzzleRunSnapshot,
|
||||
nickname: string,
|
||||
): PuzzleRunSnapshot {
|
||||
const currentLevel = run.currentLevel;
|
||||
if (
|
||||
!currentLevel ||
|
||||
currentLevel.status !== 'cleared' ||
|
||||
currentLevel.elapsedMs === null
|
||||
) {
|
||||
return run;
|
||||
}
|
||||
if ((currentLevel.leaderboardEntries ?? []).length > 0) {
|
||||
return run;
|
||||
}
|
||||
|
||||
const leaderboardEntries = buildLocalLeaderboardEntries(
|
||||
nickname,
|
||||
currentLevel.elapsedMs,
|
||||
);
|
||||
return {
|
||||
...run,
|
||||
leaderboardEntries,
|
||||
currentLevel: {
|
||||
...currentLevel,
|
||||
leaderboardEntries,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user