import EventEmitter from 'eventemitter3';
import ReceiverGroup from './ReceiverGroup';
import LobbyService from './LobbyService';
import Room from './Room';
import Lobby from './Lobby';
const DEFAULT_GAME_VERSION = '0.0.1';
function isInternationalApp(appId) {
const suffix = appId.slice(-9);
return suffix === '-MdYXbMMI';
}
/**
* 多人对战游戏服务的客户端
* @param {Object} opts
* @param {String} opts.userId 玩家唯一 Id
* @param {String} opts.appId APP ID
* @param {String} opts.appKey APP KEY
* @param {Boolean} [opts.ssl] 是否使用 ssl,仅在 Client Engine 中可用
* @param {String} [opts.gameVersion] 游戏版本号
* @param {String} [opts.playServer] 路由地址
*/
export default class Client extends EventEmitter {
constructor(opts) {
super();
if (!(typeof opts.appId === 'string')) {
throw new TypeError(`${opts.appId} is not a string`);
}
if (!(typeof opts.appKey === 'string')) {
throw new TypeError(`${opts.appKey} is not a string`);
}
if (!(typeof opts.userId === 'string')) {
throw new TypeError(`${opts.userId} is not a string`);
}
if (opts.feature !== undefined && !(typeof opts.feature === 'string')) {
throw new TypeError(`${opts.feature} is not a string`);
}
if (opts.ssl !== undefined && !(typeof opts.ssl === 'boolean')) {
throw new TypeError(`${opts.ssl} is not a boolean`);
}
if (
opts.gameVersion !== undefined &&
!(typeof opts.gameVersion === 'string')
) {
throw new TypeError(`${opts.gameVersion} is not a string`);
}
if (
opts.playServer !== undefined &&
!(typeof opts.playServer === 'string')
) {
throw new TypeError(`${opts.playServer} is not a string`);
}
if (opts.playServer === undefined && !isInternationalApp(opts.appId)) {
throw new Error('Please init with your server url.');
}
this._userId = opts.userId;
this._appId = opts.appId;
this._appKey = opts.appKey;
this._feature = opts.feature;
if (opts.ssl === false) {
this._insecure = true;
}
if (opts.gameVersion) {
this._gameVersion = opts.gameVersion;
} else {
this._gameVersion = DEFAULT_GAME_VERSION;
}
this._playServer = opts.playServer;
}
/**
* 建立连接
*/
connect() {
this._lobbyService = new LobbyService(this);
return this._lobbyService.authorize();
}
/**
* 重新连接
*/
async reconnect() {
return this._lobbyService.authorize();
}
/**
* 重新连接并自动加入房间
*/
async reconnectAndRejoin() {
if (!this.room) {
throw new Error('You have no room.');
}
return this.rejoinRoom(this.room.name);
}
/**
* 关闭
*/
async close() {
if (this._lobby) {
await this._lobby.close();
}
if (this.room) {
await this.room.close();
}
this._clear();
}
/**
* 加入大厅
*/
joinLobby() {
if (this._lobby) {
// 已经存在 Lobby 对象
throw new Error('You are already in lobby.');
}
this._lobby = new Lobby(this);
return this._lobby.join();
}
/**
* 离开大厅
*/
leaveLobby() {
if (!this._lobby) {
// 不存在 Lobby 对象
throw new Error('You are not in lobby yet');
}
return this._lobby.leave();
}
/**
* 创建房间
* @param {Object} [opts] 创建房间选项
* @param {String} [opts.roomName] 房间名称,在整个游戏中唯一,默认值为 null,则由服务端分配一个唯一 Id
* @param {Object} [opts.roomOptions] 创建房间选项,默认值为 null
* @param {Boolean} [opts.roomOptions.open] 房间是否打开
* @param {Boolean} [opts.roomOptions.visible] 房间是否可见,只有「可见」的房间会出现在房间列表里
* @param {Number} [opts.roomOptions.emptyRoomTtl] 房间为空后,延迟销毁的时间
* @param {Number} [opts.roomOptions.playerTtl] 玩家掉线后,延迟销毁的时间
* @param {Number} [opts.roomOptions.maxPlayerCount] 最大玩家数量
* @param {Object} [opts.roomOptions.customRoomProperties] 自定义房间属性
* @param {Array.<String>} [opts.roomOptions.customRoomPropertyKeysForLobby] 在大厅中可获得的房间属性「键」数组
* @param {CreateRoomFlag} [opts.roomOptions.flag] 创建房间标记,可多选
* @param {Array.<String>} [opts.expectedUserIds] 邀请好友 ID 数组,默认值为 null
*/
async createRoom({
roomName = null,
roomOptions = null,
expectedUserIds = null,
} = {}) {
if (this.room) {
// 判断当前处于游戏中
throw new Error('You are already in room.');
}
if (this._lobby) {
this._lobby.close();
}
this._room = new Room(this);
await this.room.create(roomName, roomOptions, expectedUserIds);
return this.room;
}
/**
* 加入房间sss
* @param {String} roomName 房间名称
* @param {*} [expectedUserIds] 邀请好友 ID 数组,默认值为 null
*/
async joinRoom(roomName, { expectedUserIds = null } = {}) {
if (this.room) {
// 判断当前处于游戏中
throw new Error('You are already in room.');
}
if (this._lobby) {
this._lobby.close();
}
this._room = new Room(this);
await this.room.join(roomName, expectedUserIds);
return this.room;
}
/**
* 重新加入房间
* @param {String} roomName 房间名称
*/
async rejoinRoom(roomName) {
if (this._lobby) {
this._lobby.close();
}
this._room = new Room(this);
await this.room.rejoin(roomName);
return this.room;
}
/**
* 随机加入或创建房间
* @param {String} roomName 房间名称
* @param {Object} [opts] 创建房间选项
* @param {Object} [opts.roomOptions] 创建房间选项,默认值为 null
* @param {Boolean} [opts.roomOptions.open] 房间是否打开
* @param {Boolean} [opts.roomOptions.visible] 房间是否可见,只有「可见」的房间会出现在房间列表里
* @param {Number} [opts.roomOptions.emptyRoomTtl] 房间为空后,延迟销毁的时间
* @param {Number} [opts.roomOptions.playerTtl] 玩家掉线后,延迟销毁的时间
* @param {Number} [opts.roomOptions.maxPlayerCount] 最大玩家数量
* @param {Object} [opts.roomOptions.customRoomProperties] 自定义房间属性
* @param {Array.<String>} [opts.roomOptions.customRoomPropertyKeysForLobby] 在大厅中可获得的房间属性「键」数组
* @param {CreateRoomFlag} [opts.roomOptions.flag] 创建房间标记,可多选
* @param {Array.<String>} [opts.expectedUserIds] 邀请好友 ID 数组,默认值为 null
*/
async joinOrCreateRoom(
roomName,
{ roomOptions = null, expectedUserIds = null } = {}
) {
if (this.room) {
// 判断当前处于游戏中
throw new Error('You are already in room.');
}
if (this._lobby) {
this._lobby.close();
}
this._room = new Room(this);
await this.room.joinOrCreate(roomName, roomOptions, expectedUserIds);
return this.room;
}
/**
* 随机加入房间
* @param {Object} [opts] 随机加入房间选项
* @param {Object} [opts.matchProperties] 匹配属性,默认值为 null
*/
async joinRandomRoom({
matchProperties = null,
expectedUserIds = null,
} = {}) {
if (this.room) {
// 判断当前处于游戏中
throw new Error('You are already in room.');
}
if (this._lobby) {
this._lobby.close();
}
this._room = new Room(this);
await this.room.joinRandom(matchProperties, expectedUserIds);
return this.room;
}
/**
* 随机匹配,匹配成功后并不加入房间,而是返回房间 id
* @param {Object} [opts] 随机加入房间选项
* @param {Object} [opts.matchProperties] 匹配属性,默认值为 null
*/
matchRandom(
piggybackPeerId,
{ matchProperties = null, expectedUserIds = null } = {}
) {
return this._lobbyService.matchRandom(
piggybackPeerId,
matchProperties,
expectedUserIds
);
}
/**
* 设置房间开启 / 关闭
* @param {Boolean} open 是否开启
*/
setRoomOpen(open) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.setOpen(open);
}
/**
* 设置房间可见 / 不可见
* @param {Boolean} visible 是否可见
*/
setRoomVisible(visible) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.setVisible(visible);
}
/**
* 设置房间允许的最大玩家数量
* @param {*} count 数量
*/
setRoomMaxPlayerCount(count) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.setMaxPlayerCount(count);
}
/**
* 设置房间占位玩家 Id 列表
* @param {*} expectedUserIds 玩家 Id 列表
*/
setRoomExpectedUserIds(expectedUserIds) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.setExpectedUserIds(expectedUserIds);
}
/**
* 清空房间占位玩家 Id 列表
*/
clearRoomExpectedUserIds() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.clearExpectedUserIds();
}
/**
* 增加房间占位玩家 Id 列表
* @param {*} expectedUserIds 增加的玩家 Id 列表
*/
addRoomExpectedUserIds(expectedUserIds) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.addExpectedUserIds(expectedUserIds);
}
/**
* 移除房间占位玩家 Id 列表
* @param {*} expectedUserIds 移除的玩家 Id 列表
*/
removeRoomExpectedUserIds(expectedUserIds) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.removeExpectedUserIds(expectedUserIds);
}
/**
* 设置房主
* @param {Number} newMasterId 新房主 ID
*/
setMaster(newMasterId) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.setMaster(newMasterId);
}
/**
* 发送自定义消息
* @param {Number|String} eventId 事件 ID
* @param {Object} eventData 事件参数
* @param {Object} options 发送事件选项
* @param {ReceiverGroup} options.receiverGroup 接收组
* @param {Array.<Number>} options.targetActorIds 接收者 Id。如果设置,将会覆盖 receiverGroup
*/
sendEvent(
eventId,
eventData = {},
options = { receiverGroup: ReceiverGroup.All }
) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.sendEvent(eventId, eventData, options);
}
/**
* 离开房间
*/
async leaveRoom() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
await this.room.leave();
}
/**
* 踢人
* @param {Number} actorId 踢用户的 actorId
* @param {Object} [opts] 附带参数
* @param {Number} [opts.code] 编码
* @param {String} [opts.msg] 附带信息
*/
kickPlayer(actorId, { code = null, msg = null } = {}) {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room.kickPlayer(actorId, code, msg);
}
/**
* 暂停消息队列处理
* @return {void}
*/
pauseMessageQueue() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
this.room.pauseMessageQueue();
}
/**
* 恢复消息队列处理
* @return {void}
*/
resumeMessageQueue() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
this.room.resumeMessageQueue();
}
/**
* 获取当前所在房间
* @type {Room}
* @readonly
*/
get room() {
return this._room;
}
/**
* 获取当前玩家
* @type {Player}
* @readonly
*/
get player() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room._player;
}
/**
* 获取房间列表
* @type {Array.<LobbyRoom>}
* @readonly
*/
get lobbyRoomList() {
if (!this._lobby) {
throw new Error('You are not in lobby yet.s');
}
return this._lobby._lobbyRoomList;
}
// 清理内存数据
_clear() {
this.removeAllListeners();
this._lobbyRoomList = null;
this._masterServer = null;
this._gameServer = null;
this._lobby = null;
this._room = null;
}
// 模拟断线
_simulateDisconnection() {
if (!this.room) {
throw new Error('You are not in room yet.');
}
return this.room._simulateDisconnection();
}
/**
* 获取用户 id
* @type {String}
* @readonly
*/
get userId() {
return this._userId;
}
}