123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- import { NetRoom } from "./NetRoom";
- import { NetTeam } from "./NetTeam";
- import { WsClient } from "./WsClient";
- /**自定义同步游戏变量(只能以r_或p_开头,按帧率同步,重新进入会收到最新的数据)
- * 只有第一个参数有效,可加上第一个参数跟第一个参数同类型,用于接收改变前的数据
- * t_开头为队伍事件
- * r_开头 主机游戏数据 主机权限
- * revt_ 开头房间事件
- * p_ 开头玩家数据 玩家权限和主机ai权限
- * online 玩家在线下线状态
- * 尽量拆分数据类型,不要设置过于复杂的数据类型*/
- export interface game_protocol extends chsdk.OmitIndex<chsdk.EventsMap> {
- t_entry(id: string, location: number, nickName: string): void;//队伍有人进入
- t_exit(id: string, location: number, nickName: string): void;//队伍有人退出
- t_host(id: string, location: number, nickName: string): void;//队长切换
- t_chat(id: string, msg: string, location: number, nickName: string): void;//队伍聊天
- t_online(id: string, online: boolean, location: number, nickName: string): void;//队伍玩家在线情况变化
- t_ready(id: string, online: boolean, location: number, nickName: string): void;//队伍玩家准备情况变化
- t_matchStart(): void;//匹配开始
- t_matchCancel(): void;//匹配取消
- t_matchSuccess(): void;//匹配成功
- t_no_ready(): void;//有玩家未准备
- t_closed(): void;//队伍解散(一般用于被踢出事件)
- //
- r_obj(key: string, data: any, old: any): void;
- r_closed(): void;//房间关闭 关闭后 获取 results 结算信息
- r_host(id: string, location: number, nickName: string): void;//房主切换
- r_chat(id: string, msg: string, location: number, nickName: string): void;//房间聊天
- r_online(id: string, online: boolean, location: number, nickName: string): void;//房间玩家在线情况变化
- r_finish(id: string, rank: number): void//房间某个玩家完成游戏获得名次
- r_state(state: number, old_state?: number): void;//房间游戏状态
- p_state(state: number, old_state?: number): void;//玩家游戏状态
- finish(rank: number): void;//玩家完成游戏获得名次
- online(online: boolean): void//玩家断线重连消息
- }
- /**网络状态*/
- interface ws_event_protocol {
- Connecting(): void;//连接中
- Reconnecting(reconnectCount: number): void;//重新连接中
- Connected(): void;//进入大厅连接成功
- Reconnected(): void;//重连成功
- Error(err: any | string): void;//错误消息
- Closing(): void;//关闭连接中
- Closed(event: CloseEvent): void;//连接已关闭
- }
- function isArrayBuffer(it: unknown): it is ArrayBuffer {
- try {
- return it instanceof ArrayBuffer
- } catch (_) {
- return false
- }
- }
- const HEARTBEAT_INTERVAL = 1000; //每秒发送一次 Ping
- const HEARTBEAT_TIMEOUT = 30000; //30 秒的断线超时
- const DIRTYDATACHECK_INTERVAL = 200;//每200毫秒同步一次自定义游戏变量
- const EVTCHECK_INTERVAL = 66;//每66毫秒同步一次自定义游戏事件
- const RECONNECT_COUNT = 10;//默认重连次数
- const RECONNECT_INTERVAL = 2000;//默认重连间隔
- const PING = 'ping';
- const PONG = 'pong';
- //
- const S2C_LOGIN_SUCCESS = 's2c_login_success';
- const S2C_TEAM_SUCCESS = 's2c_team_success';
- const S2C_JOIN_TEAM_FAIL = 's2c_join_team_fail';
- const S2C_TEAM_USER_JOIN = 's2c_team_user_join';
- const S2C_TEAM_USER_EXIT = 's2c_team_user_exit';
- const S2C_TEAM_CHANGE_HOST = 's2c_team_change_host';
- const S2C_USER_RECONNECT = 's2c_user_reconnect';
- const S2C_USER_DISCONNECT = 's2c_user_disconnect';
- const S2C_MATCH = 's2c_match';
- const S2C_MATCH_SUCCESS = 's2c_match_success';
- const S2C_MATCH_CANCEL = 's2c_match_cancel';
- const S2C_ROOM_GAMEDATA_CHANGE = 's2c_room_gameData_change';
- const S2C_USER_GAMEDATA_CHANGE = 's2c_user_gameData_change';
- const S2C_ROOM_CHANGE_HOST = 's2c_room_change_host';
- const S2C_ROOM_CLOSED = 's2c_room_closed';
- const S2C_TALK = 's2c_talk';
- const S2C_FINISH = 's2c_finish';
- const S2C_SETTLEMENT = 's2c_settlement';
- const S2C_READY = 's2c_ready';
- const S2C_NOT_READY = 's2c_not_ready';
- //
- const C2S_UPDATE_USER_GAMEDATA = 'c2s_update_user_gameData';
- const C2S_UPDATE_ROOM_GAMEDATA = 'c2s_update_room_gameData';
- const C2S_SET_TEAM = 'c2s_set_team';
- const C2S_JOIN_TEAM = 'c2s_join_team';
- const C2S_EXIT_TEAM = 'c2s_exit_team';
- const C2S_CLOSE_ROOM = 'c2s_close_room';
- const C2S_ROOM_EXIT = 'c2s_room_exit';
- const C2S_MESSAGE = 'c2s_message';
- const C2S_MESSAGE_TO_HOST = 'c2s_message_to_host';
- const C2S_MESSAGE_TO_OTHER = 'c2s_message_without_self';
- const C2S_TALK = 'c2s_talk';
- const C2S_BACKED_RETURN = 'c2s_backed_return';
- const C2S_BACKED = 'c2s_to_backed';
- const C2S_FINISH = 'c2s_finish';
- //
- const Ver: string = '0.1.8';
- /**客户端*/
- export class ch_net<GD extends game_protocol = game_protocol> {
- /**连接状态事件*/
- public state = chsdk.get_new_event<ws_event_protocol>();
- private _ws: WsClient | null = null;
- private _url?: string | null;
- private _ca?: string;
- private reconnection: boolean;
- private reconnectCount: number;
- private reconnectInterval: number;
- private timeoutInterval: number;
- private gameDataInterval: number;
- private gameEvtInterval: number;
- private timeout: any | null = null;
- private json: boolean = false;
- private heartbeatInterval: any | null = null; // 心跳定时器
- private dirtyDataCheckInterval: any | null = null; //变量同步定时器
- private evtCheckInterval: any | null = null; //事件同步定时器
- private _currentReconnectCount: number = 0;
- private _pingTime: number = 0;
- private _ping: number = 0;//ping值
- private _callbacks: { [id: string]: (result: any) => void } = {};
- private _waitSends: Array<string | ArrayBufferLike | Blob | ArrayBufferView> = [];
- private _new_resolve<T>(id: string): Promise<T> { return new Promise(resolve => this._callbacks[id] = resolve); }
- private _lv: { LowerRank: number, Rank: number, Star: number } = { LowerRank: 0, Rank: 0, Star: 0 };
- public get ownLevel(): { LowerRank: number, Rank: number, Star: number } { return this._lv };
- private _do_resolve<T>(id: string, data: T): boolean {
- const resolveCallback = this._callbacks[id];
- if (!resolveCallback) return false;
- resolveCallback(data);
- delete this._callbacks[id];
- return true;
- }
- private _team: NetTeam<GD> | null;
- private _room: NetRoom<GD> | null;
- public get dataInterval(): number { return this.gameDataInterval * 0.001 };
- public get evtInterval(): number { return this.gameEvtInterval * 0.001 };
- public get isActive(): boolean { return this._ws && this._ws.isActive };
- /**队伍信息*/
- public get team(): NetTeam<GD> {
- return this._team;
- }
- /**是否在队伍中*/
- public get inTeam(): boolean {
- return this._team != null && this._team.own != null;
- }
- /**房间信息*/
- public get room(): NetRoom<GD> {
- return this._room;
- }
- /**是否在房间中*/
- public get inRoom(): boolean {
- return this._room != null && !this._room.cloosed;
- }
- /**
- * 创建一个客户端
- */
- constructor() {
- this._waitSends = [];
- this._callbacks = {};
- }
- /**初始化
- * @param url - 连接的地址 'ws://localhost:3000'
- * @param options - 可选的配置选项对象,支持以下属性:
- * - **ca**: (可选) CA 证书字符串,用于 SSL 连接的验证。
- * - **reconnection**: (可选) 指示是否启用重连机制,默认为 `true`。
- * - **reconnectCount**: (可选) 在连接失败后重连的最大次数,默认值为 `10`。
- * - **reconnectInterval**: (可选) 每次重连之间的间隔时间,以毫秒为单位,默认值为 `2000` (2 秒)。
- * - **timeoutInterval**: (可选) 心跳断线时间,以毫秒为单位,默认值为 `30000` (30 秒)。
- * - **gameEvtInterval**:(可选) 游戏事件同步间隔,默认值为 `66` (0.06秒 1秒钟15次)。
- * - **gameDataInterval**:(可选) 游戏变量同步间隔,默认值为 `200` (0.2秒 1秒钟5次)。
- * - **json**: (可选) 是否用json序列化否则用messagepck 默认为 `false`。
- * @example
- * 自定义消息
- interface message extends message_protocol {
- useItem(userId: string, otherId: string, itemId: number): void//使用道具
- }
- 自定义数据
- export interface gd extends game_data {
- r_lv(lv: number);//关卡信息
- r_time(time: number);//关卡时间
- }
- export const net = ch.get_new_net<gd, message>();
- const url = chsdk.getUrl('/handle').replace(chsdk.getUrl('/handle').split(':')[0], 'ws');
- const token = chsdk.getToken();
- net.init(url,{query: `token=${token}`});
- */
- public init(url: string, options?: { query?: string, ca?: string, reconnection?: boolean, reconnectCount?: number, reconnectInterval?: number, timeoutInterval?: number, gameEvtInterval?: number, gameDataInterval?: number, json?: boolean }) {
- this._url = url;
- this._url = `${this._url}${options?.query?.length ? '?' + options.query : ''}`;
- this._ca = options?.ca;
- this.reconnection = options?.reconnection ?? true;
- this.reconnectCount = options?.reconnectCount ?? RECONNECT_COUNT;
- this.reconnectInterval = options?.reconnectInterval ?? RECONNECT_INTERVAL;
- this.timeoutInterval = options?.timeoutInterval ?? HEARTBEAT_TIMEOUT;
- this.gameDataInterval = options?.gameDataInterval ?? DIRTYDATACHECK_INTERVAL;
- this.gameEvtInterval = options?.gameEvtInterval ?? EVTCHECK_INTERVAL;
- this.json = options?.json ?? false;
- this._ws = new WsClient(this._url, this._ca);
- this._ws.onConnected = this._onConnected.bind(this);
- this._ws.onError = this._onError.bind(this);
- this._ws.onClosing = this._onClosing.bind(this);
- this._ws.onClosed = this._onClosed.bind(this);
- this._ws.onMessage = this._onMessage.bind(this);
- const isbuffer = typeof ArrayBuffer !== 'undefined';
- console.log('ch_net 初始化 ver:', Ver, isbuffer, this.json, this._url);
- //
- chsdk.sdk_event.on('hide', this.on_hide, this);
- chsdk.sdk_event.on('show', this.on_show, this);
- }
- /**主动断开连接*/
- public dispose(): void {
- this.state.clearAll();
- this._clear_team();
- this._clear_room();
- this._callbacks = {};
- this._waitSends.length = 0;
- this._ws.close(5000, 'client disconnect');
- chsdk.sdk_event.off('hide', this.on_hide, this);
- chsdk.sdk_event.off('show', this.on_show, this);
- }
- private on_hide(): void {
- if (!this.inRoom) return;
- this.send_data(C2S_BACKED);
- }
- private on_show(): void {
- if (!this.inRoom) return;
- this.send_data(C2S_BACKED_RETURN);
- }
- private encode(msg: any): any {
- return this.json ? JSON.stringify(msg) : msgpack.encode(msg);
- }
- private decode(medata: any): any {
- return isArrayBuffer(medata) ? msgpack.decode(new Uint8Array(medata)) : JSON.parse(medata);
- }
- private send_data(type: string, data?: any): void {
- this._send(this.encode(data ? { type: type, data: data } : { type: type }));
- }
- /**开始连接,返回null为成功,否则为错误提示*/
- public async connect(): Promise<string | null> {
- if (!this._ws) {
- chsdk.log.error('not init');
- return 'not init';
- }
- if (!this._ws.connect()) return 'no netconnect';
- this.state.emit(this.state.key.Connecting);
- return this._new_resolve('connect');
- }
- /**主动重新连接*/
- public reconnect(): string | null {
- if (!this._ws) {
- chsdk.log.error('not init');
- return 'not init';
- }
- this._currentReconnectCount = 1;
- this.do_reconnect();
- }
- private do_reconnect(): void {
- if (!this._ws.connect()) return;
- this.state.emit(this.state.key.Reconnecting, this._currentReconnectCount);
- }
- /**玩家创建队伍,返回null为成功,否则为错误提示*/
- public async creat_team(player_count: number = 4): Promise<string | null> {
- if (!this._ws) return 'no netconnect';
- if (this.inTeam) return null;
- this.send_data(C2S_SET_TEAM, player_count);
- return this._new_resolve('creat_team');
- }
- /**玩家进入队伍,返回null为成功,否则为错误提示*/
- public async join_team(password: string): Promise<string | null> {
- if (!this._ws) return 'no netconnect';
- if (this.inTeam) return null;
- this.send_data(C2S_JOIN_TEAM, { password: password });
- return this._new_resolve('join_team');
- }
- /**玩家退出队伍,返回null为成功,否则为错误提示*/
- public async exit_team(): Promise<string | null> {
- if (!this._ws) return 'no netconnect';
- if (!this.inTeam) return 'not in team';
- if (this.inRoom) return 'in game';
- this.send_data(C2S_EXIT_TEAM);
- return this._new_resolve('exit_team');
- }
- /**主机结束游戏关闭房间,成功后收到房间关闭事件*/
- public close_room(): void {
- if (!this._ws) return;
- if (!this.inRoom) return;
- if (!this.room.isHost) return;
- this.send_data(C2S_CLOSE_ROOM);
- }
- /**玩家退出房间 ,返回null为成功,否则为错误提示,退出成功后收到房间关闭事件*/
- public async exit_room(): Promise<string | null> {
- if (!this._ws) return 'no netconnect';
- if (!this.inRoom) return 'not in room';
- this.send_data(C2S_ROOM_EXIT);
- return this._new_resolve('exit_room');
- }
- private _clear_team(): void {
- this._team?.dispose();
- this._team = null;
- }
- private _clear_room(): void {
- if (!this._room) return;
- this._room?.dispose();
- this._room = null;
- }
- private _send(data: Parameters<WebSocket['send']>[0]) {
- if (!this._ws) return;
- if (this._ws.isActive) {
- this._ws.send(data);
- } else {
- this._waitSends.push(data);
- }
- }
- private _updatePlayerStatus(id: string, online: boolean) {
- if (this.inTeam) (this._team as any).updatePlayerStatus(id, online);
- if (this.inRoom) (this._room as any).updatePlayerStatus(id, online);
- }
- //
- private _onMessage(msg: MessageEvent): void {
- this.resetHeartbeat();
- try {
- const { data: medata } = msg;
- const data = this.decode(medata);
- if (data.type !== PONG) chsdk.log.log('receive', JSON.stringify(data));
- switch (data.type) {
- case PONG:
- this._ping = chsdk.date.now() - this._pingTime;
- chsdk.date.updateServerTime(data.data);
- //chsdk.log.log("pong:", this._ping, data.data, chsdk.date.now());
- break;
- case S2C_LOGIN_SUCCESS:
- this._lv = data.data;
- if (this._do_resolve('connect', null)) {
- this.state.emit(this.state.key.Connected);
- } else {
- this.state.emit(this.state.key.Reconnected);
- }
- this._callbacks = {};
- this.startHeartbeat();
- while (this._waitSends.length) {
- if (!this._ws) break;
- const data = this._waitSends.shift();
- if (data) this._ws.send(data);
- }
- break;
- case S2C_TEAM_SUCCESS:
- if (this._team) this._clear_team();
- this._team = new NetTeam<GD>(data.data, this.send_data.bind(this));
- if (!this._do_resolve('creat_team', null)) this._do_resolve('join_team', null);
- break;
- case S2C_JOIN_TEAM_FAIL:
- this._do_resolve('join_team', data.data);
- break;
- case S2C_TEAM_USER_JOIN:
- const join_user = data.data;
- join_user.status = true;
- (this._team as any).addPlayer({ key: join_user.userKey, data: join_user }, true);
- break;
- case S2C_TEAM_USER_EXIT:
- const esit_id = data.data;
- if (esit_id === this._team.own.Id) {
- (this._team as any).closed();
- this._clear_team();
- this._do_resolve('exit_team', null);
- } else {
- (this._team as any).removePlayer(esit_id);
- }
- break;
- case S2C_TEAM_CHANGE_HOST:
- (this._team as any).changeHost(data.data);
- break;
- case S2C_ROOM_CHANGE_HOST:
- (this._room as any).changeHost(data.data);
- break;
- case S2C_USER_RECONNECT:
- this._updatePlayerStatus(data.data, true);
- break;
- case S2C_USER_DISCONNECT:
- this._updatePlayerStatus(data.data, false);
- break;
- case S2C_MATCH:
- (this._team as any).match_start();
- break;
- case S2C_MATCH_CANCEL:
- (this._team as any).match_cancel();
- break;
- case S2C_NOT_READY:
- (this._team as any).not_ready();
- break;
- case S2C_READY:
- (this._team as any).updatePlayerReady(data.data, true);
- break;
- case S2C_MATCH_SUCCESS:
- this._clear_room();
- const roomData = data.data.roomData;
- const pData = data.data.playerData;
- this._room = new NetRoom<GD>(roomData, pData);
- if (this._team) (this._team as any).match_success();
- break;
- case S2C_ROOM_GAMEDATA_CHANGE:
- (this._room as any).server_change(data.data);
- break;
- case S2C_USER_GAMEDATA_CHANGE:
- const p = this._room.getPlayer(data.data.userKey);
- if (!p) break;
- (p as any).server_change(data.data.data);
- break;
- case S2C_ROOM_CLOSED:
- (this._room as any).closed(data.data);
- if (this.inTeam) {
- const list = this.room.all;
- for (let i = 0; i < list.length; i++) {
- const rp = list[i];
- if (rp.isAI) continue;
- const p = this.team.getPlayer(rp.Id);
- if (!p) continue;
- (p as any).set_level(rp.level, rp.rank, rp.score, rp.totalRank);
- }
- }
- this._do_resolve('exit_room', null);
- break;
- case S2C_TALK:
- if (this.inRoom) {
- (this._room as any).onChat(data.data.userKey, data.data.msg);
- } else if (this.inTeam) {
- (this._team as any).onChat(data.data.userKey, data.data.msg);
- }
- break;
- case S2C_FINISH:
- (this._room as any).finish(data.data.userKey, data.data.rank);
- break;
- case S2C_SETTLEMENT:
- (this._room as any).settlement(data.data);
- break;
- case C2S_MESSAGE:
- if (Array.isArray(data.data)) {
- for (let i = 0; i < data.data.length; i++) {
- const d = data.data[i];
- (this._room as any)._onEvt(d.type, d.data);
- }
- } else {
- chsdk.log.log('no def type:', data.data);
- //(this.receive as any)._emit(data.type, data.data);
- }
- break;
- default:
- break;
- }
- } catch (error) {
- chsdk.log.warn(error)
- this.state.emit(this.state.key.Error, error);
- }
- }
- private _onConnected(evt: any): void {
- if (this.timeout) clearTimeout(this.timeout);
- this._currentReconnectCount = 0;
- this.timeout = setTimeout(() => {
- this._ws.close();
- chsdk.log.error("Closing connection.");
- }, 3000);
- }
- private _onError(err: any): void {
- chsdk.log.log('err', err);
- this.state.emit(this.state.key.Error, err);
- }
- private _onClosing(): void {
- chsdk.log.log('closing');
- this.state.emit(this.state.key.Connecting);
- }
- private _onClosed(event: CloseEvent): void {
- chsdk.log.log("WebSocket connection closed", event);
- this.stopHeartbeat();
- if (!this.reconnection || (event.reason && event.code > 4000)) {
- this.state.emit(this.state.key.Closed, event);
- this._do_resolve('connect', event);
- chsdk.log.log("WebSocket connection closed", event);
- return;
- }
- if (this._currentReconnectCount < this.reconnectCount) {
- this._currentReconnectCount += 1;
- chsdk.log.log(`Reconnecting... Attempt ${this._currentReconnectCount}`);
- setTimeout(() => { this.do_reconnect() }, this.reconnectInterval)
- } else {
- chsdk.log.error("Max reconnect attempts reached. Giving up.");
- this.state.emit(this.state.key.Closed, event);
- this._do_resolve('connect', event);
- }
- }
- private startHeartbeat() {
- this.heartbeatInterval = setInterval(() => {
- this.sendHeartbeat();
- }, HEARTBEAT_INTERVAL);
- this.dirtyDataCheckInterval = setInterval(() => {
- this.dirtyDataCheck();
- }, this.gameDataInterval);
- this.evtCheckInterval = setInterval(() => {
- this.evtCheck();
- }, this.gameEvtInterval);
- }
- private resetHeartbeat() {
- if (this.timeout) clearTimeout(this.timeout);
- this.timeout = setTimeout(() => {
- chsdk.log.error("Heartbeat timeout. Closing connection.");
- this._ws.close();
- }, this.timeoutInterval);
- }
- private sendHeartbeat() {
- this._pingTime = chsdk.date.now();
- this.send_data(PING, this._ping);
- }
- private stopHeartbeat() {
- if (this.heartbeatInterval) clearInterval(this.heartbeatInterval);
- if (this.timeout) clearTimeout(this.timeout);
- if (this.dirtyDataCheckInterval) clearInterval(this.dirtyDataCheckInterval);
- if (this.evtCheckInterval) clearInterval(this.evtCheckInterval);
- }
- private evtCheck() {
- if (this.inRoom) {
- (this.room as any).doSendChat((msg: string) => {
- if (!msg) return;
- this.send_data(C2S_TALK, msg);
- });
- (this.room as any).doSendMode((mode0, mode1, mode2) => {
- if (mode0.length > 0) this.send_data(C2S_MESSAGE, mode0);
- if (mode1.length > 0) this.send_data(C2S_MESSAGE_TO_HOST, mode1);
- if (mode2.length > 0) this.send_data(C2S_MESSAGE_TO_OTHER, mode2);
- });
- const ps = this.room.all;
- for (let i = 0; i < ps.length; i++) {
- const p = ps[i];
- (p as any).doFinishGame(() => { this.send_data(C2S_FINISH, p.Id); });
- }
- } else if (this.inTeam) {
- (this.team as any).doSendChat((msg: string) => {
- if (!msg) return;
- this.send_data(C2S_TALK, msg);
- });
- }
- }
- private dirtyDataCheck() {
- if (!this.inRoom) return;
- (this.room.own as any).doDirtyData((dirty) => {
- this.send_data(C2S_UPDATE_USER_GAMEDATA, { userKey: this.room.own.Id, data: dirty });
- })
- if (!this.room.isHost) return;
- (this._room as any).doDirtyData((dirty) => {
- this.send_data(C2S_UPDATE_ROOM_GAMEDATA, dirty);
- })
- const ais = this.room.all;
- for (let i = 0; i < ais.length; i++) {
- const ai = ais[i];
- (ai as any).doDirtyData((dirty) => {
- this.send_data(C2S_UPDATE_USER_GAMEDATA, { userKey: ai.Id, data: dirty });
- })
- }
- }
- /**
- * 分享队伍信息,邀请进队
- * @param extend (可选)分享数据
- * @param title 分享显示标题
- * @param imageUrl 分享显示图片
- */
- public shareNetTeam<T extends { [key: string]: any }>(title?: string, imageUrl?: string, extend?: T) {
- if (!this.inTeam) return;
- chsdk.shareAppMessage(title, '', imageUrl, JSON.stringify({ type: 'NetTeam', pw: this.team.Password, extends: extend }));
- }
- /**
- *获取从好友分享的net数据进入游戏的数据
- */
- public getShareNetTeam<T extends { [key: string]: any }>(): { password: string, extend?: T } {
- const query = chsdk.getQuery();
- if (!query) return null;
- const message = query.message;
- if (!message) return null;
- const data = JSON.parse(message);
- if (!data) return null;
- if (data.type != 'NetTeam') return null;
- query.message = null;
- return { password: data.pw, extend: data.extends as T };
- }
- }
|