update:优化
This commit is contained in:
@@ -41,6 +41,7 @@ const AUDIO_TIMEOUT_PER_KEY = 2600;
|
||||
const AUDIO_TIMEOUT_MAX = 12000;
|
||||
const BATTLE_CANCEL_RETURN_DELAY = 2000;
|
||||
const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"];
|
||||
const X_RING_STREAKS_KEY = "team-battle-x-ring-streaks";
|
||||
const PROGRESS_ZERO_EVENT = "team-battle-progress-zero";
|
||||
const COUNTDOWN_READY_EVENT = "team-battle-countdown-ready";
|
||||
|
||||
@@ -107,6 +108,21 @@ watch(online, (newVal, oldVal) => {
|
||||
});
|
||||
|
||||
// 统一把秒级或毫秒级时间戳转成毫秒,方便和本机时间比较。
|
||||
function loadXRingStreaks() {
|
||||
const cached = uni.getStorageSync(X_RING_STREAKS_KEY);
|
||||
xRingStreaks.value =
|
||||
cached && typeof cached === "object" && !Array.isArray(cached) ? cached : {};
|
||||
}
|
||||
|
||||
function saveXRingStreaks() {
|
||||
uni.setStorageSync(X_RING_STREAKS_KEY, xRingStreaks.value);
|
||||
}
|
||||
|
||||
function clearXRingStreaks() {
|
||||
xRingStreaks.value = {};
|
||||
uni.removeStorageSync(X_RING_STREAKS_KEY);
|
||||
}
|
||||
|
||||
function normalizeTimestamp(value) {
|
||||
const numberValue = Number(value || 0);
|
||||
if (!numberValue) return 0;
|
||||
@@ -213,11 +229,19 @@ function waitForRoundTipClosed(isFinal) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleRoundTipAutoClose() {
|
||||
function closeRoundTip() {
|
||||
showRoundTip.value = false;
|
||||
clearRoundTipWaiters();
|
||||
}
|
||||
|
||||
function cancelRoundTipDisplay() {
|
||||
closeRoundTip();
|
||||
}
|
||||
|
||||
function handleRoundTipAutoClose() {
|
||||
closeRoundTip();
|
||||
}
|
||||
|
||||
function markProgressDeadline(countdown, delayMs = 0) {
|
||||
if (!countdown?.value || !countdown?.durationMs) {
|
||||
progressDeadlineAt = 0;
|
||||
@@ -283,7 +307,7 @@ function invalidateBattleQueue({ stopAudio = false, stopProgress = false } = {})
|
||||
clearAudioWaiters();
|
||||
progressDeadlineAt = 0;
|
||||
clearProgressZeroWaiters();
|
||||
clearRoundTipWaiters();
|
||||
cancelRoundTipDisplay();
|
||||
if (stopAudio) audioManager.stopAll();
|
||||
if (stopProgress) uni.$emit("update-remain", { stop: true });
|
||||
}
|
||||
@@ -442,6 +466,44 @@ function updateGoldenRound(battleInfo) {
|
||||
goldenRound.value = Math.max(1, finishedGoldCount + (battleInfo.current?.playerId ? 1 : 0));
|
||||
}
|
||||
|
||||
// Restore an info snapshot whose eventType points at the NewRound phase.
|
||||
function getRestorePrevRound(battleInfo) {
|
||||
const currentRoundValue = Number(battleInfo?.current?.round || 0);
|
||||
if (currentRoundValue > 1) return currentRoundValue - 1;
|
||||
const rounds = Array.isArray(battleInfo?.rounds) ? battleInfo.rounds : [];
|
||||
return Math.max(1, rounds.length || 1);
|
||||
}
|
||||
|
||||
function applyRestoreNewRoundSnapshot(battleInfo) {
|
||||
const prevRound = getRestorePrevRound(battleInfo);
|
||||
start.value = true;
|
||||
showRoundTip.value = false;
|
||||
scores.value = [];
|
||||
blueScores.value = [];
|
||||
currentRound.value = prevRound;
|
||||
|
||||
if (battleInfo.current?.goldRound) {
|
||||
store.updateShotInfo(0, 0);
|
||||
currentBluePoint.value = battleInfo.teams?.[1]?.score ?? 0;
|
||||
currentRedPoint.value = battleInfo.teams?.[2]?.score ?? 0;
|
||||
} else {
|
||||
const latestRound = battleInfo.rounds?.[prevRound - 1];
|
||||
if (battleInfo?.shootNumber) {
|
||||
store.updateShotInfo(0, battleInfo.shootNumber);
|
||||
}
|
||||
|
||||
if (latestRound) {
|
||||
currentBluePoint.value = latestRound.scores?.[1]?.score ?? 0;
|
||||
currentRedPoint.value = latestRound.scores?.[2]?.score ?? 0;
|
||||
} else {
|
||||
currentBluePoint.value = 0;
|
||||
currentRedPoint.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return prevRound;
|
||||
}
|
||||
|
||||
// 回填比赛基础信息:队伍、比分、轮次、金箭状态等公共字段都在这里统一处理。
|
||||
function applyBattleBase(battleInfo) {
|
||||
if (!battleInfo) return;
|
||||
@@ -650,7 +712,7 @@ function applyReadyState(battleInfo) {
|
||||
updateTips("");
|
||||
progressDeadlineAt = 0;
|
||||
clearProgressZeroWaiters();
|
||||
clearRoundTipWaiters();
|
||||
cancelRoundTipDisplay();
|
||||
|
||||
const createTime = normalizeTimestamp(battleInfo?.createTime || Date.now());
|
||||
const readyElapsed = (Date.now() - createTime) / 1000;
|
||||
@@ -662,7 +724,7 @@ function applyReadyState(battleInfo) {
|
||||
}
|
||||
|
||||
// 快照恢复入口:只把页面拉到服务端最新状态,不重放已经发生过的语音。
|
||||
function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
|
||||
function applyBattleSnapshot(battleInfo, { restore = false, restoreEventType = 0 } = {}) {
|
||||
// 快照恢复只负责“把页面拉回最新状态”,不重放历史语音。
|
||||
applyBattleBase(battleInfo);
|
||||
if (battleInfo.status === 0) {
|
||||
@@ -672,6 +734,12 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
|
||||
|
||||
start.value = true;
|
||||
showRoundTip.value = false;
|
||||
|
||||
if (restore && restoreEventType === MESSAGETYPESV2.NewRound) {
|
||||
applyRestoreNewRoundSnapshot(battleInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
updateShotInfo(battleInfo);
|
||||
updateCurrentRoundScores(battleInfo);
|
||||
|
||||
@@ -699,6 +767,7 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
|
||||
// 开局任务:切换到正式比赛态,并播报“比赛开始”。
|
||||
async function runBattleStartTask(task, runId) {
|
||||
// 开赛任务只负责切换正式态并播“比赛开始”,后续进入队列顺序。
|
||||
clearXRingStreaks();
|
||||
applyBattleBase(task.message);
|
||||
start.value = true;
|
||||
pendingRoundAudio = true;
|
||||
@@ -711,12 +780,20 @@ async function runBattleStartTask(task, runId) {
|
||||
async function runToSomeoneShootTask(task, runId) {
|
||||
// 新射手任务:先等上一轮倒计时归零,再更新展示、播轮次/射手语音、启动倒计时。
|
||||
const battleInfo = task.message;
|
||||
const shouldEnterImmediately = showRoundTip.value;
|
||||
if (shouldEnterImmediately) {
|
||||
cancelRoundTipDisplay();
|
||||
progressDeadlineAt = 0;
|
||||
clearProgressZeroWaiters();
|
||||
} else {
|
||||
await waitForProgressZero();
|
||||
}
|
||||
if (!isQueueAlive(runId)) return;
|
||||
|
||||
applyBattleBase(battleInfo);
|
||||
start.value = true;
|
||||
showRoundTip.value = false;
|
||||
hideRestoreLoading();
|
||||
cancelRoundTipDisplay();
|
||||
updateShotInfo(battleInfo);
|
||||
|
||||
const current = battleInfo.current || {};
|
||||
@@ -769,12 +846,17 @@ function updateXRingStreak(shooterId, isXRing) {
|
||||
const id = String(shooterId);
|
||||
if (!isXRing) {
|
||||
xRingStreaks.value[id] = 0;
|
||||
saveXRingStreaks();
|
||||
return false;
|
||||
}
|
||||
|
||||
xRingStreaks.value[id] = (xRingStreaks.value[id] || 0) + 1;
|
||||
if (xRingStreaks.value[id] < 3) return false;
|
||||
if (xRingStreaks.value[id] < 3) {
|
||||
saveXRingStreaks();
|
||||
return false;
|
||||
}
|
||||
xRingStreaks.value[id] = 0;
|
||||
saveXRingStreaks();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -818,7 +900,7 @@ async function runShootResultTask(task) {
|
||||
async function runNewRoundTask(task, runId) {
|
||||
// 新回合提示要故意延后一点,避免和上一箭结果展示抢先后顺序。
|
||||
const battleInfo = task.message;
|
||||
const prevRound = currentRound.value;
|
||||
const prevRound = task.restorePrevRound || currentRound.value;
|
||||
await new Promise((resolve) => setTimeout(resolve, ROUND_TIP_DELAY));
|
||||
if (!isQueueAlive(runId)) return;
|
||||
|
||||
@@ -854,9 +936,6 @@ async function runNewRoundTask(task, runId) {
|
||||
currentRedPoint.value = 0;
|
||||
}
|
||||
pendingRoundAudio = true;
|
||||
await waitForRoundTipClosed(!!battleInfo.current?.goldRound);
|
||||
if (!isQueueAlive(runId)) return;
|
||||
showRoundTip.value = false;
|
||||
}
|
||||
|
||||
// 终局任务:播放结束语音后,根据状态跳结果页或返回上一页。
|
||||
@@ -864,6 +943,7 @@ async function runBattleEndTask(task, runId) {
|
||||
const battleInfo = task.message;
|
||||
applyBattleBase(battleInfo);
|
||||
battleEnded = true;
|
||||
clearXRingStreaks();
|
||||
matchStatus.value = battleInfo.status;
|
||||
if (battleInfo.status === 4) {
|
||||
showRoundTip.value = true;
|
||||
@@ -924,15 +1004,44 @@ async function restoreLatestBattle() {
|
||||
latestAppliedServerTime.value = Math.max(latestAppliedServerTime.value, snapshotTime);
|
||||
}
|
||||
|
||||
const restoreEventType = Number(result?.eventType || 0);
|
||||
|
||||
if (result.status === 2) {
|
||||
clearXRingStreaks();
|
||||
hideRestoreLoading();
|
||||
uni.redirectTo({
|
||||
url: `/pages/friend-battle-result?battleId=${result.matchId}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (result.status === 4) {
|
||||
clearXRingStreaks();
|
||||
}
|
||||
|
||||
applyBattleSnapshot(result, { restore: true });
|
||||
if (restoreEventType === MESSAGETYPESV2.NewRound) {
|
||||
const prevRound = getRestorePrevRound(result);
|
||||
const restoreMessage = { ...result, type: MESSAGETYPESV2.NewRound };
|
||||
const restoreKey = getMessageKey(restoreMessage);
|
||||
applyBattleSnapshot(result, { restore: true, restoreEventType });
|
||||
|
||||
if (!handledMessageKeys.has(restoreKey) && !queuedMessageKeys.has(restoreKey)) {
|
||||
queuedMessageKeys.add(restoreKey);
|
||||
battleQueue.value.unshift({
|
||||
message: result,
|
||||
type: MESSAGETYPESV2.NewRound,
|
||||
key: restoreKey,
|
||||
serverTime: snapshotTime,
|
||||
receivedAt: Date.now(),
|
||||
order: ++queueOrder,
|
||||
restorePrevRound: prevRound,
|
||||
});
|
||||
}
|
||||
|
||||
runBattleQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
applyBattleSnapshot(result, { restore: true, restoreEventType });
|
||||
runBattleQueue();
|
||||
}
|
||||
|
||||
@@ -984,7 +1093,7 @@ onLoad((options) => {
|
||||
shootTimeTotal.value = DEFAULT_SHOOT_TIME;
|
||||
showOfflineModal.value = false;
|
||||
hideRestoreLoading();
|
||||
xRingStreaks.value = {};
|
||||
loadXRingStreaks();
|
||||
queueGeneration += 1;
|
||||
battleQueue.value = [];
|
||||
queueRunning.value = false;
|
||||
@@ -998,7 +1107,7 @@ onLoad((options) => {
|
||||
queuedMessageKeys.clear();
|
||||
progressDeadlineAt = 0;
|
||||
clearProgressZeroWaiters();
|
||||
clearRoundTipWaiters();
|
||||
cancelRoundTipDisplay();
|
||||
store.updateShotInfo(0, 0);
|
||||
store.updateTips("");
|
||||
latestShotFlash.value = null;
|
||||
|
||||
Reference in New Issue
Block a user