Compare commits

..

3 Commits

Author SHA1 Message Date
f0de649733 工作记录 2025-07-09 23:22:35 +08:00
c2901b2e37 优化消息注册,消息派发,消息事件注册 2025-07-09 23:21:34 +08:00
787ac75484 README 2025-07-08 23:36:42 +08:00
5 changed files with 162 additions and 38 deletions

View File

@ -8,6 +8,7 @@
2. 登陆界面
1. 连接网关并实现登陆功能。(已完成)
2. 编写单独的消息解码器,派发消息时是已解码的消息。
2. 编写单独的消息解码器,派发消息时是已解码的消息。(已完成)
3. 登陆成功后关闭登陆界面,进入大厅界面。
4. 网络断开时弹出转圈圈界面。
5. ai 生成更宽一点的登陆界面,以及登陆注册 ui转圈圈图标。

View File

@ -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) {}

View File

@ -0,0 +1,50 @@
// MessageDecoder.ts
import * as pb from './pbExport'
export class MessageDecoder {
// 消息ID与消息类的映射表
private static _messageClasses: Map<number, (buffer: Uint8Array) => any> = new Map()
/**
*
* @param msgId ID
* @param decoder pb.ReqUserLogin.decode
*/
public static Register<T>(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)

View File

@ -0,0 +1,71 @@
// MessageDispatcher.ts
/** 消息处理器类型 */
export type MessageHandler = (data: any) => void
export class MessageDispatcher {
private static _instance: MessageDispatcher
private _handlers: Map<number, MessageHandler[]> = 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)) // 顺序执行
}
}
}

View File

@ -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)
}