update:新增乱斗语音,排位赛界面新增统计

This commit is contained in:
2026-11-06 10:29:48 +08:00
parent 419cefd00e
commit 4435553c60
8 changed files with 324 additions and 35 deletions
+78
View File
@@ -0,0 +1,78 @@
export const MELEE_FIRST_HALF_COMPLETE_AUDIO =
"上半场6箭已射完,请等待他人完成射箭";
export const MELEE_SECOND_HALF_COMPLETE_AUDIO =
"下半场6箭已射完,请等待最终排名";
// 独立于页面和连接生命周期,避免切回页面、同场重连后重复提示。
export function createMeleeCompletionTracker() {
let contextKey = "";
let completedHalves = new Set();
let closedThrough = 0;
function prepare(info, userId) {
if (!info?.matchId || userId === undefined || userId === null) return false;
const key = JSON.stringify([String(info.matchId), String(userId)]);
if (contextKey !== key) {
contextKey = key;
completedHalves = new Set();
closedThrough = 0;
}
return true;
}
function observe(info, userId) {
if (!prepare(info, userId)) return;
const rounds = Array.isArray(info.rounds) ? info.rounds : [];
rounds.slice(0, 2).forEach((round, index) => {
if ((round.shoots?.[userId]?.length || 0) >= 6) {
completedHalves.add(index + 1);
}
});
if (rounds.length === 2 || Number(info.status) === 3) {
closedThrough = Math.max(closedThrough, 1);
}
if ([2, 4].includes(Number(info.status))) closedThrough = 2;
}
function getShotAudio(info, userId) {
if (!prepare(info, userId)) return "";
const mode = Number(info.mode);
const rounds = Array.isArray(info.rounds) ? info.rounds : [];
const half = rounds.length;
const roster = info.teams?.[0]?.players;
const expectedPlayers = mode === 4 ? 5 : mode === 5 ? 10 : 0;
const shoots = rounds[half - 1]?.shoots;
const ownShots = shoots?.[userId];
const eligible =
expectedPlayers > 0 &&
[1, 2].includes(half) &&
half > closedThrough &&
!completedHalves.has(half) &&
![2, 3, 4].includes(Number(info.status)) &&
String(info.shootData?.playerId) === String(userId) &&
Array.isArray(ownShots) && ownShots.length === 6 &&
Array.isArray(roster) && roster.length === expectedPlayers &&
new Set(roster.map((player) => String(player.id))).size === expectedPlayers &&
roster.some((player) => String(player.id) === String(userId)) &&
roster.every((player) => {
// protobuf map 可以省略零箭用户;缺失项按零箭处理,异常项不参与推断。
const list = shoots[player.id];
return list === undefined || Array.isArray(list);
}) &&
roster.some((player) =>
String(player.id) !== String(userId) &&
(shoots[player.id]?.length || 0) < 6
);
// 包括最后完成者在内,完成状态只消费一次;恢复快照也走同一入口。
observe(info, userId);
if (!eligible) return "";
return half === 1
? MELEE_FIRST_HALF_COMPLETE_AUDIO
: MELEE_SECOND_HALF_COMPLETE_AUDIO;
}
return { observe, getShotAudio };
}
export default createMeleeCompletionTracker();