update:优化
This commit is contained in:
@@ -41,6 +41,7 @@ const AUDIO_TIMEOUT_PER_KEY = 2600;
|
|||||||
const AUDIO_TIMEOUT_MAX = 12000;
|
const AUDIO_TIMEOUT_MAX = 12000;
|
||||||
const BATTLE_CANCEL_RETURN_DELAY = 2000;
|
const BATTLE_CANCEL_RETURN_DELAY = 2000;
|
||||||
const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"];
|
const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"];
|
||||||
|
const X_RING_STREAKS_KEY = "team-battle-x-ring-streaks";
|
||||||
const PROGRESS_ZERO_EVENT = "team-battle-progress-zero";
|
const PROGRESS_ZERO_EVENT = "team-battle-progress-zero";
|
||||||
const COUNTDOWN_READY_EVENT = "team-battle-countdown-ready";
|
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) {
|
function normalizeTimestamp(value) {
|
||||||
const numberValue = Number(value || 0);
|
const numberValue = Number(value || 0);
|
||||||
if (!numberValue) return 0;
|
if (!numberValue) return 0;
|
||||||
@@ -213,11 +229,19 @@ function waitForRoundTipClosed(isFinal) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRoundTipAutoClose() {
|
function closeRoundTip() {
|
||||||
showRoundTip.value = false;
|
showRoundTip.value = false;
|
||||||
clearRoundTipWaiters();
|
clearRoundTipWaiters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cancelRoundTipDisplay() {
|
||||||
|
closeRoundTip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRoundTipAutoClose() {
|
||||||
|
closeRoundTip();
|
||||||
|
}
|
||||||
|
|
||||||
function markProgressDeadline(countdown, delayMs = 0) {
|
function markProgressDeadline(countdown, delayMs = 0) {
|
||||||
if (!countdown?.value || !countdown?.durationMs) {
|
if (!countdown?.value || !countdown?.durationMs) {
|
||||||
progressDeadlineAt = 0;
|
progressDeadlineAt = 0;
|
||||||
@@ -283,7 +307,7 @@ function invalidateBattleQueue({ stopAudio = false, stopProgress = false } = {})
|
|||||||
clearAudioWaiters();
|
clearAudioWaiters();
|
||||||
progressDeadlineAt = 0;
|
progressDeadlineAt = 0;
|
||||||
clearProgressZeroWaiters();
|
clearProgressZeroWaiters();
|
||||||
clearRoundTipWaiters();
|
cancelRoundTipDisplay();
|
||||||
if (stopAudio) audioManager.stopAll();
|
if (stopAudio) audioManager.stopAll();
|
||||||
if (stopProgress) uni.$emit("update-remain", { stop: true });
|
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));
|
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) {
|
function applyBattleBase(battleInfo) {
|
||||||
if (!battleInfo) return;
|
if (!battleInfo) return;
|
||||||
@@ -650,7 +712,7 @@ function applyReadyState(battleInfo) {
|
|||||||
updateTips("");
|
updateTips("");
|
||||||
progressDeadlineAt = 0;
|
progressDeadlineAt = 0;
|
||||||
clearProgressZeroWaiters();
|
clearProgressZeroWaiters();
|
||||||
clearRoundTipWaiters();
|
cancelRoundTipDisplay();
|
||||||
|
|
||||||
const createTime = normalizeTimestamp(battleInfo?.createTime || Date.now());
|
const createTime = normalizeTimestamp(battleInfo?.createTime || Date.now());
|
||||||
const readyElapsed = (Date.now() - createTime) / 1000;
|
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);
|
applyBattleBase(battleInfo);
|
||||||
if (battleInfo.status === 0) {
|
if (battleInfo.status === 0) {
|
||||||
@@ -672,6 +734,12 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
|
|||||||
|
|
||||||
start.value = true;
|
start.value = true;
|
||||||
showRoundTip.value = false;
|
showRoundTip.value = false;
|
||||||
|
|
||||||
|
if (restore && restoreEventType === MESSAGETYPESV2.NewRound) {
|
||||||
|
applyRestoreNewRoundSnapshot(battleInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateShotInfo(battleInfo);
|
updateShotInfo(battleInfo);
|
||||||
updateCurrentRoundScores(battleInfo);
|
updateCurrentRoundScores(battleInfo);
|
||||||
|
|
||||||
@@ -699,6 +767,7 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
|
|||||||
// 开局任务:切换到正式比赛态,并播报“比赛开始”。
|
// 开局任务:切换到正式比赛态,并播报“比赛开始”。
|
||||||
async function runBattleStartTask(task, runId) {
|
async function runBattleStartTask(task, runId) {
|
||||||
// 开赛任务只负责切换正式态并播“比赛开始”,后续进入队列顺序。
|
// 开赛任务只负责切换正式态并播“比赛开始”,后续进入队列顺序。
|
||||||
|
clearXRingStreaks();
|
||||||
applyBattleBase(task.message);
|
applyBattleBase(task.message);
|
||||||
start.value = true;
|
start.value = true;
|
||||||
pendingRoundAudio = true;
|
pendingRoundAudio = true;
|
||||||
@@ -711,12 +780,20 @@ async function runBattleStartTask(task, runId) {
|
|||||||
async function runToSomeoneShootTask(task, runId) {
|
async function runToSomeoneShootTask(task, runId) {
|
||||||
// 新射手任务:先等上一轮倒计时归零,再更新展示、播轮次/射手语音、启动倒计时。
|
// 新射手任务:先等上一轮倒计时归零,再更新展示、播轮次/射手语音、启动倒计时。
|
||||||
const battleInfo = task.message;
|
const battleInfo = task.message;
|
||||||
await waitForProgressZero();
|
const shouldEnterImmediately = showRoundTip.value;
|
||||||
|
if (shouldEnterImmediately) {
|
||||||
|
cancelRoundTipDisplay();
|
||||||
|
progressDeadlineAt = 0;
|
||||||
|
clearProgressZeroWaiters();
|
||||||
|
} else {
|
||||||
|
await waitForProgressZero();
|
||||||
|
}
|
||||||
if (!isQueueAlive(runId)) return;
|
if (!isQueueAlive(runId)) return;
|
||||||
|
|
||||||
applyBattleBase(battleInfo);
|
applyBattleBase(battleInfo);
|
||||||
start.value = true;
|
start.value = true;
|
||||||
showRoundTip.value = false;
|
hideRestoreLoading();
|
||||||
|
cancelRoundTipDisplay();
|
||||||
updateShotInfo(battleInfo);
|
updateShotInfo(battleInfo);
|
||||||
|
|
||||||
const current = battleInfo.current || {};
|
const current = battleInfo.current || {};
|
||||||
@@ -769,12 +846,17 @@ function updateXRingStreak(shooterId, isXRing) {
|
|||||||
const id = String(shooterId);
|
const id = String(shooterId);
|
||||||
if (!isXRing) {
|
if (!isXRing) {
|
||||||
xRingStreaks.value[id] = 0;
|
xRingStreaks.value[id] = 0;
|
||||||
|
saveXRingStreaks();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
xRingStreaks.value[id] = (xRingStreaks.value[id] || 0) + 1;
|
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;
|
xRingStreaks.value[id] = 0;
|
||||||
|
saveXRingStreaks();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,7 +900,7 @@ async function runShootResultTask(task) {
|
|||||||
async function runNewRoundTask(task, runId) {
|
async function runNewRoundTask(task, runId) {
|
||||||
// 新回合提示要故意延后一点,避免和上一箭结果展示抢先后顺序。
|
// 新回合提示要故意延后一点,避免和上一箭结果展示抢先后顺序。
|
||||||
const battleInfo = task.message;
|
const battleInfo = task.message;
|
||||||
const prevRound = currentRound.value;
|
const prevRound = task.restorePrevRound || currentRound.value;
|
||||||
await new Promise((resolve) => setTimeout(resolve, ROUND_TIP_DELAY));
|
await new Promise((resolve) => setTimeout(resolve, ROUND_TIP_DELAY));
|
||||||
if (!isQueueAlive(runId)) return;
|
if (!isQueueAlive(runId)) return;
|
||||||
|
|
||||||
@@ -854,9 +936,6 @@ async function runNewRoundTask(task, runId) {
|
|||||||
currentRedPoint.value = 0;
|
currentRedPoint.value = 0;
|
||||||
}
|
}
|
||||||
pendingRoundAudio = true;
|
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;
|
const battleInfo = task.message;
|
||||||
applyBattleBase(battleInfo);
|
applyBattleBase(battleInfo);
|
||||||
battleEnded = true;
|
battleEnded = true;
|
||||||
|
clearXRingStreaks();
|
||||||
matchStatus.value = battleInfo.status;
|
matchStatus.value = battleInfo.status;
|
||||||
if (battleInfo.status === 4) {
|
if (battleInfo.status === 4) {
|
||||||
showRoundTip.value = true;
|
showRoundTip.value = true;
|
||||||
@@ -924,15 +1004,44 @@ async function restoreLatestBattle() {
|
|||||||
latestAppliedServerTime.value = Math.max(latestAppliedServerTime.value, snapshotTime);
|
latestAppliedServerTime.value = Math.max(latestAppliedServerTime.value, snapshotTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const restoreEventType = Number(result?.eventType || 0);
|
||||||
|
|
||||||
if (result.status === 2) {
|
if (result.status === 2) {
|
||||||
|
clearXRingStreaks();
|
||||||
hideRestoreLoading();
|
hideRestoreLoading();
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/friend-battle-result?battleId=${result.matchId}`,
|
url: `/pages/friend-battle-result?battleId=${result.matchId}`,
|
||||||
});
|
});
|
||||||
return;
|
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();
|
runBattleQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -984,7 +1093,7 @@ onLoad((options) => {
|
|||||||
shootTimeTotal.value = DEFAULT_SHOOT_TIME;
|
shootTimeTotal.value = DEFAULT_SHOOT_TIME;
|
||||||
showOfflineModal.value = false;
|
showOfflineModal.value = false;
|
||||||
hideRestoreLoading();
|
hideRestoreLoading();
|
||||||
xRingStreaks.value = {};
|
loadXRingStreaks();
|
||||||
queueGeneration += 1;
|
queueGeneration += 1;
|
||||||
battleQueue.value = [];
|
battleQueue.value = [];
|
||||||
queueRunning.value = false;
|
queueRunning.value = false;
|
||||||
@@ -998,7 +1107,7 @@ onLoad((options) => {
|
|||||||
queuedMessageKeys.clear();
|
queuedMessageKeys.clear();
|
||||||
progressDeadlineAt = 0;
|
progressDeadlineAt = 0;
|
||||||
clearProgressZeroWaiters();
|
clearProgressZeroWaiters();
|
||||||
clearRoundTipWaiters();
|
cancelRoundTipDisplay();
|
||||||
store.updateShotInfo(0, 0);
|
store.updateShotInfo(0, 0);
|
||||||
store.updateTips("");
|
store.updateTips("");
|
||||||
latestShotFlash.value = null;
|
latestShotFlash.value = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user