diff --git a/src/audioManager.js b/src/audioManager.js index 6fb4882..8d742ed 100644 --- a/src/audioManager.js +++ b/src/audioManager.js @@ -20,6 +20,12 @@ export const audioFils = { "https://static.shelingxingqiu.com/attachment/2025-09-17/dcutwrda0amn5kqr4j.mp3", 距离不足: "https://static.shelingxingqiu.com/attachment/2025-11-12/de6hr2faw28t0ianh0.mp3", + "靶纸不符!请更换靶纸": + "https://static.shelingxingqiu.com/shootmini/static/audio/%E9%9D%B6%E7%BA%B8%E4%B8%8D%E7%AC%A6%EF%BC%81%E8%AF%B7%E6%9B%B4%E6%8D%A2%E9%9D%B6%E7%BA%B8.MP3", + "站距与靶纸合格": + "https://static.shelingxingqiu.com/shootmini/static/audio/%E7%AB%99%E8%B7%9D%E4%B8%8E%E9%9D%B6%E7%BA%B8%E5%90%88%E6%A0%BC.MP3", + "请射箭!测试站距与靶纸": + "https://static.shelingxingqiu.com/shootmini/static/audio/%E8%AF%B7%E5%B0%84%E7%AE%AD%EF%BC%81%E6%B5%8B%E8%AF%95%E7%AB%99%E8%B7%9D%E4%B8%8E%E9%9D%B6%E7%BA%B8.MP3", "未发现靶纸,请瞄准靶纸射箭": "https://static.shelingxingqiu.com/shootmini/static/audio/%E6%9C%AA%E5%8F%91%E7%8E%B0%E9%9D%B6%E7%BA%B8%EF%BC%8C%E8%AF%B7%E7%9E%84%E5%87%86%E9%9D%B6%E7%BA%B8%E5%B0%84%E7%AE%AD.MP3", 轮到你了: @@ -54,6 +60,8 @@ export const audioFils = { "https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%E6%A3%80%E6%9F%A5%E8%B7%9D%E7%A6%BB%E5%92%8C%E9%9D%B6%E7%BA%B8.mp3", "射箭无效,距离不足": "https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E8%B7%9D%E7%A6%BB%E4%B8%8D%E8%B6%B3.MP3", + "射箭无效,距离不足且靶纸错误": + "https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E8%B7%9D%E7%A6%BB%E4%B8%8D%E8%B6%B3%E4%B8%94%E9%9D%B6%E7%BA%B8%E9%94%99%E8%AF%AF.MP3", "射箭无效,未识别到靶纸": "https://static.shelingxingqiu.com/shootmini/static/audio/%E5%B0%84%E7%AE%AD%E6%97%A0%E6%95%88%EF%BC%8C%E6%9C%AA%E8%AF%86%E5%88%AB%E5%88%B0%E9%9D%B6%E7%BA%B8.MP3", "射箭无效,靶纸错误": @@ -126,8 +134,12 @@ const AUDIO_WARM_PRIORITY_KEYS = [ "比赛结束", "射击无效", "射箭无效,距离不足", + "射箭无效,距离不足且靶纸错误", "射箭无效,未识别到靶纸", "射箭无效,靶纸错误", + "靶纸不符!请更换靶纸", + "站距与靶纸合格", + "请射箭!测试站距与靶纸", "中场休息", "下半场开始", "决金箭轮", diff --git a/src/components/HeaderProgress.vue b/src/components/HeaderProgress.vue index b01472b..936d5bd 100644 --- a/src/components/HeaderProgress.vue +++ b/src/components/HeaderProgress.vue @@ -2,7 +2,11 @@ import { ref, watch, onMounted, onBeforeUnmount } from "vue"; import audioManager from "@/audioManager"; import { MESSAGETYPESV2 } from "@/constants"; -import { getDirectionText, getInvalidShotAudioKey } from "@/util"; +import { + getDirectionText, + getInvalidShotAudioKey, + getInvalidShotText, +} from "@/util"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -88,7 +92,7 @@ async function onReceiveMessage(message) { currentRoundEnded.value = true; } else if (type === MESSAGETYPESV2.InvalidShot) { uni.showToast({ - title: "距离不足,无效", + title: getInvalidShotText(shootData), icon: "none", }); audioManager.play(getInvalidShotAudioKey(shootData)); diff --git a/src/components/ShootProgress.vue b/src/components/ShootProgress.vue index cd0912b..5e1fea3 100644 --- a/src/components/ShootProgress.vue +++ b/src/components/ShootProgress.vue @@ -2,7 +2,11 @@ import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue"; import audioManager from "@/audioManager"; import { MESSAGETYPESV2 } from "@/constants"; -import { getDirectionText, getInvalidShotAudioKey } from "@/util"; +import { + getDirectionText, + getInvalidShotAudioKey, + getInvalidShotText, +} from "@/util"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -171,7 +175,7 @@ async function onReceiveMessage(msg) { audioManager.play("中场休息"); } else if (msg.type === MESSAGETYPESV2.InvalidShot) { uni.showToast({ - title: "距离不足,无效", + title: getInvalidShotText(msg.shootData), icon: "none", }); audioManager.play(getInvalidShotAudioKey(msg.shootData)); diff --git a/src/components/TestDistance.vue b/src/components/TestDistance.vue index fbbb91d..7beb4f2 100644 --- a/src/components/TestDistance.vue +++ b/src/components/TestDistance.vue @@ -6,6 +6,7 @@ import Avatar from "@/components/Avatar.vue"; import audioManager from "@/audioManager"; import { simulShootAPI } from "@/apis"; import { MESSAGETYPESV2 } from "@/constants"; +import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util"; import useStore from "@/store"; import { storeToRefs } from "pinia"; const store = useStore(); @@ -26,6 +27,7 @@ const props = defineProps({ }); const arrow = ref({}); const distance = ref(0); +const statusText = ref(""); const showsimul = ref(false); const count = ref(props.count); const timer = ref(null); @@ -34,7 +36,7 @@ const updateTimer = (value) => { count.value = Math.round(value); }; onMounted(() => { - audioManager.play("请射箭测试距离"); + audioManager.play("请射箭!测试站距与靶纸"); if (props.isBattle) { timer.value = setInterval(() => { count.value -= 1; @@ -51,14 +53,12 @@ onBeforeUnmount(() => { async function onReceiveMessage(msg) { if (Array.isArray(msg)) return; if (msg.type === MESSAGETYPESV2.TestDistance) { - const rawDistance = Number(msg.shootData?.distance); + const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst); distance.value = Number.isFinite(rawDistance) ? Number((rawDistance / 100).toFixed(2)) : 0; - if (rawDistance === 0) { - audioManager.play("未发现靶纸,请瞄准靶纸射箭"); - } else if (distance.value >= 5) audioManager.play("距离合格"); - else audioManager.play("距离不足"); + statusText.value = getDistanceCheckText(msg.shootData); + audioManager.play(getDistanceCheckAudioKey(msg.shootData)); } } @@ -101,13 +101,12 @@ onBeforeUnmount(() => { 模拟射箭 - - 当前距离{{ distance }}米 - 已达到距离要求 - 请调整站位 + + 当前距离{{ distance }}米 + {{ statusText }} - 请射箭,测试站距 + 请射箭,测试站距与靶纸 diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index 734a751..ab82d89 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -9,7 +9,11 @@ import { getServerMessageTypeName, } from "@/utils/matchProtocol"; import { MESSAGETYPESV2 } from "@/constants"; -import { getDirectionText, getInvalidShotAudioKey } from "@/util"; +import { + getDirectionText, + getDistanceCheckAudioKey, + getInvalidShotAudioKey, +} from "@/util"; import { normalizeId, normalizeMatchInfo, @@ -49,20 +53,6 @@ const ENABLE_REALTIME_MESSAGE_LOG = (() => { } })(); -function getServerMessageLogSummary(message = {}) { - const practiceInfo = message.practice_info || message.practiceInfo || {}; - const matchInfo = message.match_info || message.matchInfo || {}; - return { - type: message.type, - matchId: normalizeId(pickField(message, "matchId", "match_id")), - sequence: message.sequence, - practiceDetailCount: Array.isArray(practiceInfo.details) - ? practiceInfo.details.length - : 0, - roundCount: Array.isArray(matchInfo.rounds) ? matchInfo.rounds.length : 0, - }; -} - // 比赛服消息类型先映射成项目里已有的 V2 业务消息,页面仍然复用原来的 socket-inbox 流程。 const BUSINESS_TYPE_BY_SERVER_TYPE = { [ServerMessageType.SERVER_MSG_MATCH_READY]: MESSAGETYPESV2.AboutToStart, @@ -87,6 +77,9 @@ function normalizeShootData(shootData) { if (normalized.distance === undefined && normalized.dst !== undefined) { normalized.distance = normalized.dst; } + if (normalized.targetOk === undefined && normalized.target_ok !== undefined) { + normalized.targetOk = normalized.target_ok; + } return normalized; } @@ -368,10 +361,8 @@ function getShootResultAudioKeys(shootData) { } function getTestDistanceAudioKeys(shootData) { - const distance = Number(shootData?.distance ?? shootData?.dst); - if (Number.isNaN(distance)) return []; - if (distance === 0) return ["未发现靶纸,请瞄准靶纸射箭"]; - return [distance / 100 >= 5 ? "\u8ddd\u79bb\u5408\u683c" : "\u8ddd\u79bb\u4e0d\u8db3"]; + if (!shootData) return []; + return [getDistanceCheckAudioKey(shootData)]; } function getAckAudioKeys(message, businessMessage) { @@ -805,13 +796,8 @@ function handleMessage(data) { return; } - const typeName = getServerMessageTypeName(message.type); if (ENABLE_REALTIME_MESSAGE_LOG) { - console.log( - "收到比赛服 WebSocket 消息", - typeName, - getServerMessageLogSummary(message) - ); + console.log("收到比赛服 WebSocket 消息", message); } const decodedMatchId = normalizeId(pickField(message, "matchId", "match_id")); diff --git a/src/pages/first-try.vue b/src/pages/first-try.vue index 89d8bd4..b767cb3 100644 --- a/src/pages/first-try.vue +++ b/src/pages/first-try.vue @@ -22,7 +22,12 @@ import { } from "@/apis"; import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket"; import { sharePractiseData } from "@/canvas"; -import { wxShare, debounce } from "@/util"; +import { + wxShare, + debounce, + getDistanceCheckAudioKey, + getShootValidation, +} from "@/util"; import { MESSAGETYPESV2 } from "@/constants"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -154,14 +159,11 @@ async function onReceiveMessage(msg) { } else if (msg.type === MESSAGETYPESV2.BattleEnd) { setTimeout(() => onOver(msg), 1500); } else if (msg.type === MESSAGETYPESV2.TestDistance && step.value === 3) { - const rawDistance = Number(msg.shootData?.distance); - if (rawDistance === 0) { - audioManager.play("未发现靶纸,请瞄准靶纸射箭"); - } else if (rawDistance / 100 >= 5) { - audioManager.play("距离合格"); - btnDisabled.value = false; - showGuide.value = true; - } else audioManager.play("距离不足"); + const result = getShootValidation(msg.shootData); + const isQualified = result.distanceOk && result.targetOk; + audioManager.play(getDistanceCheckAudioKey(msg.shootData)); + btnDisabled.value = !isQualified; + showGuide.value = isQualified; } // messages.forEach((msg) => { // if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) { diff --git a/src/pages/team-battle/components/TestDistance.vue b/src/pages/team-battle/components/TestDistance.vue index 372ab92..cc932d1 100644 --- a/src/pages/team-battle/components/TestDistance.vue +++ b/src/pages/team-battle/components/TestDistance.vue @@ -6,6 +6,7 @@ import Avatar from "./Avatar.vue"; import audioManager from "@/audioManager"; import { simulShootAPI } from "@/apis"; import { MESSAGETYPESV2 } from "@/constants"; +import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util"; import useStore from "@/store"; import { storeToRefs } from "pinia"; const store = useStore(); @@ -26,6 +27,7 @@ const props = defineProps({ }); const arrow = ref({}); const distance = ref(0); +const statusText = ref(""); const showsimul = ref(false); const count = ref(props.count); const timer = ref(null); @@ -34,7 +36,7 @@ const updateTimer = (value) => { count.value = Math.round(value); }; onMounted(() => { - audioManager.play("请射箭测试距离"); + audioManager.play("请射箭!测试站距与靶纸"); if (props.isBattle) { timer.value = setInterval(() => { count.value -= 1; @@ -51,14 +53,12 @@ onBeforeUnmount(() => { async function onReceiveMessage(msg) { if (Array.isArray(msg)) return; if (msg.type === MESSAGETYPESV2.TestDistance) { - const rawDistance = Number(msg.shootData?.distance); + const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst); distance.value = Number.isFinite(rawDistance) ? Number((rawDistance / 100).toFixed(2)) : 0; - if (rawDistance === 0) { - audioManager.play("未发现靶纸,请瞄准靶纸射箭"); - } else if (distance.value >= 5) audioManager.play("距离合格"); - else audioManager.play("距离不足"); + statusText.value = getDistanceCheckText(msg.shootData); + audioManager.play(getDistanceCheckAudioKey(msg.shootData)); } } @@ -101,13 +101,12 @@ onBeforeUnmount(() => { 模拟射箭 - - 当前距离{{ distance }}米 - 已达到距离要求 - 请调整站位 + + 当前距离{{ distance }}米 + {{ statusText }} - 请射箭,测试站距 + 请射箭,测试站距与靶纸 diff --git a/src/pages/team-battle/index.vue b/src/pages/team-battle/index.vue index 239cad1..c1580f4 100644 --- a/src/pages/team-battle/index.vue +++ b/src/pages/team-battle/index.vue @@ -20,7 +20,11 @@ import { MATCH_WS_STATE_EVENT, } from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; -import { getDirectionText, getInvalidShotAudioKey } from "@/util"; +import { + getDirectionText, + getInvalidShotAudioKey, + getInvalidShotText, +} from "@/util"; import { takeMatchReturnSnapshot } from "@/utils/matchReturn"; import audioManager, { AUDIO_INTERRUPTION_BEGIN_EVENT, @@ -1133,7 +1137,7 @@ async function runBattleEndTask(task, runId) { async function runInvalidShotTask(task, runId) { if (!isQueueAlive(runId)) return; uni.showToast({ - title: "距离不足,无效", + title: getInvalidShotText(task.message?.shootData), icon: "none", }); await playAudioKeys(getInvalidShotAudioKey(task.message?.shootData), { diff --git a/src/pages/training/components/ShootProgress.vue b/src/pages/training/components/ShootProgress.vue index 7de4571..abf442d 100644 --- a/src/pages/training/components/ShootProgress.vue +++ b/src/pages/training/components/ShootProgress.vue @@ -2,7 +2,11 @@ import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue"; import audioManager from "@/audioManager"; import { MESSAGETYPESV2 } from "@/constants"; -import { getDirectionText, getInvalidShotAudioKey } from "@/util"; +import { + getDirectionText, + getInvalidShotAudioKey, + getInvalidShotText, +} from "@/util"; import Avatar from "@/components/Avatar.vue"; import useStore from "@/store"; @@ -238,7 +242,7 @@ async function onReceiveMessage(msg) { audioManager.play("中场休息"); } else if (msg.type === MESSAGETYPESV2.InvalidShot) { uni.showToast({ - title: "距离不足,无效", + title: getInvalidShotText(msg.shootData), icon: "none", }); audioManager.play(getInvalidShotAudioKey(msg.shootData)); diff --git a/src/pages/training/components/TestDistance.vue b/src/pages/training/components/TestDistance.vue index 75e893b..791e621 100644 --- a/src/pages/training/components/TestDistance.vue +++ b/src/pages/training/components/TestDistance.vue @@ -6,6 +6,7 @@ import Avatar from "@/components/Avatar.vue"; import audioManager from "@/audioManager"; import { simulShootAPI } from "@/apis"; import { MESSAGETYPESV2 } from "@/constants"; +import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util"; import useStore from "@/store"; import { storeToRefs } from "pinia"; const store = useStore(); @@ -30,6 +31,7 @@ const props = defineProps({ }); const arrow = ref({}); const distance = ref(0); +const statusText = ref(""); const showsimul = ref(false); const count = ref(props.count); const timer = ref(null); @@ -38,7 +40,7 @@ const updateTimer = (value) => { count.value = Math.round(value); }; onMounted(() => { - audioManager.play("请射箭测试距离"); + audioManager.play("请射箭!测试站距与靶纸"); if (props.isBattle) { timer.value = setInterval(() => { count.value -= 1; @@ -55,14 +57,12 @@ onBeforeUnmount(() => { async function onReceiveMessage(msg) { if (Array.isArray(msg)) return; if (msg.type === MESSAGETYPESV2.TestDistance) { - const rawDistance = Number(msg.shootData?.distance); + const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst); distance.value = Number.isFinite(rawDistance) ? Number((rawDistance / 100).toFixed(2)) : 0; - if (rawDistance === 0) { - audioManager.play("未发现靶纸,请瞄准靶纸射箭"); - } else if (distance.value >= 5) audioManager.play("距离合格"); - else audioManager.play("距离不足"); + statusText.value = getDistanceCheckText(msg.shootData); + audioManager.play(getDistanceCheckAudioKey(msg.shootData)); } } @@ -100,13 +100,12 @@ onBeforeUnmount(() => { 当前靶纸为{{ targetType }}cm全环靶 - - 当前距离{{ distance }} - 已达到距离要求 - 请调整站位 + + 当前距离{{ distance }} + {{ statusText }} - 请射箭,测试站距 + 请射箭,测试站距与靶纸 diff --git a/src/util.js b/src/util.js index 0de566a..c703cf7 100644 --- a/src/util.js +++ b/src/util.js @@ -329,18 +329,70 @@ export const getDirectionText = (angle = 0) => { } }; -// 正式射箭阶段的距离单位为厘米,按距离异常类型选择对应语音。 -export const getInvalidShotAudioKey = (shootData) => { - if (!shootData || typeof shootData !== "object") return "射击无效"; - // protobuf 会省略值为 0 的标量字段;消息体存在且距离缺失时按 0 处理。 +// 射箭数据中的距离单位为厘米;旧版本会明确上报 target_ok=true。 +export const getShootValidation = (shootData) => { + if (!shootData || typeof shootData !== "object") { + return { + rawDistance: 0, + distance: 0, + distanceOk: false, + targetOk: false, + targetDetected: false, + }; + } + const rawDistance = Number(shootData.distance ?? shootData.dst ?? 0); - if (!Number.isFinite(rawDistance)) return "射击无效"; - if (rawDistance < 0) return "射箭无效,靶纸错误"; - if (rawDistance === 0) return "射箭无效,未识别到靶纸"; - if (rawDistance / 100 < 5) return "射箭无效,距离不足"; + const finiteDistance = Number.isFinite(rawDistance) ? rawDistance : 0; + const targetFlag = shootData.targetOk ?? shootData.target_ok; + const targetDetected = finiteDistance !== 0; + const targetOk = finiteDistance > 0 && targetFlag === true; + + return { + rawDistance: finiteDistance, + distance: Math.max(0, finiteDistance / 100), + // 旧固件以负距离表示靶纸错误,此时只提示靶纸问题,不叠加距离不足。 + distanceOk: finiteDistance < 0 || finiteDistance >= 500, + targetOk: targetDetected && targetOk, + targetDetected, + }; +}; + +// 测距阶段提示音:同时校验站距和靶纸,保留旧版本距离不足音频。 +export const getDistanceCheckAudioKey = (shootData) => { + const result = getShootValidation(shootData); + if (!result.targetDetected) return "未发现靶纸,请瞄准靶纸射箭"; + if (!result.distanceOk && !result.targetOk) { + return "射箭无效,距离不足且靶纸错误"; + } + if (!result.targetOk) return "靶纸不符!请更换靶纸"; + if (result.distanceOk) return "站距与靶纸合格"; + return "距离不足"; +}; + +export const getDistanceCheckText = (shootData) => { + const result = getShootValidation(shootData); + if (!result.targetDetected) return "未识别到靶纸,请瞄准靶纸射箭"; + if (result.rawDistance < 0) return "靶纸错误"; + return `${result.distanceOk ? "站距合格" : "站距过近"},${ + result.targetOk ? "靶纸正确" : "靶纸错误" + }`; +}; + +// 正式射箭阶段的距离和靶纸异常类型选择对应语音。 +export const getInvalidShotAudioKey = (shootData) => { + const result = getShootValidation(shootData); + if (!result.targetDetected) return "射箭无效,未识别到靶纸"; + if (!result.distanceOk && !result.targetOk) { + return "射箭无效,距离不足且靶纸错误"; + } + if (!result.targetOk) return "射箭无效,靶纸错误"; + if (!result.distanceOk) return "射箭无效,距离不足"; return "射击无效"; }; +export const getInvalidShotText = (shootData) => + getInvalidShotAudioKey(shootData); + export const wxLogin = () => { return new Promise((resolve, reject) => { uni.login({ diff --git a/src/utils/match.min.js b/src/utils/match.min.js index 87f6493..b0a391e 100644 --- a/src/utils/match.min.js +++ b/src/utils/match.min.js @@ -1,4 +1,4 @@ /* eslint-disable */ import * as $protobuf from "protobufjs"; -const $root=$protobuf.Root.create({"nested":{"rpc":{"ServerMessageType":{"SERVER_MSG_UNKNOWN":0,"SERVER_MSG_MATCH_READY":1,"SERVER_MSG_MATCH_START":2,"SERVER_MSG_NOW_YOU":3,"SERVER_MSG_SHOT":4,"SERVER_MSG_NEW_ROUND":5,"SERVER_MSG_MATCH_END":6,"SERVER_MSG_TIMEOUT":7,"SERVER_MSG_CHECK":8,"SERVER_MSG_RAND":9,"SERVER_MSG_NOT_ENOUGH_DISTANCE":10,"SERVER_MSG_PLAYER_LEFT":11,"SERVER_MSG_HEARTBEAT":12,"SERVER_MSG_PRACTICE_END":13,"SERVER_MSG_SYNC_PRACTICE_INFO":14,"SERVER_MSG_SYNC_MATCH_INFO":15},"ClientMessageType":{"CLIENT_MSG_UNKNOWN":0,"CLIENT_MSG_HEARTBEAT_ACK":1,"CLIENT_MSG_SHOOT_DATA":2,"CLIENT_MSG_ACK":3,"CLIENT_MSG_LEAVE":4,"CLIENT_MSG_SYNC_PRACTICE_INFO":5,"CLIENT_MSG_SYNC_MATCH_INFO":6},"MatchStatus":{"MATCH_STATUS_READY":0,"MATCH_STATUS_STARTED":1,"MATCH_STATUS_END":2,"MATCH_STATUS_TIMEOUT":3,"MATCH_STATUS_UNEXPECTEDLY":4},"MatchPlayerStatus":{"MATCH_PLAYER_STATUS_READY":0,"MATCH_PLAYER_STATUS_STARTED":1,"MATCH_PLAYER_STATUS_END":2},"MatchShoot":{"fields":{"player_id":{"type":"int64","id":1},"status":{"type":"int32","id":2},"x":{"type":"float","id":3},"y":{"type":"float","id":4},"ring":{"type":"int32","id":5},"ring_x":{"type":"bool","id":6},"angle":{"type":"float","id":7},"distance":{"type":"float","id":8},"three_consecutive_10_rings":{"type":"bool","id":9},"ok":{"type":"bool","id":10}}},"MatchShootList":{"fields":{"items":{"type":"MatchShoot","id":1,"rule":"repeated"}}},"RoundScore":{"fields":{"total_ring":{"type":"int32","id":1},"score":{"type":"int32","id":2},"if_win":{"type":"bool","id":3}}},"MatchRound":{"fields":{"shoots":{"type":"MatchShootList","id":1,"keytype":"int64"},"scores":{"type":"RoundScore","id":2,"keytype":"int32"},"round":{"type":"int32","id":3},"if_gold":{"type":"bool","id":4},"status":{"type":"int32","id":5},"gold_round":{"type":"int32","id":6}}},"PlayerMatchResult":{"fields":{"total_ring":{"type":"int32","id":1},"user_id":{"type":"int64","id":2},"ten_ring_count":{"type":"int32","id":3},"average_ring":{"type":"float","id":4}}},"PlayerFull":{"fields":{"id":{"type":"int64","id":1},"name":{"type":"string","id":2},"avatar":{"type":"string","id":3},"exp":{"type":"int32","id":4},"score":{"type":"int32","id":5},"level":{"type":"int32","id":6},"before_level":{"type":"int32","id":7},"before_exp":{"type":"int32","id":8},"current_exp":{"type":"int32","id":9},"upgrade_exp":{"type":"int32","id":10},"active":{"type":"int32","id":11},"device_id":{"type":"string","id":12},"s_vip":{"type":"bool","id":13},"vip":{"type":"bool","id":14},"player_match_result":{"type":"PlayerMatchResult","id":15},"rank_lvl":{"type":"int32","id":16},"rank_name":{"type":"string","id":17},"rank_icon":{"type":"string","id":18}}},"TeamInfo":{"fields":{"players":{"type":"PlayerFull","id":1,"rule":"repeated"},"id":{"type":"int32","id":2},"name":{"type":"string","id":3},"score":{"type":"int32","id":4}}},"CurrentShoot":{"fields":{"round":{"type":"int32","id":1},"round_id":{"type":"int64","id":2},"index":{"type":"int32","id":3},"start_time":{"type":"int64","id":4},"player_id":{"type":"int64","id":5},"gold_round":{"type":"bool","id":6},"start_time_text":{"type":"string","id":7},"my_index":{"type":"int32","id":8},"index_map":{"type":"int32","id":9,"keytype":"int64"},"ack_time":{"type":"int64","id":10}}},"ShootData":{"fields":{"x":{"type":"float","id":1},"y":{"type":"float","id":2},"r":{"type":"float","id":3},"dst":{"type":"float","id":4},"m":{"type":"string","id":5},"adc":{"type":"float","id":6},"device_id":{"type":"string","id":7},"shoot_id":{"type":"string","id":8},"three_consecutive_10_rings":{"type":"bool","id":9}}},"PracticeInfo":{"fields":{"id":{"type":"int64","id":1},"user_id":{"type":"int64","id":2},"status":{"type":"int32","id":3},"status_text":{"type":"string","id":4},"start_time":{"type":"int64","id":5},"target_type":{"type":"int32","id":6},"vip":{"type":"bool","id":7},"s_vip":{"type":"bool","id":8},"device_id":{"type":"string","id":9},"shoot_data":{"type":"MatchShoot","id":10},"details":{"type":"MatchShoot","id":11,"rule":"repeated"},"training_type":{"type":"string","id":12},"difficulty_level":{"type":"int32","id":13},"hit_req":{"type":"int32","id":14},"arrows_left":{"type":"int32","id":15},"target_arrows":{"type":"int32","id":16},"target_rings":{"type":"int32","id":17},"current_arrows":{"type":"int32","id":18},"current_rings":{"type":"int32","id":19},"blocks":{"type":"int32","id":20},"random_block":{"type":"int32","id":21},"random_ring_area":{"type":"int32","id":22},"score_slot":{"type":"int32","id":44},"current_energy":{"type":"int32","id":45},"energy_cost_per_sec":{"type":"int32","id":46},"energy_per_hit":{"type":"int32","id":47},"energy_req_percent":{"type":"int32","id":48},"round_time":{"type":"int32","id":50},"shoot_time":{"type":"int32","id":53},"shoot_window_start":{"type":"int64","id":51},"in_shoot_window":{"type":"bool","id":52},"time_limit":{"type":"int32","id":23},"completed":{"type":"bool","id":24},"total_arrows":{"type":"int32","id":25},"duration":{"type":"int32","id":26},"average_ring":{"type":"float","id":27},"stability":{"type":"float","id":28},"max_combo":{"type":"int32","id":29},"total_hits":{"type":"int32","id":30},"delta_total_hits":{"type":"int32","id":31},"delta_duration":{"type":"int32","id":32},"delta_max_combo":{"type":"int32","id":33},"delta_total_rings":{"type":"int32","id":34},"delta_total_arrows":{"type":"int32","id":35},"delta_average_ring":{"type":"float","id":36},"delta_stability":{"type":"float","id":37},"delta_current_energy":{"type":"int32","id":49},"before_exp":{"type":"int32","id":38},"before_level":{"type":"int32","id":39},"current_exp":{"type":"int32","id":40},"level":{"type":"int32","id":41},"upgrade_exp":{"type":"int32","id":42},"calories":{"type":"double","id":43}}},"MatchInfo":{"fields":{"match_id":{"type":"string","id":1},"create_time":{"type":"int64","id":2},"start_time":{"type":"int64","id":3},"server_time":{"type":"int64","id":4},"shoot_time":{"type":"int32","id":5},"shoot_number":{"type":"int32","id":6},"ready_time":{"type":"int32","id":7},"way":{"type":"int32","id":8},"mode":{"type":"int32","id":9},"status":{"type":"MatchStatus","id":10},"status_text":{"type":"string","id":11},"rounds":{"type":"MatchRound","id":12,"rule":"repeated"},"teams":{"type":"TeamInfo","id":13,"keytype":"int32"},"current":{"type":"CurrentShoot","id":14},"next":{"type":"CurrentShoot","id":15},"shoot_data":{"type":"MatchShoot","id":16},"win_team":{"type":"int32","id":17},"mvp":{"type":"PlayerFull","id":18},"room_id":{"type":"string","id":19},"result_list":{"type":"PlayerMatchResult","id":20,"rule":"repeated"},"timeout_time":{"type":"int64","id":21},"target_type":{"type":"int32","id":22},"event_type":{"type":"int32","id":23},"timeout":{"type":"int32","id":24},"server_addr":{"type":"string","id":25},"countdown_start_time":{"type":"int64","id":26}}},"ServerMessage":{"fields":{"type":{"type":"ServerMessageType","id":1},"match_id":{"type":"string","id":2},"timestamp":{"type":"int64","id":3},"match_info":{"type":"MatchInfo","id":4},"shoot_data":{"type":"ShootData","id":5},"practice_info":{"type":"PracticeInfo","id":6},"sequence":{"type":"int64","id":7}}},"ClientMessage":{"fields":{"type":{"type":"ClientMessageType","id":1},"match_id":{"type":"string","id":2},"user_id":{"type":"int64","id":3},"sequence":{"type":"int64","id":4},"data":{"type":"bytes","id":5}}}}}}); +const $root=$protobuf.Root.create({"nested":{"rpc":{"ServerMessageType":{"SERVER_MSG_UNKNOWN":0,"SERVER_MSG_MATCH_READY":1,"SERVER_MSG_MATCH_START":2,"SERVER_MSG_NOW_YOU":3,"SERVER_MSG_SHOT":4,"SERVER_MSG_NEW_ROUND":5,"SERVER_MSG_MATCH_END":6,"SERVER_MSG_TIMEOUT":7,"SERVER_MSG_CHECK":8,"SERVER_MSG_RAND":9,"SERVER_MSG_NOT_ENOUGH_DISTANCE":10,"SERVER_MSG_PLAYER_LEFT":11,"SERVER_MSG_HEARTBEAT":12,"SERVER_MSG_PRACTICE_END":13,"SERVER_MSG_SYNC_PRACTICE_INFO":14,"SERVER_MSG_SYNC_MATCH_INFO":15},"ClientMessageType":{"CLIENT_MSG_UNKNOWN":0,"CLIENT_MSG_HEARTBEAT_ACK":1,"CLIENT_MSG_SHOOT_DATA":2,"CLIENT_MSG_ACK":3,"CLIENT_MSG_LEAVE":4,"CLIENT_MSG_SYNC_PRACTICE_INFO":5,"CLIENT_MSG_SYNC_MATCH_INFO":6},"MatchStatus":{"MATCH_STATUS_READY":0,"MATCH_STATUS_STARTED":1,"MATCH_STATUS_END":2,"MATCH_STATUS_TIMEOUT":3,"MATCH_STATUS_UNEXPECTEDLY":4},"MatchPlayerStatus":{"MATCH_PLAYER_STATUS_READY":0,"MATCH_PLAYER_STATUS_STARTED":1,"MATCH_PLAYER_STATUS_END":2},"MatchShoot":{"fields":{"player_id":{"type":"int64","id":1},"status":{"type":"int32","id":2},"x":{"type":"float","id":3},"y":{"type":"float","id":4},"ring":{"type":"int32","id":5},"ring_x":{"type":"bool","id":6},"angle":{"type":"float","id":7},"distance":{"type":"float","id":8},"three_consecutive_10_rings":{"type":"bool","id":9},"ok":{"type":"bool","id":10},"target_ok":{"type":"bool","id":11}}},"MatchShootList":{"fields":{"items":{"type":"MatchShoot","id":1,"rule":"repeated"}}},"RoundScore":{"fields":{"total_ring":{"type":"int32","id":1},"score":{"type":"int32","id":2},"if_win":{"type":"bool","id":3}}},"MatchRound":{"fields":{"shoots":{"type":"MatchShootList","id":1,"keytype":"int64"},"scores":{"type":"RoundScore","id":2,"keytype":"int32"},"round":{"type":"int32","id":3},"if_gold":{"type":"bool","id":4},"status":{"type":"int32","id":5},"gold_round":{"type":"int32","id":6}}},"PlayerMatchResult":{"fields":{"total_ring":{"type":"int32","id":1},"user_id":{"type":"int64","id":2},"ten_ring_count":{"type":"int32","id":3},"average_ring":{"type":"float","id":4}}},"PlayerFull":{"fields":{"id":{"type":"int64","id":1},"name":{"type":"string","id":2},"avatar":{"type":"string","id":3},"exp":{"type":"int32","id":4},"score":{"type":"int32","id":5},"level":{"type":"int32","id":6},"before_level":{"type":"int32","id":7},"before_exp":{"type":"int32","id":8},"current_exp":{"type":"int32","id":9},"upgrade_exp":{"type":"int32","id":10},"active":{"type":"int32","id":11},"device_id":{"type":"string","id":12},"s_vip":{"type":"bool","id":13},"vip":{"type":"bool","id":14},"player_match_result":{"type":"PlayerMatchResult","id":15},"rank_lvl":{"type":"int32","id":16},"rank_name":{"type":"string","id":17},"rank_icon":{"type":"string","id":18}}},"TeamInfo":{"fields":{"players":{"type":"PlayerFull","id":1,"rule":"repeated"},"id":{"type":"int32","id":2},"name":{"type":"string","id":3},"score":{"type":"int32","id":4}}},"CurrentShoot":{"fields":{"round":{"type":"int32","id":1},"round_id":{"type":"int64","id":2},"index":{"type":"int32","id":3},"start_time":{"type":"int64","id":4},"player_id":{"type":"int64","id":5},"gold_round":{"type":"bool","id":6},"start_time_text":{"type":"string","id":7},"my_index":{"type":"int32","id":8},"index_map":{"type":"int32","id":9,"keytype":"int64"},"ack_time":{"type":"int64","id":10}}},"ShootData":{"fields":{"x":{"type":"float","id":1},"y":{"type":"float","id":2},"r":{"type":"float","id":3},"dst":{"type":"float","id":4},"m":{"type":"string","id":5},"adc":{"type":"float","id":6},"device_id":{"type":"string","id":7},"shoot_id":{"type":"string","id":8},"three_consecutive_10_rings":{"type":"bool","id":9},"target_ok":{"type":"bool","id":10}}},"PracticeInfo":{"fields":{"id":{"type":"int64","id":1},"user_id":{"type":"int64","id":2},"status":{"type":"int32","id":3},"status_text":{"type":"string","id":4},"start_time":{"type":"int64","id":5},"target_type":{"type":"int32","id":6},"vip":{"type":"bool","id":7},"s_vip":{"type":"bool","id":8},"device_id":{"type":"string","id":9},"shoot_data":{"type":"MatchShoot","id":10},"details":{"type":"MatchShoot","id":11,"rule":"repeated"},"training_type":{"type":"string","id":12},"difficulty_level":{"type":"int32","id":13},"hit_req":{"type":"int32","id":14},"arrows_left":{"type":"int32","id":15},"target_arrows":{"type":"int32","id":16},"target_rings":{"type":"int32","id":17},"current_arrows":{"type":"int32","id":18},"current_rings":{"type":"int32","id":19},"blocks":{"type":"int32","id":20},"random_block":{"type":"int32","id":21},"random_ring_area":{"type":"int32","id":22},"score_slot":{"type":"int32","id":44},"current_energy":{"type":"int32","id":45},"energy_cost_per_sec":{"type":"int32","id":46},"energy_per_hit":{"type":"int32","id":47},"energy_req_percent":{"type":"int32","id":48},"round_time":{"type":"int32","id":50},"shoot_time":{"type":"int32","id":53},"shoot_window_start":{"type":"int64","id":51},"in_shoot_window":{"type":"bool","id":52},"time_limit":{"type":"int32","id":23},"completed":{"type":"bool","id":24},"total_arrows":{"type":"int32","id":25},"duration":{"type":"int32","id":26},"average_ring":{"type":"float","id":27},"stability":{"type":"float","id":28},"max_combo":{"type":"int32","id":29},"total_hits":{"type":"int32","id":30},"delta_total_hits":{"type":"int32","id":31},"delta_duration":{"type":"int32","id":32},"delta_max_combo":{"type":"int32","id":33},"delta_total_rings":{"type":"int32","id":34},"delta_total_arrows":{"type":"int32","id":35},"delta_average_ring":{"type":"float","id":36},"delta_stability":{"type":"float","id":37},"delta_current_energy":{"type":"int32","id":49},"before_exp":{"type":"int32","id":38},"before_level":{"type":"int32","id":39},"current_exp":{"type":"int32","id":40},"level":{"type":"int32","id":41},"upgrade_exp":{"type":"int32","id":42},"calories":{"type":"double","id":43}}},"MatchInfo":{"fields":{"match_id":{"type":"string","id":1},"create_time":{"type":"int64","id":2},"start_time":{"type":"int64","id":3},"server_time":{"type":"int64","id":4},"shoot_time":{"type":"int32","id":5},"shoot_number":{"type":"int32","id":6},"ready_time":{"type":"int32","id":7},"way":{"type":"int32","id":8},"mode":{"type":"int32","id":9},"status":{"type":"MatchStatus","id":10},"status_text":{"type":"string","id":11},"rounds":{"type":"MatchRound","id":12,"rule":"repeated"},"teams":{"type":"TeamInfo","id":13,"keytype":"int32"},"current":{"type":"CurrentShoot","id":14},"next":{"type":"CurrentShoot","id":15},"shoot_data":{"type":"MatchShoot","id":16},"win_team":{"type":"int32","id":17},"mvp":{"type":"PlayerFull","id":18},"room_id":{"type":"string","id":19},"result_list":{"type":"PlayerMatchResult","id":20,"rule":"repeated"},"timeout_time":{"type":"int64","id":21},"target_type":{"type":"int32","id":22},"event_type":{"type":"int32","id":23},"timeout":{"type":"int32","id":24},"server_addr":{"type":"string","id":25},"countdown_start_time":{"type":"int64","id":26}}},"ServerMessage":{"fields":{"type":{"type":"ServerMessageType","id":1},"match_id":{"type":"string","id":2},"timestamp":{"type":"int64","id":3},"match_info":{"type":"MatchInfo","id":4},"shoot_data":{"type":"ShootData","id":5},"practice_info":{"type":"PracticeInfo","id":6},"sequence":{"type":"int64","id":7}}},"ClientMessage":{"fields":{"type":{"type":"ClientMessageType","id":1},"match_id":{"type":"string","id":2},"user_id":{"type":"int64","id":3},"sequence":{"type":"int64","id":4},"data":{"type":"bytes","id":5}}}}}}); export default $root; diff --git a/src/utils/matchProtocol.js b/src/utils/matchProtocol.js index 68fadfb..1b36c67 100644 --- a/src/utils/matchProtocol.js +++ b/src/utils/matchProtocol.js @@ -7,8 +7,8 @@ const { Reader, Writer } = protobuf; // 所以这里使用 minimal Reader/Writer 做静态字段解码和客户端消息编码。 // // 此区块由 scripts/generate-match-schema.mjs 自动生成,请勿手动修改。 -// 来源:src/utils/match.min.js(sha256: 150812589c2e6f7a) -// 协议命名空间:rpc;消息数:12;字段数:151 +// 来源:src/utils/match.min.js(sha256: a7ab92ae43e405e7) +// 协议命名空间:rpc;消息数:12;字段数:153 export const ServerMessageType = { SERVER_MSG_UNKNOWN: 0, @@ -51,6 +51,7 @@ const SCHEMAS = { 8: { name: "distance", kind: "float" }, 9: { name: "three_consecutive_10_rings", kind: "bool" }, 10: { name: "ok", kind: "bool" }, + 11: { name: "target_ok", kind: "bool" }, }, MatchShootList: { 1: { name: "items", kind: "message", type: "MatchShoot", repeated: true }, @@ -139,6 +140,7 @@ const SCHEMAS = { 7: { name: "device_id", kind: "string" }, 8: { name: "shoot_id", kind: "string" }, 9: { name: "three_consecutive_10_rings", kind: "bool" }, + 10: { name: "target_ok", kind: "bool" }, }, PracticeInfo: { 1: { name: "id", kind: "int64" },