Commit e19dda5f authored by 范雪寒's avatar 范雪寒

feat: networkHelper

parent 915199c0
No preview for this file type
{ {
"ver": "1.1.2", "ver": "1.1.2",
"uuid": "d5f63b05-0201-428e-a578-4a52a688266d", "uuid": "827d871e-1ae4-411e-9fe3-0411c5279abe",
"isBundle": false, "isBundle": false,
"bundleName": "", "bundleName": "",
"priority": 1, "priority": 1,
......
export as namespace Play;
declare class EventEmitter<T> {
on<K extends keyof T>(event: K, listener: (payload: T[K]) => any): this;
on(evt: string, listener: Function): this;
once<K extends keyof T>(event: K, listener: (payload: T[K]) => any): this;
once(evt: string, listener: Function): this;
off<K extends keyof T>(evt: K | string, listener?: Function): this;
emit<K extends keyof T>(evt: K | string, ...args: any[]): boolean;
}
export enum Event {
/** 断开连接 */
DISCONNECTED = 'disconnected',
/** 加入到大厅 */
LOBBY_JOINED = 'lobbyJoined',
/** 大厅房间列表变化 */
LOBBY_ROOM_LIST_UPDATED = 'lobbyRoomListUpdate',
/** 有新玩家加入房间 */
PLAYER_ROOM_JOINED = 'newPlayerJoinedRoom',
/** 有玩家离开房间 */
PLAYER_ROOM_LEFT = 'playerLeftRoom',
/** 玩家活跃属性变化 */
PLAYER_ACTIVITY_CHANGED = 'playerActivityChanged',
/** 主机变更 */
MASTER_SWITCHED = 'masterSwitched',
/** 离开房间 */
ROOM_LEFT = 'roomLeft',
/** 被踢出房间 */
ROOM_KICKED = 'roomKicked',
/** 房间系统属性变化 */
ROOM_SYSTEM_PROPERTIES_CHANGED = 'roomSystemPropertiesChanged',
/** 房间自定义属性变化 */
ROOM_CUSTOM_PROPERTIES_CHANGED = 'roomCustomPropertiesChanged',
/** 玩家自定义属性变化 */
PLAYER_CUSTOM_PROPERTIES_CHANGED = 'playerCustomPropertiesChanged',
/** 自定义事件 */
CUSTOM_EVENT = 'customEvent',
/** 错误事件 */
ERROR = 'error',
}
export enum ReceiverGroup {
/** 其他人(除了自己之外的所有人) */
Others,
/** 所有人(包括自己) */
All,
/** 主机客户端 */
MasterClient,
}
interface CustomProperties {
[key: string]: any;
}
interface CustomEventData {
[key: string]: any;
}
interface ErrorEvent {
code: number;
detail: string;
}
declare interface PlayEvent {
connected: void;
connectFailed: ErrorEvent;
disconnected: void;
lobbyJoined: void;
lobbyLeft: void;
lobbyRoomListUpdate: void;
roomCreated: void;
roomCreateFailed: ErrorEvent;
roomJoined: void;
roomJoinFailed: ErrorEvent;
newPlayerJoinedRoom: {
newPlayer: Player;
};
playerLeftRoom: {
leftPlayer: Player;
};
playerActivityChanged: {
player: Player;
};
masterSwitched: {
newMaster: Player;
};
roomLeft: void;
roomKicked: {
code: number;
msg: string;
};
roomCustomPropertiesChanged: {
changedProps: CustomProperties;
};
roomSystemPropertiesChanged: {
changedProps: CustomProperties;
};
playerCustomPropertiesChanged: {
player: Player;
changedProps: CustomProperties;
};
customEvent: {
eventId: number;
eventData: CustomEventData;
senderId: number;
};
error: ErrorEvent;
}
export class LobbyRoom {
readonly roomName: string;
readonly maxPlayerCount: number;
readonly expectedUserIds: string[];
readonly emptyRoomTtl: number;
readonly playerTtl: number;
readonly playerCount: number;
readonly customRoomPropertiesForLobby: CustomProperties;
}
export class Player {
readonly userId: string;
readonly actorId: number;
readonly isLocal: boolean;
readonly isMaster: boolean;
readonly isActive: boolean;
setCustomProperties(
properties: CustomProperties,
opts?: {
expectedValues?: CustomProperties;
}
): Promise<void>;
readonly customProperties: CustomProperties;
}
export class Room {
readonly name: string;
readonly open: boolean;
readonly visible: boolean;
readonly maxPlayerCount: number;
readonly master: Player;
readonly masterId: number;
readonly expectedUserIds: string[];
readonly playerList: Player[];
getPlayer(actorId: number): Player;
setCustomProperties(
properties: CustomProperties,
opts?: {
expectedValues?: CustomProperties;
}
): Promise<void>;
readonly customProperties: CustomProperties;
setOpen(open: boolean): Promise<void>;
setVisible(visible: boolean): Promise<void>;
setRoomMaxPlayerCount(count: number): Promise<void>;
setRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
clearRoomExpectedUserIds(): Promise<void>;
addRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
removeRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
setMaster(newMasterId: number): Promise<void>;
sendEvent(
eventId: number,
eventData?: CustomEventData,
options?: {
receiverGroup?: ReceiverGroup;
targetActorIds?: number[];
}
): Promise<void>;
kickPlayer(
actorId: number,
opts?: {
code?: number;
msg?: string;
}
): Promise<void>;
leave(): Promise<void>;
}
export class Client extends EventEmitter<PlayEvent> {
readonly room: Room;
readonly player: Player;
readonly lobbyRoomList: LobbyRoom[];
userId: string;
constructor(opts: {
appId: string;
appKey: string;
userId: string;
ssl?: boolean;
feature?: string;
gameVersion?: string;
playServer?: string;
});
connect(): Promise<Client>;
reconnect(): Promise<Client>;
reconnectAndRejoin(): Promise<Room>;
close(): Promise<void>;
joinLobby(): Promise<void>;
leaveLobby(): Promise<void>;
createRoom(opts?: {
roomName?: string;
roomOptions?: Object;
expectedUserIds?: string[];
}): Promise<Room>;
joinRoom(
roomName: string,
opts?: {
expectedUserIds?: string[];
}
): Promise<Room>;
rejoinRoom(roomName: string): Promise<Room>;
joinOrCreateRoom(
roomName: string,
opts?: {
roomOptions?: Object;
expectedUserIds: string[];
}
): Promise<Room>;
joinRandomRoom(opts?: {
matchProperties?: Object;
expectedUserIds?: string[];
}): Promise<Room>;
matchRandom(
piggybackPeerId: string,
opts?: { matchProperties?: Object; expectedUserIds?: string[] }
): Promise<LobbyRoom>;
setRoomOpen(open: boolean): Promise<void>;
setRoomVisible(visible: boolean): Promise<void>;
setRoomMaxPlayerCount(count: number): Promise<void>;
setRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
clearRoomExpectedUserIds(): Promise<void>;
addRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
removeRoomExpectedUserIds(expectedUserIds: string[]): Promise<void>;
setMaster(newMasterId: number): Promise<void>;
sendEvent(
eventId: number,
eventData?: CustomEventData,
options?: {
receiverGroup?: ReceiverGroup;
targetActorIds?: number[];
}
): Promise<void>;
leaveRoom(): Promise<void>;
kickPlayer(
actorId: number,
opts?: {
code?: number;
msg?: string;
}
): Promise<void>;
pauseMessageQueue(): void;
resumeMessageQueue(): void;
}
export enum CreateRoomFlag {
FixedMaster = 1,
MasterUpdateRoomProperties = 2,
}
export function setAdapters(newAdapters: { WebSocket: Function }): void;
export enum LogLevel {
Debug = 'Debug',
Warn = 'Warn',
Error = 'Error',
}
export function setLogger(logger: {
Debug: (...args: any[]) => any;
Warn: (...args: any[]) => any;
Error: (...args: any[]) => any;
}): void;
export enum PlayErrorCode {
OPEN_WEBSOCKET_ERROR = 10001,
SEND_MESSAGE_STATE_ERROR = 10002,
}
export function registerType<T>(
type: T,
typeId: number,
serializeMethod: (obj: T) => Uint8Array,
deserializeMethod: (bytes: Uint8Array) => T
): void;
export function serializeObject(obj: Object): Uint8Array;
export function deserializeObject(bytes: Uint8Array): Object;
{
"ver": "2.0.0",
"uuid": "5bcc0ae2-0927-4b6b-9ac1-9c4bfe24b34d",
"subMetas": {}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{ {
"ver": "1.0.8", "ver": "1.0.8",
"uuid": "92c53b26-dc66-4a71-9e9b-862df5cb12b5", "uuid": "3e7a7ab3-dbdb-49c9-995d-757dbfe9f58b",
"isPlugin": true, "isPlugin": true,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,
"loadPluginInEditor": false, "loadPluginInEditor": true,
"subMetas": {} "subMetas": {}
} }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
import { RandomInt } from "../script/util";
export class NetworkHelper { export class NetworkHelper {
_eventListeners: any = {}; _eventListeners: any = {};
ctor() {} ctor() { }
on(eventName, func) { on(eventName, func) {
this._eventListeners[eventName] = func; this._eventListeners[eventName] = func;
} }
async init(roomType: string, maxPlayers: number) { async init(roomType: string, maxPlayers: number) {
this.initRoom(); await this.initRoom();
return await this.joinRoom(roomType, maxPlayers);
try {
return await this.joinRoom(roomType, maxPlayers);
} catch (e) {
await this.initListener();
this.initRoom();
return await this.joinRoom(roomType, maxPlayers);
}
} }
async startGame() { async startGame() {
...@@ -25,238 +20,136 @@ export class NetworkHelper { ...@@ -25,238 +20,136 @@ export class NetworkHelper {
async stopGame() { async stopGame() {
await this.stopFrameSync(); await this.stopFrameSync();
await this.closeRoom();
await this.leaveRoom(); await this.leaveRoom();
} }
getRoomInfo() { listenerInited = false;
return this.room.roomInfo;
}
initListener() {
if (MGOBE.Player.id !== undefined) {
return;
}
return new Promise((resolve, reject) => {
const gameId = "obg-i4ql53h1"; //替换为控制台上的 游戏 ID
const secretKey = "060d81c7abaf24c8ce2afc5a725c152062676d35"; //替换为控制台上的 游戏 Key
const serverUrl = "i4ql53h1.wxlagame.com"; //替换为控制台上的 域名
const gameInfo = {
gameId: gameId,
openId: "openid_test" + Math.random(), //自定义的用户唯一ID
secretKey: secretKey,
};
const config = {
url: serverUrl,
reconnectMaxTimes: 5,
reconnectInterval: 1000,
resendInterval: 1000,
resendTimeout: 10000,
cacertNativeUrl: "",
};
MGOBE.DebuggerLog.enable = false; room: any;
// 如果是原生平台,则加载 Cert 证书,否则会提示 WSS 错误 client: any;
if (cc.sys.isNative) { async initRoom() {
let cacertFile; const client = new globalThis.Play.Client({
const cacertNode = cc.find("cacertNode"); appId: "lyn5nahSjCX0gpuRPugoMILM-gzGzoHsz",
if (cacertNode) { appKey: "Nh9qGdBHq7MGjPbgUoLxm8oG",
cacertFile = cacertNode.getComponent("cacert").cacertFile; userId: `${new Date().getTime()}_${RandomInt(100000000)}`,
} playServer: 'https://lyn5nahs.lc-cn-n1-shared.com'
if (!cacertFile) {
this.log("没有cacertFile!!!");
}
config.cacertNativeUrl =
cc.loader.md5Pipe && cc.ENGINE_VERSION < "2.4.0"
? cc.loader.md5Pipe.transformURL(cacertFile.nativeUrl)
: cacertFile.nativeUrl;
}
MGOBE.Listener.init(gameInfo, config, (event) => {
this.log(JSON.stringify(event));
if (event.code !== 0) {
this.log("初始化失败: " + event.code);
reject();
return;
}
this.log("初始化成功");
resolve(null);
});
}); });
console.log('client = ', client);
await client.connect();
this.client = client;
console.log('连接成功');
} }
room: MGOBE.Room; player: any;
initRoom() { joinRoom(roomType: string, maxPlayers: number) {
this.room = new MGOBE.Room();
MGOBE.Listener.add(this.room);
this.room.onJoinRoom = this.onJoinRoom.bind(this);
this.room.onLeaveRoom = this.onLeaveRoom.bind(this);
this.room.onRecvFromClient = this.onRecvFromClient.bind(this);
this.room.onRecvFrame = this.onRecvFrame.bind(this);
this.room.onChangePlayerNetworkState =
this.onChangePlayerNetworkState.bind(this);
this.room.onStartFrameSync = this.onStartFrameSync.bind(this);
this.room.onStopFrameSync = this.onStopFrameSync.bind(this);
this.room.onRecvFromGameSvr = this.onRecvFromGameSvr.bind(this);
this.log("this.room = " + JSON.stringify(this.room.roomInfo));
}
joinRoom(roomType: string, maxPlayers: number, customData: string = "") {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const playerName = "Tom" + Math.random(); const roomProp = { roomType, maxPlayers };
const playerInfo = { this.client.joinRandomRoom({
name: playerName, matchProperties: roomProp,
customPlayerStatus: 0, }).then((room) => {
customProfile: customData, resolve(this.onJoinRoomSuccess(room));
}; }).catch((error) => {
console.log('加入房间失败');
const matchRoomPara = { if (error.code == 4301) {
playerInfo, const options = {
maxPlayers: maxPlayers, visible: true,
roomType: roomType, playerTtl: 0,
}; emptyRoomTtl: 0,
maxPlayerCount: maxPlayers,
this.room.matchRoom(matchRoomPara, (event) => { customRoomProperties: roomProp,
this.log(JSON.stringify(event)); customRoomPropertyKeysForLobby: ['roomType', 'maxPlayers'],
if (event.code === 0) { flag: globalThis.Play.CreateRoomFlag.MasterUpdateRoomProperties
cc.log("匹配成功: " + event.data.roomInfo.id); };
const player = event.data.roomInfo.playerList.find( this.client.createRoom({
(player) => player.name == playerName roomOptions: options,
); }).then((room) => {
if (this.checkRoomOwnerOffLine()) { resolve(this.onJoinRoomSuccess(room));
if (this._eventListeners["playerOffLine"]) { }).catch((error) => {
this._eventListeners["playerOffLine"](event); console.error(error.code, error.detail);
} });
cc.log("房主掉线了");
resolve(null);
return;
}
resolve(player.id);
} else {
cc.log("匹配失败");
reject(event);
} }
}); });
}); });
} }
leaveRoom() { onJoinRoomSuccess(room: globalThis.Play.Room) {
return new Promise((resolve, reject) => { console.log('加入房间成功 room = ', room);
this.room.leaveRoom({}, (event) => { const playerMe = room.playerList.find(player => player.isLocal);
this.log(JSON.stringify(event)); const masterPlayer = room.playerList.find(player => player.isMaster);
if (event.code === 0) { const masterId = masterPlayer.userId;
this.log("退房成功" + this.room.roomInfo.id); const playerId = playerMe.userId;
// this.room.initRoom(); this.room = new FakeRoom(masterId);
resolve(null); this.room.players.push(this.room.player);
} else { this.player = this.room.player;
this.log("退房失败");
} this.client.on(globalThis.Play.Event.PLAYER_ROOM_LEFT, (event) => {
}); this.onLeaveRoom({ data: { leavePlayerId: event.leftPlayer.userId } });
}); });
this.client.on(globalThis.Play.Event.PLAYER_ROOM_JOINED, (event) => {
this.onJoinRoom({ playerId: event.newPlayer.userId });
});
this.client.on(globalThis.Play.Event.CUSTOM_EVENT, (event) => {
this.onRecvFrame({ data: event.eventData });
});
// this.room.onDisconnect(this.onDisconnect.bind(this));
// this.room.onDismiss(this.onDisconnect.bind(this));
return playerId;
} }
closeRoom() { async leaveRoom() {
return new Promise((resolve, reject) => { await this.client.close();
this.room.changeRoom({ isForbidJoin: true }, (event) => { console.log("退房成功");
console.log("关门");
this.log(JSON.stringify(event));
resolve(null);
});
});
} }
sendMessage() { async dismissRoom() {
const sendToClientPara = { if (this.room.ownerId == this.player.id) {
recvType: MGOBE.ENUM.RecvType.ROOM_ALL, console.log("房间已解散");
recvPlayerList: [], }
msg: "hello" + Math.random(),
};
this.room.sendToClient(sendToClientPara, (event) => console.log(event));
} }
startFrameSync() { async closeRoom() {
return new Promise((resolve, reject) => { // 设置房间不可见
this.room.startFrameSync({}, (event) => { await this.client.setRoomVisible(false);
this.log(JSON.stringify(event)); console.log(this.client.room.visible);
if (event.code === 0) {
cc.log("开始帧同步成功,请到控制台查看具体帧同步信息");
resolve(null);
} else {
reject();
}
});
});
} }
stopFrameSync() { async startFrameSync() {
return new Promise((resolve, reject) => { console.log("开始帧同步成功");
if (!this.room) {
resolve(null);
return;
}
this.room.stopFrameSync({}, (event) => {
this.log(JSON.stringify(event));
if (event.code === 0) {
this.log("停止帧同步成功");
resolve(null);
} else {
this.log("停止帧同步失败");
reject(event.code);
}
});
});
} }
sendToServer() { async stopFrameSync() {
const sendToGameServerPara = { console.log("停止帧同步成功");
data: {
cmd: 1,
},
};
this.room.sendToGameSvr(sendToGameServerPara, (event) =>
console.log(event)
);
} }
sendFrame(data: any) { sendFrame(data: any) {
this.room.sendFrame({ data }, (err) => { this.client.sendEvent(0, { frame: { items: [{ data: data }] } }, {
if (err.code != 0) { receiverGroup: globalThis.Play.ReceiverGroup.All,
console.log("err", err);
}
}); });
} }
onJoinRoom(event) { onJoinRoom(event) {
console.log("新玩家加入", event);
if (this._eventListeners["playerJoin"]) { if (this._eventListeners["playerJoin"]) {
this._eventListeners["playerJoin"](event); this._eventListeners["playerJoin"](event);
} }
console.log("新玩家加入", event.data.joinPlayerId); this.room.players.forEach(player => {
console.log('player.playerId = ', player.playerId);
});
} }
onLeaveRoom(event) { onLeaveRoom(event) {
console.log("onLeaveRoom");
if (this._eventListeners["playerLeave"]) { if (this._eventListeners["playerLeave"]) {
this._eventListeners["playerLeave"](event); this._eventListeners["playerLeave"](event);
} }
console.log("玩家退出", event.data.leavePlayerId); console.log("玩家退出", event.data.leavePlayerId);
} }
onRecvFromClient() {} onRecvFromClient() { }
checkRoomOwnerOffLine() {
const owner = this.room.roomInfo.playerList.find( onDisconnect(event) {
(player) => player.id == this.room.roomInfo.owner this.log("玩家掉线了: " + JSON.stringify(event));
); if (this._eventListeners["playerOffLine"]) {
return ( this._eventListeners["playerOffLine"](event);
owner.commonNetworkState == MGOBE.types.NetworkState.COMMON_OFFLINE ||
owner.relayNetworkState == MGOBE.types.NetworkState.RELAY_OFFLINE
);
}
onChangePlayerNetworkState(event) {
console.log("玩家网络变化: " + JSON.stringify(event));
if (this.checkRoomOwnerOffLine()) {
if (this._eventListeners["playerOffLine"]) {
this._eventListeners["playerOffLine"](event);
}
cc.log("房主掉线了");
} }
} }
...@@ -266,21 +159,25 @@ export class NetworkHelper { ...@@ -266,21 +159,25 @@ export class NetworkHelper {
} }
} }
onStartFrameSync(event) { onStartFrameSync(event) {
console.log('onStartFrameSync');
if (this._eventListeners["gameStart"]) { if (this._eventListeners["gameStart"]) {
this._eventListeners["gameStart"](event); this._eventListeners["gameStart"](event);
} }
} }
onStopFrameSync(event) {} onStopFrameSync(event) { }
onRecvFromGameSvr() {} onRecvFromGameSvr() { }
async onDestroy() { async onDestroy() {
try { try {
this.log("onDestroy1"); console.log("onDestroy1");
MGOBE.Listener.clear(); // MGOBE.Listener.clear();
await this.stopGame(); this.stopFrameSync();
this.log("onDestroy2"); this.closeRoom();
this.dismissRoom();
this.leaveRoom();
console.log("onDestroy2");
} catch (e) { } catch (e) {
this.log(JSON.stringify(e)); console.log(JSON.stringify(e));
} }
} }
...@@ -292,4 +189,48 @@ export class NetworkHelper { ...@@ -292,4 +189,48 @@ export class NetworkHelper {
cc.log(str); cc.log(str);
} }
} }
callNetworkApiGet(baseUrl, uri, data, callBack) {
let queryStr = "?";
const params = [];
for (const key in data) {
if (Object.hasOwnProperty.call(data, key)) {
params.push(`${key}=${data[key]}`);
}
}
queryStr += params.join("&");
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 400) {
callBack(xhr.responseText);
}
};
const url = `${baseUrl}${uri}${queryStr}`;
console.log("url = " + url);
xhr.open("GET", url, true);
xhr.send();
}
} }
export function asyncDelay(time) {
return new Promise((resolve, reject) => {
cc.tween(cc.find("Canvas"))
.delay(time)
.call(() => {
resolve(null);
})
.start();
});
}
class FakeRoom {
ownerId;
players = [];
player: any;
roomInfo;
constructor(playerId) {
this.player = { playerId: playerId };
this.ownerId = playerId;
this.roomInfo = { owner: playerId }
}
}
\ No newline at end of file
...@@ -467,7 +467,7 @@ cc.Class({ ...@@ -467,7 +467,7 @@ cc.Class({
try { try {
this.log("喵喵喵1"); this.log("喵喵喵1");
this.playerId = await this.networkHelper.init("op_09_plus", 5); this.playerId = await this.networkHelper.init("OP32_PLUS", 5);
this.log("喵喵喵2"); this.log("喵喵喵2");
const room = this.networkHelper.room; const room = this.networkHelper.room;
if (this.playerId == room.roomInfo.owner) { if (this.playerId == room.roomInfo.owner) {
......
{ {
"ver": "1.0.8", "ver": "1.0.8",
"uuid": "f9688dab-f4fd-4e4b-9a97-a76b90f239f4", "uuid": "f9688dab-f4fd-4e4b-9a97-a76b90f239f4",
"isPlugin": true, "isPlugin": false,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,
"loadPluginInEditor": false, "loadPluginInEditor": false,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment