update:新增比赛服链接
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import matchRoot from "./match.min.js";
|
||||
|
||||
// 比赛服 protobuf 协议适配层:
|
||||
// 这里只负责 raw protobuf frame 的解码和客户端消息编码,不处理 UI 状态。
|
||||
const ServerMessage = matchRoot.lookupType("rpc.ServerMessage");
|
||||
const ClientMessage = matchRoot.lookupType("rpc.ClientMessage");
|
||||
|
||||
// 从反射 Root 中读取枚举,避免直接依赖生成文件内部结构。
|
||||
function getEnumValues(name) {
|
||||
return matchRoot.lookupEnum(name).values || {};
|
||||
}
|
||||
|
||||
// protobufjs 的 enum 默认是 name -> value,这里反转成 value -> name 用于日志打印。
|
||||
function invertEnum(values) {
|
||||
return Object.keys(values).reduce((result, name) => {
|
||||
result[values[name]] = name;
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export const ServerMessageType = getEnumValues("rpc.ServerMessageType");
|
||||
export const ClientMessageType = getEnumValues("rpc.ClientMessageType");
|
||||
|
||||
const ServerMessageTypeNameByValue = invertEnum(ServerMessageType);
|
||||
|
||||
// 统一把 int64 转成字符串,避免小程序环境下大整数精度丢失。
|
||||
const TO_OBJECT_OPTIONS = {
|
||||
longs: String,
|
||||
enums: Number,
|
||||
bytes: Array,
|
||||
oneofs: true,
|
||||
};
|
||||
|
||||
// 小程序 websocket 收到的 data 可能是 ArrayBuffer、TypedArray 或字符串,这里统一成 Uint8Array。
|
||||
function toUint8Array(data) {
|
||||
if (data instanceof Uint8Array) return data;
|
||||
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
||||
}
|
||||
if (typeof data === "string") {
|
||||
const bytes = new Uint8Array(data.length);
|
||||
for (let i = 0; i < data.length; i += 1) {
|
||||
bytes[i] = data.charCodeAt(i) & 0xff;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
throw new TypeError("Unsupported match websocket message payload");
|
||||
}
|
||||
|
||||
// uni.sendSocketMessage 发送二进制时使用 ArrayBuffer。
|
||||
function toArrayBuffer(bytes) {
|
||||
const output = new Uint8Array(bytes.length);
|
||||
output.set(bytes);
|
||||
return output.buffer;
|
||||
}
|
||||
|
||||
export function decodeServerMessage(data) {
|
||||
// 后端已确认比赛服 websocket 下发的是原始 protobuf frame,直接 ServerMessage.decode。
|
||||
const message = ServerMessage.decode(toUint8Array(data));
|
||||
return ServerMessage.toObject(message, TO_OBJECT_OPTIONS);
|
||||
}
|
||||
|
||||
export function encodeClientMessage(payload) {
|
||||
// ClientMessage 字段名按 proto 定义传入,例如 match_id、user_id。
|
||||
const message = ClientMessage.create(payload);
|
||||
return toArrayBuffer(ClientMessage.encode(message).finish());
|
||||
}
|
||||
|
||||
export function getServerMessageTypeName(type) {
|
||||
return ServerMessageTypeNameByValue[type] || String(type);
|
||||
}
|
||||
|
||||
export function createHeartbeatAckMessage() {
|
||||
// 心跳 ACK 按文档立即回,不等待语音播报。
|
||||
return encodeClientMessage({
|
||||
type: ClientMessageType.CLIENT_MSG_HEARTBEAT_ACK,
|
||||
});
|
||||
}
|
||||
|
||||
export function createAckMessage({ matchId, sequence }) {
|
||||
// 普通消息 ACK 仍携带 sequence,但前端不做 sequence 补发或排序。
|
||||
return encodeClientMessage({
|
||||
type: ClientMessageType.CLIENT_MSG_ACK,
|
||||
match_id: matchId,
|
||||
sequence,
|
||||
});
|
||||
}
|
||||
|
||||
export function createLeaveMessage({ matchId, userId }) {
|
||||
// 比赛结束或页面离开时通知比赛服释放当前玩家连接。
|
||||
return encodeClientMessage({
|
||||
type: ClientMessageType.CLIENT_MSG_LEAVE,
|
||||
match_id: matchId,
|
||||
user_id: userId,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user