diff --git a/assets/scripts/login/loginPanel.ts b/assets/scripts/login/loginPanel.ts index b1f58d4..e9df5cf 100644 --- a/assets/scripts/login/loginPanel.ts +++ b/assets/scripts/login/loginPanel.ts @@ -1,9 +1,8 @@ import { _decorator, Button, Component, EditBox, Label, Node } from 'cc' import { WsClient } from '../network/wsclient' import { WsConfig } from '../network/wsconfig' -import { PbHelper } from '../network/pbHelper' -import { ReqUserLogin, ServiceTypeId, MsgId, RspUserLogin } from '../network/pbExport' -import { EventType } from '../constant' +import * as pb from '../network/pbExport' +import { MessageDispatcher } from '../network/messageDispatcher' const { ccclass, property } = _decorator @ccclass('loginPanel') @@ -21,11 +20,11 @@ export class loginPanel extends Component { start() { this.loginButton.node.on(Button.EventType.CLICK, this.onLoginButtonClick, this) // 监听websocket消息事件 - window.addEventListener(EventType.Ws, this.onMessage.bind(this)) + MessageDispatcher.Instance.On(pb.MsgId.RspUserLoginId, this.onLogin.bind(this)) } protected onDestroy(): void { - window.removeEventListener(EventType.Ws, this.onMessage.bind(this)) + MessageDispatcher.Instance.Off(pb.MsgId.RspUserLoginId, this.onLogin.bind(this)) } // 登录按钮点击处理函数 @@ -40,40 +39,30 @@ export class loginPanel extends Component { this.statusLable.string = '请输入密码' return } - const ws = WsClient.Instance() + const ws = WsClient.Instance console.log(typeof ws) - if (!ws.IsConnected) { - await ws.ConnectAsync(WsConfig.Address[1].Address[0]) - if (!ws.IsConnected) { + if (!WsClient.Instance.IsConnected) { + await WsClient.Instance.ConnectAsync(WsConfig.Address[1].Address[0]) + if (!WsClient.Instance.IsConnected) { this.statusLable.string = '连接网络失败' return } } - - console.log('登陆帐号:', username, '密码:', pwd) - - const req = new ReqUserLogin() - req.username = username - req.password = pwd - req.version = '20250601123030' - const buffer = ReqUserLogin.encode(req).finish() - ws.Send(ServiceTypeId.STI_Login, MsgId.ReqUserLoginId, buffer) + // console.log('登陆帐号:', username, '密码:', pwd) + this.reqLogin(username, pwd) } - private onMessage(event: CustomEvent) { - try { - const [msgid, buffer] = PbHelper.DecodeClient(event.detail) - switch (msgid) { - case MsgId.RspUserLoginId: - const rsp = PbHelper.Decode(RspUserLogin, buffer) - console.log('收到返回消息:', rsp) - default: - // console.log('收到非json消息:', event.detail) - } - } catch (error) { - // console.log('解析错误失败:', error) - console.log(PbHelper.Uint8ToHex(event.detail)) - } + private reqLogin(username, password: string) { + const req = new pb.ReqUserLogin() + req.username = username + req.password = password + req.version = '20250601123030' + const buffer = pb.ReqUserLogin.encode(req).finish() + WsClient.Instance.Send(pb.ServiceTypeId.STI_Login, pb.MsgId.ReqUserLoginId, buffer) + } + + private onLogin(rsp: typeof pb.RspUserLogin.prototype) { + console.log('收到返回消息:', rsp) } update(deltaTime: number) {} diff --git a/assets/scripts/network/messageDecoder.ts b/assets/scripts/network/messageDecoder.ts new file mode 100644 index 0000000..dc832ce --- /dev/null +++ b/assets/scripts/network/messageDecoder.ts @@ -0,0 +1,50 @@ +// MessageDecoder.ts +import * as pb from './pbExport' + +export class MessageDecoder { + // 消息ID与消息类的映射表 + private static _messageClasses: Map any> = new Map() + + /** + * 注册消息类(启动时调用) + * @param msgId 消息ID + * @param decoder 解码函数(如 pb.ReqUserLogin.decode) + */ + public static Register(msgId: number, decoder: (buffer: Uint8Array) => T): void { + this._messageClasses.set(msgId, decoder) + } + + /** + * 解码消息(根据ID动态实例化对应消息类) + * @param msgId 消息ID + * @param buffer 原始消息(Uint8Array) + * @returns 解码后的消息对象 + */ + public static Decode(msgId: number, buffer: Uint8Array): [any, Error] { + try { + const decoder = this._messageClasses.get(msgId) + if (!decoder) { + return [null, new Error(`未注册的消息ID: ${msgId}`)] + } + // 实例化消息类并解码数据 + const instance = decoder(buffer) + return [instance, null] + } catch (err) { + return [null, new Error(`解消息: ${msgId} 失败。err:${err}`)] + } + } + + /** + * 字节流转换成Hex码 + * @param buffer 原始消息(Uint8Array) + * @returns 字节流转换成Hex码 + */ + public static Uint8ToHex(buffer: Uint8Array): string { + return Array.from(buffer) + .map((byte) => byte.toString(16).padStart(2, '0')) + .join(' ') + } +} + +MessageDecoder.Register(pb.MsgId.ReqUserLoginId, pb.ReqUserLogin.decode) +MessageDecoder.Register(pb.MsgId.RspUserLoginId, pb.RspUserLogin.decode) diff --git a/assets/scripts/network/messageDispatcher.ts b/assets/scripts/network/messageDispatcher.ts new file mode 100644 index 0000000..1436613 --- /dev/null +++ b/assets/scripts/network/messageDispatcher.ts @@ -0,0 +1,71 @@ +// MessageDispatcher.ts + +/**​ 消息处理器类型 */ +export type MessageHandler = (data: any) => void + +export class MessageDispatcher { + private static _instance: MessageDispatcher + private _handlers: Map = new Map() + + /**​ 单例模式 */ + public static get Instance(): MessageDispatcher { + if (!this._instance) { + this._instance = new MessageDispatcher() + } + return this._instance + } + + /** + * 注册消息处理器(允许多个 Handler) + * @param msgId 消息ID + * @param handler 回调函数 + */ + public On(msgId: number, handler: MessageHandler): void { + if (!this._handlers.has(msgId)) { + this._handlers.set(msgId, []) + } + this._handlers.get(msgId)?.push(handler) // 添加到队列 + } + + /** + * 移除指定的消息处理器(通过函数引用精准匹配) + * @param msgId 消息ID + * @param handler 要移除的回调函数 + */ + public Off(msgId: number, handler: MessageHandler): void { + const handlers = this._handlers.get(msgId) + if (!handlers) return + + // 过滤掉指定的 handler + const newHandlers = handlers.filter((h) => h !== handler) + this._handlers.set(msgId, newHandlers) + } + + /** + * 消息派发器中handler数量 + * @param msgId 消息ID + * @returns 返回消息派发器中handler数量 + */ + public Size(msgId: number): number { + if (msgId === 0) { + return this._handlers.size + } + const handlers = this._handlers.get(msgId) + if (handlers) { + return handlers.length + } + return 0 + } + + /** + * 派发消息(按注册顺序执行所有 Handler) + * @param msgId 消息ID + * @param msg 消息数据 + */ + public Dispatch(msgId: number, msg: any): void { + const handlers = this._handlers.get(msgId) + if (handlers) { + handlers.forEach((handler) => handler(msg)) // 顺序执行 + } + } +} diff --git a/assets/scripts/network/wsclient.ts b/assets/scripts/network/wsclient.ts index 8e7dad2..64024d8 100644 --- a/assets/scripts/network/wsclient.ts +++ b/assets/scripts/network/wsclient.ts @@ -1,6 +1,6 @@ import { ClientMsg } from '../network/pbExport' -import { EventType } from '../constant' -import { PbHelper } from '../network/pbHelper' +import { MessageDispatcher } from '../network/messageDispatcher' +import { MessageDecoder } from '../network/messageDecoder' export class WsClient { private socket: WebSocket | null = null @@ -11,13 +11,20 @@ export class WsClient { private isConnected: boolean = false private static instance: WsClient = null + private static netEvent: EventTarget = null // 单例 - public static Instance(): WsClient { + public static get Instance(): WsClient { if (!this.instance) this.instance = new WsClient() return this.instance } + // 网络事件中心 + public static EventMgr(): EventTarget { + if (!this.netEvent) this.netEvent = new EventTarget() + return this.netEvent + } + // 是否连接 public get IsConnected(): boolean { return this.isConnected @@ -112,8 +119,14 @@ export class WsClient { const buffer = await event.data.arrayBuffer() const uint8Array = new Uint8Array(buffer) // console.log('收到消息:', uint8Array) - console.log('收到消息:', PbHelper.Uint8ToHex(uint8Array)) - window.dispatchEvent(new CustomEvent(EventType.Ws, { detail: uint8Array })) + const cMsg = ClientMsg.decode(uint8Array) + // console.log('收到消息:', MessageDecoder.Uint8ToHex(uint8Array)) + const [msg, err] = MessageDecoder.Decode(cMsg.msgId, cMsg.data) + if (err) { + console.error(err) + return + } + MessageDispatcher.Instance.Dispatch(cMsg.msgId, msg) } catch (error) { console.error('解析网络消息失败:', error) }