update:新增比赛服断线重连机制

This commit is contained in:
2026-07-10 15:11:45 +08:00
parent b5373bee31
commit 98ca638b63
4 changed files with 339 additions and 38 deletions
+74 -26
View File
@@ -17,6 +17,7 @@ import {
closeMatchWebSocket,
connectMatchWebSocket,
MATCH_WS_AUDIO_ACK_EVENT,
MATCH_WS_STATE_EVENT,
} from "@/matchWebsocket";
import { MESSAGETYPESV2 } from "@/constants";
import { takeMatchReturnSnapshot } from "@/utils/matchReturn";
@@ -55,6 +56,7 @@ const showOfflineModal = ref(false);
const xRingStreaks = ref({});
let battleEnded = false;
let skipNextRestoreOnShow = false;
let restoreGeneration = 0;
function clearHalfRestCountdown() {
if (halfRestTimer) {
@@ -78,13 +80,24 @@ function getHalfRestSeconds(battleInfo) {
}
}
const endTime = Number(battleInfo?.halfRestEndTime ?? battleInfo?.restEndTime);
if (!Number.isFinite(endTime) || endTime <= 0) return HALF_REST_SECONDS;
const timeoutTime = normalizeTimestamp(battleInfo?.timeoutTime);
if (timeoutTime) {
const elapsedSeconds = Math.max(0, (Date.now() - timeoutTime) / 1000);
return Math.max(
0,
Math.min(HALF_REST_SECONDS, Math.ceil(HALF_REST_SECONDS - elapsedSeconds))
);
}
const timestamp = endTime < 1e12 ? endTime * 1000 : endTime;
const diffSeconds = (timestamp - Date.now()) / 1000;
if (diffSeconds > 0 && diffSeconds <= HALF_REST_SECONDS) {
return Math.ceil(diffSeconds);
const endTime = normalizeTimestamp(
battleInfo?.halfRestEndTime ?? battleInfo?.restEndTime
);
if (endTime) {
const diffSeconds = (endTime - Date.now()) / 1000;
return Math.max(
0,
Math.min(HALF_REST_SECONDS, Math.ceil(diffSeconds))
);
}
return HALF_REST_SECONDS;
@@ -92,7 +105,14 @@ function getHalfRestSeconds(battleInfo) {
function startHalfRestCountdown(seconds = HALF_REST_SECONDS) {
clearHalfRestCountdown();
halfRestRemain.value = Math.max(0, Math.ceil(Number(seconds) || HALF_REST_SECONDS));
const secondsValue = Number(seconds);
const normalizedSeconds = Number.isFinite(secondsValue)
? secondsValue
: HALF_REST_SECONDS;
halfRestRemain.value = Math.max(
0,
Math.min(HALF_REST_SECONDS, Math.ceil(normalizedSeconds))
);
if (halfRestRemain.value <= 0) return;
@@ -305,6 +325,47 @@ function recoverData(battleInfo, { force = false } = {}) {
}
}
async function restoreLatestBattle() {
if (!battleId.value) return;
const currentRestoreId = ++restoreGeneration;
let result = null;
try {
result = normalizeBattleInfo(await getBattleAPI(battleId.value));
} catch (err) {
console.log("restore latest melee battle failed:", err);
return;
}
if (currentRestoreId !== restoreGeneration || !result) return;
if (result.status === 2) {
battleEnded = true;
uni.showToast({
title: "比赛已结束",
icon: "none",
});
uni.navigateBack({
delta: 2,
});
return;
}
reconnectMatchServer(result);
recoverData(result, { force: true });
}
function onMatchSocketState(event) {
if (event?.state !== "open" || event?.reconnected !== true) return;
if (
event.matchId &&
battleId.value &&
String(event.matchId) !== String(battleId.value)
) {
return;
}
restoreLatestBattle();
}
onLoad(async (options) => {
const returnSnapshot = options.fromReturn ? takeMatchReturnSnapshot() : null;
skipNextRestoreOnShow = false;
@@ -392,7 +453,7 @@ async function onReceiveMessage(msg) {
halfTimeTip.value = true;
halfRest.value = true;
tips.value = "准备下半场";
startHalfRestCountdown();
startHalfRestCountdown(getHalfRestSeconds(msg));
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
battleEnded = true;
notifyMatchAudioAck(msg);
@@ -409,14 +470,17 @@ onMounted(async () => {
keepScreenOn: true,
});
uni.$on("socket-inbox", onReceiveMessage);
uni.$on(MATCH_WS_STATE_EVENT, onMatchSocketState);
await laserCloseAPI();
});
onBeforeUnmount(() => {
uni.setKeepScreenOn({
keepScreenOn: false,
});
restoreGeneration += 1;
clearHalfRestCountdown();
uni.$off("socket-inbox", onReceiveMessage);
uni.$off(MATCH_WS_STATE_EVENT, onMatchSocketState);
closeBattleServer("melee-battle-unmount");
audioManager.stopAll();
});
@@ -425,28 +489,12 @@ onHide(() => {
closeBattleServer("melee-battle-hide");
});
onShow(async () => {
onShow(() => {
if (skipNextRestoreOnShow) {
skipNextRestoreOnShow = false;
return;
}
if (battleId.value) {
const result = normalizeBattleInfo(await getBattleAPI(battleId.value));
if (!result) return;
if (result.status === 2) {
battleEnded = true;
uni.showToast({
title: "比赛已结束",
icon: "none",
});
uni.navigateBack({
delta: 2,
});
} else {
reconnectMatchServer(result);
recoverData(result, { force: true });
}
}
restoreLatestBattle();
});
</script>