cocos 使用 WebSocket(goEasy版)

先记录用 goEasy 的方案

卡了我三天气死了,手册啥也没有写

1 下载sdk

下载地址 https://docs.goeasy.io/2.x/pubsub/sdk/sdk_initial

2 这个大坑就是需要证书

证书去 他的官方示例里面找,去gitee里面找
https://gitee.com/goeasy-io/cocos

看一下我 文件路径

在这里插入图片描述

3 建立一个 控制文件(这个重新改了)
typescript 复制代码
// GoEasyManager.ts
import { log } from 'cc';
import GoEasy from './goeasy-lite.min.js';

// 声明全局 GoEasy 类型
declare global {
    interface Window {
        GoEasy: any;
        goEasy: any;
    }
}

// 导出用户状态枚举
export enum UserStatus {
    ONLINE = 'online',
    OFFLINE = 'offline',
    AWAY = 'away'
}

// 导出 Presence 事件类型
export interface PresenceEvent {
    action: 'join' | 'leave' | 'state-change';
    channel: string;
    clientId: string;
    data?: any;
    timestamp: number;
}

// 消息回调类型定义
export type MessageCallback = (content: any) => void;
export type PresenceCallback = (event: PresenceEvent) => void;

class GoEasyManager {
    private static _instance: GoEasyManager | null = null;
    
    // GoEasy 实例
    private goEasy: any = null;
    private GoEasyLib: any = null;
    
    // 连接状态
    private _isConnected: boolean = false;
    
    // 频道订阅信息
    private subscriptions: Map<string, Set<MessageCallback>> = new Map();
    
    // 用户状态管理
    private userId: string = "";
    private userData: any = {};
    private userStatus: UserStatus = UserStatus.ONLINE;
    
    // Presence 管理
    private presenceSubscriptions: Map<string, Set<PresenceCallback>> = new Map();
    private channelUsers: Map<string, Map<string, any>> = new Map();
    
    // 私有构造函数
    private constructor() {}
    
    /**
     * 获取单例实例
     */
    public static get instance(): GoEasyManager {
        if (!GoEasyManager._instance) {
            GoEasyManager._instance = new GoEasyManager();
        }
        return GoEasyManager._instance;
    }
    
