先记录用 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');
}
}