    /**
     * 初始化 GoEasy 并自动连接
     * @param appKey 应用密钥
     * @param host 服务器地址 (默认为 hangzhou.goeasy.io)
     * @param userId 用户ID (可选)
     * @param userData 用户数据 (可选)
     */
    public init(appKey: string, host: string = "hangzhou.goeasy.io", userId?: string, userData: any = {}): void {
        if (this.goEasy) {
            log("GoEasy 已经初始化");
            return;
        }
        
        try {
            // 导入 GoEasy 库
            this.GoEasyLib = GoEasy;
            
            // 设置用户信息
            this.userId = userId || `u_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
            this.userData = userData;
            this.userStatus = UserStatus.ONLINE;
            
            // 初始化 GoEasy - 只使用 pubsub 模块
            this.goEasy = this.GoEasyLib.getInstance({
                host: host,
                appkey: appKey,
                modules: ['pubsub'] // 只使用 pubsub 模块
            });
            
            // 暴露到全局
            if (typeof window !== 'undefined') {
                window.GoEasy = this.GoEasyLib;
                window.goEasy = this.goEasy;
                
                // 添加页面关闭前的清理逻辑
                window.addEventListener('beforeunload', this.handleBeforeUnload.bind(this));
            }
            
            log("GoEasy初始化完成", this.GoEasyLib, this.goEasy);
            
            // 自动连接
            this.autoConnect();
        } catch (error) {
            log("GoEasy初始化失败", error);
            throw new Error("GoEasy初始化失败: " + error.message);
        }
    }
    
    // 页面关闭前的清理
    private handleBeforeUnload() {
        // 离开所有频道
        this.channelUsers.forEach((_, channel) => {
            this.leaveChannel(channel);
        });
    }
    
    /**
     * 自动连接服务器
     */
    private autoConnect(): void {
        if (!this.goEasy) {
            log("GoEasy未初始化");
            return;
        }
        
        if (this._isConnected) {
            log("GoEasy已连接");
            return;
        }
        
        log("GoEasy正在连接...");
        
        this.goEasy.connect({
            id: this.userId,
            data: this.userData,
            onSuccess: () => {
                log("GoEasy连接成功");
                this._isConnected = true;
                
                // 重新订阅所有频道
                this.resubscribeAll();
            },
            onFailed: (error: any) => {
                log("GoEasy连接失败", error);
            },
            onProgress: (attempts: number) => {
                log(`GoEasy连接中...尝试次数: ${attempts}`);
            }
        });
    }
    
    /**
     * 设置用户状态
     * @param status 用户状态
     */
    public setUserStatus(status: UserStatus): void {
        if (this.userStatus === status) return;
        
        this.userStatus = status;
        log(`用户状态变更为: ${status}`);
        
        // 广播状态变更
        this.broadcastPresenceEvent({
            action: 'state-change',
            channel: 'system',
            clientId: this.userId,
            data: { status: status, userData: this.userData },
            timestamp: Date.now()
        });
    }
    
    /**
     * 订阅频道
     * @param channel 频道名称
     * @param callback 消息回调
     */
    public subscribe(channel: string, callback: MessageCallback): void {
        if (!this.goEasy) {
            log("GoEasy未初始化");
            return;
        }
        
        // 添加到本地订阅列表
        if (!this.subscriptions.has(channel)) {
            this.subscriptions.set(channel, new Set());
        }
        this.subscriptions.get(channel)!.add(callback);
        
        // 初始化频道用户映射
        if (!this.channelUsers.has(channel)) {
            this.channelUsers.set(channel, new Map());
        }
        
        // 如果已连接,直接订阅
        if (this._isConnected) {
            this.doSubscribe(channel);
        } else {
            // 否则自动连接
            this.autoConnect();
        }
        
        // 通知加入频道
        this.handleUserJoin(channel);
    }
    
    /**
     * 取消订阅
     * @param channel 频道名称
     * @param callback 要移除的回调函数 (可选,不传则移除所有)
     */
    public unsubscribe(channel: string, callback?: MessageCallback): void {
        if (!this.subscriptions.has(channel)) return;
        
        const callbacks = this.subscriptions.get(channel)!;
        
        if (callback) {
            callbacks.delete(callback);
            if (callbacks.size === 0) {
                this.subscriptions.delete(channel);
                if (this._isConnected) {
                    this.doUnsubscribe(channel);
                }
            }
        } else {
            // 移除所有回调
            this.subscriptions.delete(channel);
            if (this._isConnected) {
                this.doUnsubscribe(channel);
            }
        }
        
        // 通知离开频道
        this.handleUserLeave(channel);
        
        // 如果频道没有订阅者了,清理用户数据
        if (!this.subscriptions.has(channel) && !this.presenceSubscriptions.has(channel)) {
            this.channelUsers.delete(channel);
        }
    }
    
    /**
     * 发布消息
     * @param channel 频道名称
     * @param message 消息内容 (对象会自动转为JSON字符串)
     */
    public publish(channel: string, message: any): void {
        if (!this.goEasy) {
            log("GoEasy未初始化");
            return;
        }
        
        if (!this._isConnected) {
            log("GoEasy未连接,尝试自动连接...");
            this.autoConnect();
            // 延迟发送消息
            setTimeout(() => this.publish(channel, message), 1000);
            return;
        }
        
        this.doPublish(channel, message);
    }
    
    /**
     * 加入频道 (上线)
     * @param channel 频道名称
     */
    public joinChannel(channel: string): void {
        if (!this.goEasy || !this._isConnected) {
            log("GoEasy未连接或未初始化");
            return;
        }
        
        // 初始化频道用户映射
        if (!this.channelUsers.has(channel)) {
            this.channelUsers.set(channel, new Map());
        }
        
        // 添加自己到频道用户列表
        this.channelUsers.get(channel)!.set(this.userId, {
            userId: this.userId,
            userData: this.userData,
            status: this.userStatus,
            lastActive: Date.now()
        });
        
        // 广播加入事件
        this.broadcastPresenceEvent({
            action: 'join',
            channel: channel,
            clientId: this.userId,
            data: this.channelUsers.get(channel)!.get(this.userId),
            timestamp: Date.now()
        });
    }
    
    /**
     * 离开频道 (下线)
     * @param channel 频道名称
     */
    public leaveChannel(channel: string): void {
        if (!this.goEasy || !this._isConnected) {
            log("GoEasy未连接或未初始化");
            return;
        }
        
        // 从频道用户列表中移除
        if (this.channelUsers.has(channel) && this.channelUsers.get(channel)!.has(this.userId)) {
            this.channelUsers.get(channel)!.delete(this.userId);
            
            // 广播离开事件
            this.broadcastPresenceEvent({
                action: 'leave',
                channel: channel,
                clientId: this.userId,
                data: { userId: this.userId },
                timestamp: Date.now()
            });
        }
    }
    
    /**
     * 订阅 Presence 事件
     * @param channel 频道名称
     * @param callback 事件回调
     */
    public subscribePresence(channel: string, callback: PresenceCallback): void {
        if (!this.goEasy) {
            log("GoEasy未初始化");
            return;
        }
        
        // 添加到本地订阅列表
        if (!this.presenceSubscriptions.has(channel)) {
            this.presenceSubscriptions.set(channel, new Set());
            // 初始化频道用户映射
            if (!this.channelUsers.has(channel)) {
                this.channelUsers.set(channel, new Map());
            }
        }
        this.presenceSubscriptions.get(channel)!.add(callback);
        
        // 如果已连接,直接订阅
        if (this._isConnected) {
            // 不需要额外订阅
        } else {
            // 否则自动连接
            this.autoConnect();
        }
        
        // 添加当前用户到频道
        if (!this.channelUsers.get(channel)!.has(this.userId)) {
            this.channelUsers.get(channel)!.set(this.userId, {
                userId: this.userId,
                userData: this.userData,
                status: this.userStatus,
                lastActive: Date.now()
            });
        }
        
        // 通知当前用户加入
        callback({
            action: 'join',
            channel: channel,
            clientId: this.userId,
            data: this.channelUsers.get(channel)!.get(this.userId),
            timestamp: Date.now()
        });
        
        // 通知所有其他用户有新用户加入
        this.broadcastPresenceEvent({
            action: 'join',
            channel: channel,
            clientId: this.userId,
            data: this.channelUsers.get(channel)!.get(this.userId),
            timestamp: Date.now()
        });
    }
    
    /**
     * 取消订阅 Presence 事件
     * @param channel 频道名称
     * @param callback 要移除的回调函数 (可选,不传则移除所有)
     */
    public unsubscribePresence(channel: string, callback?: PresenceCallback): void {
        if (!this.presenceSubscriptions.has(channel)) return;
        
        const callbacks = this.presenceSubscriptions.get(channel)!;
        
        if (callback) {
            callbacks.delete(callback);
            if (callbacks.size === 0) {
                this.presenceSubscriptions.delete(channel);
            }
        } else {
            // 移除所有回调
            this.presenceSubscriptions.delete(channel);
        }
        
        // 通知离开频道
        this.handleUserLeave(channel);
        
        // 如果频道没有订阅者了,清理用户数据
        if (!this.subscriptions.has(channel) && !this.presenceSubscriptions.has(channel)) {
            this.channelUsers.delete(channel);
        }
    }
    
    /**
     * 获取在线用户列表
     * @param channel 频道名称
     * @param callback 用户列表回调
     */
    public getOnlineUsers(channel: string, callback: (users: any[]) => void): void {
        if (!this.channelUsers.has(channel)) {
            callback([]);
            return;
        }
        
        const users = Array.from(this.channelUsers.get(channel)!.values());
        callback(users);
    }
    
    /**
     * 检查连接状态
     */
    public isConnected(): boolean {
        return this._isConnected;
    }
    
    /**
     * 实际执行订阅操作
     */
    private doSubscribe(channel: string): void {
        this.goEasy.pubsub.subscribe({
            channel: channel,
            onMessage: (message: any) => {
                try {
                    const content = JSON.parse(message.content);
                    
                    // 处理 Presence 事件
                    if (content && content.type === 'presence') {
                        this.handlePresenceEvent(content.event);
                        return;
                    }
                    
                    // 处理普通消息
                    const callbacks = this.subscriptions.get(channel);
                    if (callbacks) {
                        callbacks.forEach(cb => cb(content));
                    }
                } catch (e) {
                    log(`解析频道 ${channel} 的消息失败`, e);
                }
            },
            onSuccess: () => {
                log(`订阅频道 ${channel} 成功`);
            },
            onFailed: (error: any) => {
                log(`订阅频道 ${channel} 失败`, error);
            }
        });
    }
    
    /**
     * 实际执行取消订阅操作
     */
    private doUnsubscribe(channel: string): void {
        this.goEasy.pubsub.unsubscribe({
            channel: channel,
            onSuccess: () => {
                log(`取消订阅频道 ${channel} 成功`);
            },
            onFailed: (error: any) => {
                log(`取消订阅频道 ${channel} 失败`, error);
            }
        });
    }
    
    /**
     * 实际执行发布操作
     */
    private doPublish(channel: string, message: any): void {
        const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
        
        this.goEasy.pubsub.publish({
            channel: channel,
            message: messageStr,
            onSuccess: () => {
                log(`消息发布到频道 ${channel} 成功`);
            },
            onFailed: (error: any) => {
                log(`消息发布到频道 ${channel} 失败`, error);
            }
        });
    }
    
    /**
     * 处理用户加入频道
     */
    private handleUserJoin(channel: string): void {
        if (!this.channelUsers.has(channel)) {
            this.channelUsers.set(channel, new Map());
        }
        
        // 添加当前用户到频道
        this.channelUsers.get(channel)!.set(this.userId, {
            userId: this.userId,
            userData: this.userData,
            status: this.userStatus,
            lastActive: Date.now()
        });
        
        // 广播加入事件
        this.broadcastPresenceEvent({
            action: 'join',
            channel: channel,
            clientId: this.userId,
            data: this.channelUsers.get(channel)!.get(this.userId),
            timestamp: Date.now()
        });
    }
    
    /**
     * 处理用户离开频道
     */
    private handleUserLeave(channel: string): void {
        if (!this.channelUsers.has(channel)) return;
        
        // 从频道用户列表中移除
        if (this.channelUsers.get(channel)!.has(this.userId)) {
            this.channelUsers.get(channel)!.delete(this.userId);
            
            // 广播离开事件
            this.broadcastPresenceEvent({
                action: 'leave',
                channel: channel,
                clientId: this.userId,
                data: { userId: this.userId },
                timestamp: Date.now()
            });
        }
    }
    
    /**
     * 广播 Presence 事件
     */
    private broadcastPresenceEvent(event: PresenceEvent): void {
        const channel = event.channel;
        const message = {
            type: 'presence',
            event: event
        };
        
        // 发布到频道
        this.publish(channel, message);
    }
    
    /**
     * 处理 Presence 事件
     */
    private handlePresenceEvent(event: PresenceEvent): void {
        const channel = event.channel;
        const clientId = event.clientId;
        
        // 更新本地用户列表
        if (!this.channelUsers.has(channel)) {
            this.channelUsers.set(channel, new Map());
        }
        const users = this.channelUsers.get(channel)!;
        
        if (event.action === 'join') {
            // 新用户加入
            users.set(clientId, {
                userId: clientId,
                userData: event.data?.userData || event.data || {},
                status: event.data?.status || UserStatus.ONLINE,
                lastActive: event.timestamp
            });
        } else if (event.action === 'leave') {
            // 用户离开
            users.delete(clientId);
        } else if (event.action === 'state-change') {
            // 用户状态变更
            if (users.has(clientId)) {
                const userInfo = users.get(clientId)!;
                userInfo.status = event.data?.status || userInfo.status;
                userInfo.userData = event.data?.userData || event.data || userInfo.userData;
                userInfo.lastActive = event.timestamp;
            }
        }
        
        // 通知所有监听器
        this.notifyPresenceEvent(event);
    }
    
    /**
     * 通知 Presence 事件
     */
    private notifyPresenceEvent(event: PresenceEvent): void {
        const channel = event.channel;
        if (!this.presenceSubscriptions.has(channel)) return;
        
        const callbacks = this.presenceSubscriptions.get(channel)!;
        callbacks.forEach(cb => {
            try {
                cb(event);
            } catch (e) {
                log(`Presence 事件回调出错`, e);
            }
        });
    }
    
    /**
     * 重新订阅所有消息频道
     */
    private resubscribeAll(): void {
        this.subscriptions.forEach((_, channel) => {
            this.doSubscribe(channel);
        });
    }
}

// 导出单例实例和类型
export const goEasyManager = GoEasyManager.instance;
// export type { MessageCallback, PresenceCallback };
// export { UserStatus, PresenceEvent };
这是怎么使用(这里修改为,可以获取在线人数,状态等)
typescript 复制代码
import { _decorator, Component, Node ,director, log, AudioClip, Label, find, sys, CCObjectFlags, Prefab, instantiate, Color, resources, game, PhysicsSystem2D, EPhysics2DDrawFlags, ProgressBar } from 'cc';
import { AudioManager } from './tool/AudioManager';
import { PlayerManager } from './PlayerManager';
import { GlobalEvent } from './tool/GlobalEventManager';
import { goEasyManager, UserStatus,  PresenceEvent,  MessageCallback,  PresenceCallback  } from './tool/GoEasyManager';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {
    onLoad() {
       // 初始化 GoEasy
        goEasyManager.init(
            "BC-xxx", 
            "hangzhou.goeasy.io",
            "player_" + Date.now(), // 用户ID
            { level: 1, name: "Player" } // 用户数据
        );
        // 订阅游戏频道
        goEasyManager.subscribe('mindYourStep', this.handleGameMessage.bind(this));
        // 加入游戏频道并订阅 Presence 事件
        goEasyManager.joinChannel('mindYourStep');
        goEasyManager.subscribePresence('mindYourStep', this.handlePresenceEvent.bind(this));
        
        // 获取在线玩家列表
        this.updateOnlinePlayersList();
        setTimeout(() => {
            this.sendPlayerMove(45564);
        }, 500);
     

    }

// 处理游戏消息
    private handleGameMessage: MessageCallback = (content) => {
        // 忽略 Presence 事件(它们会被单独处理)
        if (content && content.type === 'presence') return;
        
        log("收到游戏消息:", content);
        // 处理游戏逻辑
    }
    
    // 处理 Presence 事件
    private handlePresenceEvent: PresenceCallback = (event) => {
        log(`收到 Presence 事件: ${event.action}`, event);
        
        switch (event.action) {
            case 'join':
                log(`玩家加入: ${event.clientId}`, event.data);
                break;
                
            case 'leave':
                log(`玩家离开: ${event.clientId}`);
                break;
                
            case 'state-change':
                log(`玩家状态变更: ${event.clientId}`, event.data);
                break;
        }
        
        // 更新在线玩家列表
        this.updateOnlinePlayersList();
    }
    
    // 更新在线玩家列表
    private updateOnlinePlayersList() {
        goEasyManager.getOnlineUsers('mindYourStep', (users) => {
            log("在线玩家列表:", users);
        });
    }
    
    // 发送玩家移动
    public sendPlayerMove(step: any) {
        goEasyManager.publish('mindYourStep', { step: step });
    }
    
    // 设置玩家状态
    public setPlayerStatus(status: UserStatus) {
        goEasyManager.setUserStatus(status);
    }


  
    protected onDestroy(): void {
         // 离开频道
        goEasyManager.leaveChannel('mindYourStep');
        goEasyManager.unsubscribePresence('mindYourStep');
        goEasyManager.unsubscribe('mindYourStep');
    }
}
相关推荐
NetInside_3 小时前
2025 DEM 趋势 × NetInside 产品能力:行业深度解读
运维·网络
usrcnusrcn3 小时前
智能建筑的 “隐形神经”:交换机如何连接安防、照明与门禁系统?
运维·服务器·网络
喵了meme4 小时前
C语言实战2
c语言·开发语言·网络
独行soc4 小时前
2025年渗透测试面试题总结-280(题目+回答)
网络·python·安全·web安全·网络安全·渗透测试·安全狮
唯创知音5 小时前
WT2605A录音方案实现高保真音频采集本地存储云端同步!
网络·音视频·录音芯片·录音方案·录音上传
@CLoudbays_Martin115 小时前
什么是IP黑洞?
网络·网络协议·tcp/ip
qqssss121dfd5 小时前
计算机网络(第8版,谢希仁)第三章习题解答
网络·计算机网络·php
kaikaile19956 小时前
LDPC编解码与未编码信息的误码率比较
网络
老蒋新思维7 小时前
创客匠人 2025 万人峰会核心:AI 驱动知识产品变现革新
大数据·人工智能·网络协议·tcp/ip·创始人ip·创客匠人·知识变现