refactor
This commit is contained in:
		| @@ -8,7 +8,6 @@ export abstract class EntityManager extends Component { | |||||||
|   fsm: StateMachine |   fsm: StateMachine | ||||||
|   private _state: EntityStateEnum |   private _state: EntityStateEnum | ||||||
|  |  | ||||||
|  |  | ||||||
|   get state() { |   get state() { | ||||||
|     return this._state |     return this._state | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import { _decorator, Animation, Component } from 'cc' | import { _decorator, Animation, Component } from 'cc' | ||||||
| import { EntityTypeEnum, FsmParamTypeEnum } from '../Enum' | import { EntityTypeEnum } from '../Common' | ||||||
|  | import { FsmParamTypeEnum } from '../Enum' | ||||||
| const { ccclass } = _decorator | const { ccclass } = _decorator | ||||||
| import State from './State' | import State from './State' | ||||||
| import SubStateMachine from './SubStateMachine' | import SubStateMachine from './SubStateMachine' | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| import { _decorator, instantiate, ProgressBar, Label, Vec3, Tween, tween } from 'cc'; | import { _decorator, instantiate, ProgressBar, Label, Vec3, Tween, tween, director } from 'cc'; | ||||||
| import { EntityManager } from '../../Base/EntityManager'; | import { EntityManager } from '../../Base/EntityManager'; | ||||||
| import { ApiMsgEnum, EntityTypeEnum, IActor, InputTypeEnum, IVec2, toFixed } from '../../Common'; | import { ApiMsgEnum, EntityTypeEnum, IActor, InputTypeEnum, IVec2, toFixed } from '../../Common'; | ||||||
| import { EntityStateEnum } from '../../Enum'; | import { EntityStateEnum, EventEnum, SceneEnum } from '../../Enum'; | ||||||
| import DataManager from '../../Global/DataManager'; | import DataManager from '../../Global/DataManager'; | ||||||
|  | import EventManager from '../../Global/EventManager'; | ||||||
| import NetworkManager from '../../Global/NetworkManager'; | import NetworkManager from '../../Global/NetworkManager'; | ||||||
| import { rad2Angle } from '../../Utils'; | import { rad2Angle } from '../../Utils'; | ||||||
| import { WeaponManager } from '../Weapon/WeaponManager'; | import { WeaponManager } from '../Weapon/WeaponManager'; | ||||||
| @@ -30,6 +31,8 @@ export class ActorManager extends EntityManager implements IActor { | |||||||
|     private tw: Tween<any> |     private tw: Tween<any> | ||||||
|     private targetPos: Vec3 |     private targetPos: Vec3 | ||||||
|  |  | ||||||
|  |     private isDead = false | ||||||
|  |  | ||||||
|     get isSelf() { |     get isSelf() { | ||||||
|         return DataManager.Instance.myPlayerId === this.id |         return DataManager.Instance.myPlayerId === this.id | ||||||
|     } |     } | ||||||
| @@ -60,11 +63,17 @@ export class ActorManager extends EntityManager implements IActor { | |||||||
|         this.node.active = false |         this.node.active = false | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     tick(dt: number) { |     async tick(dt: number) { | ||||||
|         if (!this.isSelf) { |         if (!this.isSelf) { | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (this.hp <= 0 && !this.isDead) { | ||||||
|  |             EventManager.Instance.emit(EventEnum.GameEnd) | ||||||
|  |             this.isDead = true | ||||||
|  |             return | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (DataManager.Instance.jm.input.length()) { |         if (DataManager.Instance.jm.input.length()) { | ||||||
|             const { x, y } = DataManager.Instance.jm.input |             const { x, y } = DataManager.Instance.jm.input | ||||||
|             NetworkManager.Instance.sendMsg(ApiMsgEnum.MsgClientSync, { |             NetworkManager.Instance.sendMsg(ApiMsgEnum.MsgClientSync, { | ||||||
| @@ -87,6 +96,7 @@ export class ActorManager extends EntityManager implements IActor { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderHP(data: IActor) { |     renderHP(data: IActor) { | ||||||
|  |         this.hp = data.hp | ||||||
|         this.hpBar.progress = data.hp / this.hpBar.totalLength |         this.hpBar.progress = data.hp / this.hpBar.totalLength | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ export enum EventEnum { | |||||||
|   ExplosionBorn = 'ExplosionBorn', |   ExplosionBorn = 'ExplosionBorn', | ||||||
|   RoomJoin = 'RoomJoin', |   RoomJoin = 'RoomJoin', | ||||||
|   GameStart = 'GameStart', |   GameStart = 'GameStart', | ||||||
|  |   GameEnd = 'GameEnd', | ||||||
| } | } | ||||||
|  |  | ||||||
| export enum PrefabPathEnum { | export enum PrefabPathEnum { | ||||||
|   | |||||||
| @@ -16,25 +16,36 @@ const WEAPON_DAMAGE = 5 | |||||||
| const PLAYER_RADIUS = 50 | const PLAYER_RADIUS = 50 | ||||||
| const BULLET_RADIUS = 10 | const BULLET_RADIUS = 10 | ||||||
|  |  | ||||||
|  | const mapW = 960 | ||||||
|  | const mapH = 640 | ||||||
|  |  | ||||||
| export default class DataManager extends Singleton { | export default class DataManager extends Singleton { | ||||||
|   static get Instance() { |   static get Instance() { | ||||||
|     return super.GetInstance<DataManager>() |     return super.GetInstance<DataManager>() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //登陆数据 | ||||||
|  |   myPlayerId = 1 | ||||||
|  |  | ||||||
|  |   //大厅数据 | ||||||
|  |   roomInfo: IRoom | ||||||
|  |  | ||||||
|  |   //游戏数据 | ||||||
|   stage: Node |   stage: Node | ||||||
|   jm: JoyStickManager |   jm: JoyStickManager | ||||||
|  |  | ||||||
|   prefabMap: Map<string, Prefab> = new Map() |   prefabMap: Map<string, Prefab> = new Map() | ||||||
|   textureMap: Map<string, SpriteFrame[]> = new Map() |   textureMap: Map<string, SpriteFrame[]> = new Map() | ||||||
|  |  | ||||||
|   actorMap: Map<number, ActorManager> = new Map() |   actorMap: Map<number, ActorManager> = new Map() | ||||||
|   bulletMap: Map<number, BulletManager> = new Map() |   bulletMap: Map<number, BulletManager> = new Map() | ||||||
|  |  | ||||||
|   myPlayerId = 1 |   reset() { | ||||||
|   roomInfo: IRoom |     this.stage = null | ||||||
|   mapSize = { |     this.jm = null | ||||||
|     x: 960, |     this.actorMap.clear() | ||||||
|     y: 640, |     this.bulletMap.clear() | ||||||
|  |     this.prefabMap.clear() | ||||||
|  |     this.textureMap.clear() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   state: IState = { |   state: IState = { | ||||||
| @@ -85,8 +96,8 @@ export default class DataManager extends Singleton { | |||||||
|         player.position.x += toFixed(x * PLAYER_SPEED * dt) |         player.position.x += toFixed(x * PLAYER_SPEED * dt) | ||||||
|         player.position.y += toFixed(y * PLAYER_SPEED * dt) |         player.position.y += toFixed(y * PLAYER_SPEED * dt) | ||||||
|  |  | ||||||
|         player.position.x = clamp(player.position.x, -this.mapSize.x / 2, this.mapSize.x / 2) |         player.position.x = clamp(player.position.x, -mapW / 2, mapW / 2) | ||||||
|         player.position.y = clamp(player.position.y, -this.mapSize.y / 2, this.mapSize.y / 2) |         player.position.y = clamp(player.position.y, -mapH / 2, mapH / 2) | ||||||
|  |  | ||||||
|         player.direction = { x, y } |         player.direction = { x, y } | ||||||
|         break |         break | ||||||
| @@ -124,7 +135,7 @@ export default class DataManager extends Singleton { | |||||||
|               break |               break | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|           if (Math.abs(bullet.position.x) > this.mapSize.x / 2 || Math.abs(bullet.position.y) > this.mapSize.y / 2) { |           if (Math.abs(bullet.position.x) > mapW / 2 || Math.abs(bullet.position.y) > mapH / 2) { | ||||||
|             EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, { |             EventManager.Instance.emit(EventEnum.ExplosionBorn, bullet.id, { | ||||||
|               x: bullet.position.x, |               x: bullet.position.x, | ||||||
|               y: bullet.position.y, |               y: bullet.position.y, | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ import Singleton from '../Base/Singleton' | |||||||
| import { EventEnum } from '../Enum'; | import { EventEnum } from '../Enum'; | ||||||
|  |  | ||||||
| interface IItem { | interface IItem { | ||||||
|   func: Function; |   cb: Function; | ||||||
|   ctx: unknown; |   ctx: unknown; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -13,25 +13,25 @@ export default class EventManager extends Singleton { | |||||||
|  |  | ||||||
|   private map: Map<EventEnum, Array<IItem>> = new Map(); |   private map: Map<EventEnum, Array<IItem>> = new Map(); | ||||||
|  |  | ||||||
|   on(event: EventEnum, func: Function, ctx?: unknown) { |   on(event: EventEnum, cb: Function, ctx: unknown) { | ||||||
|     if (this.map.has(event)) { |     if (this.map.has(event)) { | ||||||
|       this.map.get(event).push({ func, ctx }); |       this.map.get(event).push({ cb, ctx }); | ||||||
|     } else { |     } else { | ||||||
|       this.map.set(event, [{ func, ctx }]); |       this.map.set(event, [{ cb, ctx }]); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   off(event: EventEnum, func: Function, ctx?: unknown) { |   off(event: EventEnum, cb: Function, ctx: unknown) { | ||||||
|     if (this.map.has(event)) { |     if (this.map.has(event)) { | ||||||
|       const index = this.map.get(event).findIndex(i => func === i.func && i.ctx === ctx); |       const index = this.map.get(event).findIndex(i => cb === i.cb && i.ctx === ctx); | ||||||
|       index > -1 && this.map.get(event).splice(index, 1); |       index > -1 && this.map.get(event).splice(index, 1); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   emit(event: EventEnum, ...params: unknown[]) { |   emit(event: EventEnum, ...params: unknown[]) { | ||||||
|     if (this.map.has(event)) { |     if (this.map.has(event)) { | ||||||
|       this.map.get(event).forEach(({ func, ctx }) => { |       this.map.get(event).forEach(({ cb, ctx }) => { | ||||||
|         ctx ? func.apply(ctx, params) : func(...params); |         cb.apply(ctx, params) | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,9 +1,14 @@ | |||||||
| import Singleton from '../Base/Singleton' | import Singleton from '../Base/Singleton' | ||||||
| import { ApiMsgEnum, IModel, strdecode, strencode } from '../Common'; | import { ApiMsgEnum, IModel } from '../Common'; | ||||||
| import { binaryEncode, binaryDecode } from '../Common/Binary'; | import { binaryEncode, binaryDecode } from '../Common/Binary'; | ||||||
|  |  | ||||||
| const TIMEOUT = 5000 | const TIMEOUT = 5000 | ||||||
|  |  | ||||||
|  | interface IItem { | ||||||
|  |   cb: Function; | ||||||
|  |   ctx: unknown; | ||||||
|  | } | ||||||
|  |  | ||||||
| export interface ICallApiRet<T> { | export interface ICallApiRet<T> { | ||||||
|   success: boolean; |   success: boolean; | ||||||
|   error?: Error; |   error?: Error; | ||||||
| @@ -18,7 +23,7 @@ export default class NetworkManager extends Singleton { | |||||||
|  |  | ||||||
|   ws: WebSocket |   ws: WebSocket | ||||||
|   port = 8888 |   port = 8888 | ||||||
|   maps: Map<ApiMsgEnum, Function[]> = new Map() |   maps: Map<ApiMsgEnum, Array<IItem>> = new Map() | ||||||
|   isConnected = false |   isConnected = false | ||||||
|  |  | ||||||
|   connect() { |   connect() { | ||||||
| @@ -28,16 +33,17 @@ export default class NetworkManager extends Singleton { | |||||||
|         return |         return | ||||||
|       } |       } | ||||||
|       this.ws = new WebSocket(`ws://localhost:${this.port}`) |       this.ws = new WebSocket(`ws://localhost:${this.port}`) | ||||||
|  |       //onmessage接受的数据类型,只有在后端返回字节数组的时候才有效果 | ||||||
|       this.ws.binaryType = 'arraybuffer'; |       this.ws.binaryType = 'arraybuffer'; | ||||||
|  |  | ||||||
|       this.ws.onopen = () => { |       this.ws.onopen = () => { | ||||||
|         console.log("ws onopen") |  | ||||||
|         this.isConnected = true |         this.isConnected = true | ||||||
|         resolve(true) |         resolve(true) | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       this.ws.onerror = () => { |       this.ws.onerror = (e) => { | ||||||
|         this.isConnected = false |         this.isConnected = false | ||||||
|  |         console.log(e) | ||||||
|         reject("ws onerror") |         reject("ws onerror") | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -53,12 +59,11 @@ export default class NetworkManager extends Singleton { | |||||||
|           try { |           try { | ||||||
|             if (this.maps.has(name) && this.maps.get(name).length) { |             if (this.maps.has(name) && this.maps.get(name).length) { | ||||||
|               console.log(json); |               console.log(json); | ||||||
|               this.maps.get(name).forEach(cb => cb(data)) |               this.maps.get(name).forEach(({ cb, ctx }) => cb.call(ctx, data)) | ||||||
|             } |             } | ||||||
|           } catch (error) { |           } catch (error) { | ||||||
|             console.log("this.maps.get(name).forEach(cb => cb(restData))", error) |             console.log("onmessage:", error) | ||||||
|           } |           } | ||||||
|  |  | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|           console.log('解析失败,不是合法的JSON格式', error) |           console.log('解析失败,不是合法的JSON格式', error) | ||||||
|         } |         } | ||||||
| @@ -72,20 +77,19 @@ export default class NetworkManager extends Singleton { | |||||||
|         // 超时处理 |         // 超时处理 | ||||||
|         const timer = setTimeout(() => { |         const timer = setTimeout(() => { | ||||||
|           resolve({ success: false, error: new Error('timeout') }) |           resolve({ success: false, error: new Error('timeout') }) | ||||||
|           this.unlistenMsg(name, cb) |           this.unlistenMsg(name as any, cb, null) | ||||||
|         }, TIMEOUT) |         }, TIMEOUT) | ||||||
|  |  | ||||||
|         // 回调处理 |         // 回调处理 | ||||||
|         const cb = (res) => { |         const cb = (res) => { | ||||||
|           resolve(res) |           resolve(res) | ||||||
|           clearTimeout(timer) |           clearTimeout(timer) | ||||||
|           this.unlistenMsg(name, cb) |           this.unlistenMsg(name as any, cb, null) | ||||||
|         } |         } | ||||||
|         this.listenMsg(name as any, cb) |         this.listenMsg(name as any, cb, null) | ||||||
|  |  | ||||||
|         this.sendMsg(name as any, data) |         this.sendMsg(name as any, data) | ||||||
|       } catch (error) { |       } catch (error) { | ||||||
|         console.log(error) |  | ||||||
|         resolve({ success: false, error: error as Error }) |         resolve({ success: false, error: error as Error }) | ||||||
|       } |       } | ||||||
|     }) |     }) | ||||||
| @@ -98,18 +102,19 @@ export default class NetworkManager extends Singleton { | |||||||
|     this.ws.send(view.buffer) |     this.ws.send(view.buffer) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void) { |   listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) { | ||||||
|     if (this.maps.has(name)) { |     if (this.maps.has(name)) { | ||||||
|       this.maps.get(name).push(cb) |       this.maps.get(name).push({ ctx, cb }) | ||||||
|     } else { |     } else { | ||||||
|       this.maps.set(name, [cb]) |       this.maps.set(name, [{ ctx, cb }]) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   unlistenMsg(name: ApiMsgEnum, cb: Function) { |   unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) { | ||||||
|     if (this.maps.has(name)) { |     if (this.maps.has(name)) { | ||||||
|       const index = this.maps.get(name).indexOf(cb) |       const items = this.maps.get(name) | ||||||
|       index > -1 && this.maps.get(name).splice(index, 1) |       const index = items.findIndex(i => cb === i.cb && i.ctx === ctx); | ||||||
|  |       index > -1 && items.splice(index, 1) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,6 +15,11 @@ export default class ObjectPoolManager extends Singleton { | |||||||
|     return objectName + 'Pool' |     return objectName + 'Pool' | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   reset() { | ||||||
|  |     this.objectPool = null | ||||||
|  |     this.map.clear() | ||||||
|  |   } | ||||||
|  |  | ||||||
|   get(objectName: EntityTypeEnum) { |   get(objectName: EntityTypeEnum) { | ||||||
|     if (this.objectPool === null) { |     if (this.objectPool === null) { | ||||||
|       this.objectPool = new Node("ObjectPool") |       this.objectPool = new Node("ObjectPool") | ||||||
|   | |||||||
| @@ -1,37 +1,52 @@ | |||||||
| import { _decorator, Component, Node, Prefab, instantiate, SpriteFrame } from 'cc'; | import { _decorator, Component, Node, Prefab, instantiate, SpriteFrame, director } from 'cc'; | ||||||
| import { ActorManager } from '../Entity/Actor/ActorManager'; | import { ActorManager } from '../Entity/Actor/ActorManager'; | ||||||
| import DataManager from '../Global/DataManager'; | import DataManager from '../Global/DataManager'; | ||||||
| import { JoyStickManager } from '../UI/JoyStickManager'; | import { JoyStickManager } from '../UI/JoyStickManager'; | ||||||
| import { ResourceManager } from '../Global/ResourceManager'; | import { ResourceManager } from '../Global/ResourceManager'; | ||||||
| import { PrefabPathEnum, TexturePathEnum } from '../Enum'; | import { EventEnum, PrefabPathEnum, SceneEnum, TexturePathEnum } from '../Enum'; | ||||||
| import NetworkManager from '../Global/NetworkManager'; | import NetworkManager from '../Global/NetworkManager'; | ||||||
| import ObjectPoolManager from '../Global/ObjectPoolManager'; | import ObjectPoolManager from '../Global/ObjectPoolManager'; | ||||||
| import { BulletManager } from '../Entity/Bullet/BulletManager'; | import { BulletManager } from '../Entity/Bullet/BulletManager'; | ||||||
| import { ApiMsgEnum, EntityTypeEnum, IMsgServerSync, InputTypeEnum } from '../Common'; | import { ApiMsgEnum, EntityTypeEnum, IMsgServerSync, InputTypeEnum } from '../Common'; | ||||||
|  | import EventManager from '../Global/EventManager'; | ||||||
|  |  | ||||||
| const { ccclass } = _decorator; | const { ccclass } = _decorator; | ||||||
|  |  | ||||||
| @ccclass('BattleManager') | @ccclass('BattleManager') | ||||||
| export class BattleManager extends Component { | export class BattleManager extends Component { | ||||||
|     stage: Node |     private stage: Node | ||||||
|     ui: Node |     private ui: Node | ||||||
|     isInited = false |     private shouldUpdate = false | ||||||
|     onLoad() { |  | ||||||
|         this.stage = DataManager.Instance.stage = this.node.getChildByName("Stage") |  | ||||||
|         this.ui = this.node.getChildByName("UI") |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async start() { |     async start() { | ||||||
|  |         //清空 | ||||||
|         this.clearGame() |         this.clearGame() | ||||||
|         await this.loadRes() |  | ||||||
|         this.initScene() |         //资源加载和网络连接同步执行 | ||||||
|         await this.connectServer() |         await Promise.all([this.loadRes(), this.connectServer()]) | ||||||
|  |  | ||||||
|  |         this.initGame() | ||||||
|  |  | ||||||
|         // 在场景初始化完毕之前,卡主别的玩家,准备好以后再告知服务器,等所有玩家都准备好以后才开始,这里就不做了 |         // 在场景初始化完毕之前,卡主别的玩家,准备好以后再告知服务器,等所有玩家都准备好以后才开始,这里就不做了 | ||||||
|         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgServerSync, this.handleSync); |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgServerSync, this.handleSync, this); | ||||||
|         this.isInited = true |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgGameEnd, this.leaveGame, this); | ||||||
|  |         EventManager.Instance.on(EventEnum.GameEnd, this.handleGameEnd, this) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     clearGame() { |     clearGame() { | ||||||
|  |         //监听 | ||||||
|  |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgServerSync, this.handleSync, this); | ||||||
|  |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgGameEnd, this.leaveGame, this); | ||||||
|  |         EventManager.Instance.off(EventEnum.GameEnd, this.handleGameEnd, this) | ||||||
|  |  | ||||||
|  |         //数据 | ||||||
|  |         this.shouldUpdate = false | ||||||
|  |         ObjectPoolManager.Instance.reset() | ||||||
|  |         DataManager.Instance.reset() | ||||||
|  |  | ||||||
|  |         //节点 | ||||||
|  |         this.stage = DataManager.Instance.stage = this.node.getChildByName("Stage") | ||||||
|  |         this.ui = this.node.getChildByName("UI") | ||||||
|         this.stage.destroyAllChildren() |         this.stage.destroyAllChildren() | ||||||
|         this.ui.destroyAllChildren() |         this.ui.destroyAllChildren() | ||||||
|     } |     } | ||||||
| @@ -53,12 +68,6 @@ export class BattleManager extends Component { | |||||||
|         await Promise.all(list) |         await Promise.all(list) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async initScene() { |  | ||||||
|         this.initJoyStick() |  | ||||||
|         this.initShoot() |  | ||||||
|         this.initMap() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async connectServer() { |     async connectServer() { | ||||||
|         if (!await NetworkManager.Instance.connect().catch(() => false)) { |         if (!await NetworkManager.Instance.connect().catch(() => false)) { | ||||||
|             await new Promise((resolve) => setTimeout(resolve, 1000)) |             await new Promise((resolve) => setTimeout(resolve, 1000)) | ||||||
| @@ -66,6 +75,26 @@ export class BattleManager extends Component { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     leaveGame() { | ||||||
|  |         this.clearGame() | ||||||
|  |         director.loadScene(SceneEnum.Hall); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async handleGameEnd() { | ||||||
|  |         const { success, res, error } = await NetworkManager.Instance.callApi(ApiMsgEnum.ApiGameEnd, { rid: DataManager.Instance.roomInfo.id }) | ||||||
|  |         if (!success) { | ||||||
|  |             console.log(error) | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async initGame() { | ||||||
|  |         this.initJoyStick() | ||||||
|  |         this.initShoot() | ||||||
|  |         this.initMap() | ||||||
|  |         this.shouldUpdate = true | ||||||
|  |     } | ||||||
|  |  | ||||||
|     initJoyStick() { |     initJoyStick() { | ||||||
|         const prefab = DataManager.Instance.prefabMap.get(EntityTypeEnum.JoyStick) |         const prefab = DataManager.Instance.prefabMap.get(EntityTypeEnum.JoyStick) | ||||||
|         const joySitck = instantiate(prefab) |         const joySitck = instantiate(prefab) | ||||||
| @@ -86,14 +115,8 @@ export class BattleManager extends Component { | |||||||
|         map.setParent(this.stage) |         map.setParent(this.stage) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     handleSync(inputs: IMsgServerSync) { |  | ||||||
|         for (const input of inputs) { |  | ||||||
|             DataManager.Instance.applyInput(input) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     update(dt: number) { |     update(dt: number) { | ||||||
|         if (!this.isInited) { |         if (!this.shouldUpdate) { | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
|         this.render() |         this.render() | ||||||
| @@ -158,5 +181,12 @@ export class BattleManager extends Component { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     handleSync(inputs: IMsgServerSync) { | ||||||
|  |         for (const input of inputs) { | ||||||
|  |             DataManager.Instance.applyInput(input) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,14 +25,14 @@ export class HallManager extends Component { | |||||||
|     onLoad() { |     onLoad() { | ||||||
|         director.preloadScene(SceneEnum.Room); |         director.preloadScene(SceneEnum.Room); | ||||||
|         EventManager.Instance.on(EventEnum.RoomJoin, this.joinRoom, this) |         EventManager.Instance.on(EventEnum.RoomJoin, this.joinRoom, this) | ||||||
|         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgPlayerList, this.renderPlayers); |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgPlayerList, this.renderPlayers, this); | ||||||
|         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgRoomList, this.renderRooms); |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgRoomList, this.renderRooms, this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     onDestroy() { |     onDestroy() { | ||||||
|         EventManager.Instance.off(EventEnum.RoomJoin, this.joinRoom, this) |         EventManager.Instance.off(EventEnum.RoomJoin, this.joinRoom, this) | ||||||
|         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgPlayerList, this.renderPlayers); |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgPlayerList, this.renderPlayers, this); | ||||||
|         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgRoomList, this.renderRooms); |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgRoomList, this.renderRooms, this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     start() { |     start() { | ||||||
|   | |||||||
| @@ -1,8 +1,7 @@ | |||||||
| import { _decorator, Component, Node, Prefab, director, instantiate } from 'cc'; | import { _decorator, Component, Node, Prefab, director, instantiate } from 'cc'; | ||||||
| import { ApiMsgEnum, IMsgGameStart, IMsgRoom } from '../Common'; | import { ApiMsgEnum, IMsgGameStart, IMsgRoom } from '../Common'; | ||||||
| import { EventEnum, SceneEnum } from '../Enum'; | import { SceneEnum } from '../Enum'; | ||||||
| import DataManager from '../Global/DataManager'; | import DataManager from '../Global/DataManager'; | ||||||
| import EventManager from '../Global/EventManager'; |  | ||||||
| import NetworkManager from '../Global/NetworkManager'; | import NetworkManager from '../Global/NetworkManager'; | ||||||
| import { PlayerManager } from '../UI/PlayerManager'; | import { PlayerManager } from '../UI/PlayerManager'; | ||||||
| const { ccclass, property } = _decorator; | const { ccclass, property } = _decorator; | ||||||
| @@ -17,13 +16,13 @@ export class RoomManager extends Component { | |||||||
|  |  | ||||||
|     onLoad() { |     onLoad() { | ||||||
|         director.preloadScene(SceneEnum.Battle); |         director.preloadScene(SceneEnum.Battle); | ||||||
|         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgRoom, this.renderPlayers); |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgRoom, this.renderPlayers, this); | ||||||
|         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgGameStart, this.startGame); |         NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgGameStart, this.handleGameStart, this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     onDestroy() { |     onDestroy() { | ||||||
|         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgRoom, this.renderPlayers); |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgRoom, this.renderPlayers, this); | ||||||
|         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgGameStart, this.startGame); |         NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgGameStart, this.handleGameStart, this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async start() { |     async start() { | ||||||
| @@ -32,7 +31,7 @@ export class RoomManager extends Component { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderPlayers = ({ room: { players: list } }: IMsgRoom) => { |     renderPlayers({ room: { players: list } }: IMsgRoom) { | ||||||
|         for (const item of this.playerContainer.children) { |         for (const item of this.playerContainer.children) { | ||||||
|             item.active = false |             item.active = false | ||||||
|         } |         } | ||||||
| @@ -67,13 +66,10 @@ export class RoomManager extends Component { | |||||||
|             console.log(error) |             console.log(error) | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // director.loadScene(SceneEnum.Battle); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     startGame = ({ state }: IMsgGameStart) => { |     handleGameStart({ state }: IMsgGameStart) { | ||||||
|         DataManager.Instance.state = state |         DataManager.Instance.state = state | ||||||
|  |  | ||||||
|         director.loadScene(SceneEnum.Battle); |         director.loadScene(SceneEnum.Battle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ export class RoomManager extends Component { | |||||||
|   init({ id, players }: { id: number, players: Array<{ id: number, nickname: string }> }) { |   init({ id, players }: { id: number, players: Array<{ id: number, nickname: string }> }) { | ||||||
|     this.id = id |     this.id = id | ||||||
|     const label = this.getComponent(Label) |     const label = this.getComponent(Label) | ||||||
|     label.string = `房间id:${id},当前人数:${players.length}` |     label.string = `房间id:${id},当前人数:${players.length}` | ||||||
|     this.node.active = true |     this.node.active = true | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,10 @@ | |||||||
| import { IPlayer, IRoom } from "./Model" | export interface IPlayer { | ||||||
|  |   id: number, nickname: string, rid: number | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface IRoom { | ||||||
|  |   id: number, players: Array<IPlayer> | ||||||
|  | } | ||||||
|  |  | ||||||
| export interface IApiPlayerListReq { | export interface IApiPlayerListReq { | ||||||
| } | } | ||||||
| @@ -47,3 +53,9 @@ export interface IApiGameStartReq { | |||||||
| } | } | ||||||
|  |  | ||||||
| export interface IApiGameStartRes { } | export interface IApiGameStartRes { } | ||||||
|  |  | ||||||
|  | export interface IApiGameEndReq { | ||||||
|  |   rid: number | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface IApiGameEndRes { } | ||||||
| @@ -22,10 +22,12 @@ export enum ApiMsgEnum { | |||||||
|   ApiRoomJoin, |   ApiRoomJoin, | ||||||
|   ApiRoomLeave, |   ApiRoomLeave, | ||||||
|   ApiGameStart, |   ApiGameStart, | ||||||
|  |   ApiGameEnd, | ||||||
|   MsgPlayerList, |   MsgPlayerList, | ||||||
|   MsgRoomList, |   MsgRoomList, | ||||||
|   MsgRoom, |   MsgRoom, | ||||||
|   MsgGameStart, |   MsgGameStart, | ||||||
|  |   MsgGameEnd, | ||||||
|   MsgClientSync, |   MsgClientSync, | ||||||
|   MsgServerSync, |   MsgServerSync, | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,9 +1,50 @@ | |||||||
|  | import { IApiGameEndReq, IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes, IApiGameEndRes } from './Api' | ||||||
|  | import { ApiMsgEnum } from './Enum' | ||||||
|  | import { IMsgClientSync, IMsgGameEnd, IMsgGameStart, IMsgPlayerList, IMsgRoom, IMsgRoomList, IMsgServerSync } from './Msg' | ||||||
|  |  | ||||||
| export interface IPlayer { | export interface IModel { | ||||||
|   id: number, nickname: string, rid: number |   api: { | ||||||
| } |     [ApiMsgEnum.ApiPlayerJoin]: { | ||||||
|  |       req: IApiPlayerJoinReq, | ||||||
| export interface IRoom { |       res: IApiPlayerJoinRes, | ||||||
|   id: number, players: Array<IPlayer> |     } | ||||||
|  |     [ApiMsgEnum.ApiPlayerList]: { | ||||||
|  |       req: IApiPlayerListReq, | ||||||
|  |       res: IApiPlayerListRes, | ||||||
|  |     } | ||||||
|  |     [ApiMsgEnum.ApiRoomList]: { | ||||||
|  |       req: IApiRoomListReq, | ||||||
|  |       res: IApiRoomListRes, | ||||||
|  |     } | ||||||
|  |     [ApiMsgEnum.ApiRoomCreate]: { | ||||||
|  |       req: IApiRoomCreateReq, | ||||||
|  |       res: IApiRoomCreateRes, | ||||||
|  |     } | ||||||
|  |     [ApiMsgEnum.ApiRoomJoin]: { | ||||||
|  |       req: IApiRoomJoinReq, | ||||||
|  |       res: IApiRoomJoinRes, | ||||||
|  |     } | ||||||
|  |     [ApiMsgEnum.ApiRoomLeave]: { | ||||||
|  |       req: IApiRoomLeaveReq, | ||||||
|  |       res: IApiRoomLeaveRes, | ||||||
|  |     } | ||||||
|  |     [ApiMsgEnum.ApiGameStart]: { | ||||||
|  |       req: IApiGameStartReq, | ||||||
|  |       res: IApiGameStartRes, | ||||||
|  |     }, | ||||||
|  |     [ApiMsgEnum.ApiGameEnd]: { | ||||||
|  |       req: IApiGameEndReq, | ||||||
|  |       res: IApiGameEndRes, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   msg: { | ||||||
|  |     [ApiMsgEnum.MsgPlayerList]: IMsgPlayerList | ||||||
|  |     [ApiMsgEnum.MsgRoomList]: IMsgRoomList, | ||||||
|  |     [ApiMsgEnum.MsgRoom]: IMsgRoom, | ||||||
|  |     [ApiMsgEnum.MsgGameStart]: IMsgGameStart, | ||||||
|  |     [ApiMsgEnum.MsgGameEnd]: IMsgGameEnd, | ||||||
|  |     [ApiMsgEnum.MsgClientSync]: IMsgClientSync, | ||||||
|  |     [ApiMsgEnum.MsgServerSync]: IMsgServerSync, | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| import { IPlayer, IRoom } from "./Model" | import { IPlayer, IRoom } from "./Api" | ||||||
| import { IClientInput, IState } from "./State" | import { IClientInput, IState } from "./State" | ||||||
|  |  | ||||||
| export interface IMsgPlayerList { | export interface IMsgPlayerList { | ||||||
| @@ -22,6 +22,10 @@ export interface IMsgGameStart { | |||||||
|   state: IState |   state: IState | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface IMsgGameEnd { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| export type IMsgClientSync = IClientInput | export type IMsgClientSync = IClientInput | ||||||
|  |  | ||||||
| export type IMsgServerSync = Array<IClientInput> | export type IMsgServerSync = Array<IClientInput> | ||||||
| @@ -7,36 +7,43 @@ export default class Room { | |||||||
|   id: number |   id: number | ||||||
|   players: Set<Player> = new Set() |   players: Set<Player> = new Set() | ||||||
|   lastSyncTime?: number |   lastSyncTime?: number | ||||||
|   timers: NodeJS.Timer[] = [] |  | ||||||
|  |  | ||||||
|  |   private timers: NodeJS.Timer[] = [] | ||||||
|   private inputs: Array<IClientInput> = [] |   private inputs: Array<IClientInput> = [] | ||||||
|  |  | ||||||
|   constructor(rid: number) { |   constructor(rid: number) { | ||||||
|     this.id = rid |     this.id = rid | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   join(uid: number) { |   join(uid: number) { | ||||||
|     const player = PlayerManager.Instance.getPlayerById(uid) |     const player = PlayerManager.Instance.getPlayerById(uid) | ||||||
|     if (player) { |     if (player) { | ||||||
|       player.rid = this.id |       player.rid = this.id | ||||||
|       this.players.add(player) |       this.players.add(player) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   leave(uid: number) { |   leave(uid: number) { | ||||||
|     const player = PlayerManager.Instance.getPlayerById(uid) |     const player = PlayerManager.Instance.getPlayerById(uid) | ||||||
|     if (player) { |     if (player) { | ||||||
|       player.rid = -1 |       player.rid = -1 | ||||||
|  |       player.connection.unlistenMsg(ApiMsgEnum.MsgClientSync, this.getInput, this) | ||||||
|       this.players.delete(player) |       this.players.delete(player) | ||||||
|       if (!this.players.size) { |       if (!this.players.size) { | ||||||
|         this.timers.forEach(t => clearInterval(t)) |  | ||||||
|         RoomManager.Instance.closeRoom(this.id) |         RoomManager.Instance.closeRoom(this.id) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   close() { | ||||||
|  |     this.timers.forEach(t => clearInterval(t)) | ||||||
|  |     for (const player of this.players) { | ||||||
|  |       player.connection.sendMsg(ApiMsgEnum.MsgGameEnd, {}) | ||||||
|  |       player.connection.unlistenMsg(ApiMsgEnum.MsgClientSync, this.getInput, this) | ||||||
|  |     } | ||||||
|  |     this.players.clear() | ||||||
|  |   } | ||||||
|  |  | ||||||
|   sync() { |   sync() { | ||||||
|     for (const player of this.players) { |     for (const player of this.players) { | ||||||
|       player.connection.sendMsg(ApiMsgEnum.MsgRoom, { |       player.connection.sendMsg(ApiMsgEnum.MsgRoom, { | ||||||
| @@ -71,10 +78,10 @@ export default class Room { | |||||||
|       player.connection.sendMsg(ApiMsgEnum.MsgGameStart, { |       player.connection.sendMsg(ApiMsgEnum.MsgGameStart, { | ||||||
|         state |         state | ||||||
|       }) |       }) | ||||||
|  |       player.connection.listenMsg(ApiMsgEnum.MsgClientSync, this.getInput, this) | ||||||
|     } |     } | ||||||
|     this.listenPlayer() |  | ||||||
|     let t1 = setInterval(() => { |     let t1 = setInterval(() => { | ||||||
|       this.syncInput() |       this.sendInput() | ||||||
|     }, 100) |     }, 100) | ||||||
|     let t2 = setInterval(() => { |     let t2 = setInterval(() => { | ||||||
|       this.timePast() |       this.timePast() | ||||||
| @@ -82,19 +89,14 @@ export default class Room { | |||||||
|     this.timers = [t1, t2] |     this.timers = [t1, t2] | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   listenPlayer() { |   getInput(input: IClientInput) { | ||||||
|     for (const player of this.players) { |  | ||||||
|       player.connection.listenMsg(ApiMsgEnum.MsgClientSync, (input) => { |  | ||||||
|     this.inputs.push(input) |     this.inputs.push(input) | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   syncInput() { |   sendInput() { | ||||||
|     const inputs = this.inputs |     const inputs = this.inputs | ||||||
|     this.inputs = [] |     this.inputs = [] | ||||||
|  |  | ||||||
|  |  | ||||||
|     for (const player of this.players) { |     for (const player of this.players) { | ||||||
|       player.connection.sendMsg(ApiMsgEnum.MsgServerSync, inputs) |       player.connection.sendMsg(ApiMsgEnum.MsgServerSync, inputs) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ export default class RoomManager extends Singleton { | |||||||
|   closeRoom(rid: number) { |   closeRoom(rid: number) { | ||||||
|     const room = this.getRoomById(rid) |     const room = this.getRoomById(rid) | ||||||
|     if (room) { |     if (room) { | ||||||
|  |       room.close() | ||||||
|       this.rooms.delete(room) |       this.rooms.delete(room) | ||||||
|       this.idMapRoom.delete(rid) |       this.idMapRoom.delete(rid) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,6 +1,3 @@ | |||||||
| import { IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes } from './Api' |  | ||||||
| import { ApiMsgEnum } from './Enum' |  | ||||||
| import { IMsgClientSync, IMsgGameStart, IMsgPlayerList, IMsgRoom, IMsgRoomList, IMsgServerSync } from './Msg' |  | ||||||
| export * from './Api' | export * from './Api' | ||||||
| export * from './Msg' | export * from './Msg' | ||||||
| export * from './Enum' | export * from './Enum' | ||||||
| @@ -9,44 +6,3 @@ export * from './State' | |||||||
| export * from './Utils' | export * from './Utils' | ||||||
| export * from './Binary' | export * from './Binary' | ||||||
|  |  | ||||||
| export interface IModel { |  | ||||||
|   api: { |  | ||||||
|     [ApiMsgEnum.ApiPlayerJoin]: { |  | ||||||
|       req: IApiPlayerJoinReq, |  | ||||||
|       res: IApiPlayerJoinRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiPlayerList]: { |  | ||||||
|       req: IApiPlayerListReq, |  | ||||||
|       res: IApiPlayerListRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiRoomList]: { |  | ||||||
|       req: IApiRoomListReq, |  | ||||||
|       res: IApiRoomListRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiRoomCreate]: { |  | ||||||
|       req: IApiRoomCreateReq, |  | ||||||
|       res: IApiRoomCreateRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiRoomJoin]: { |  | ||||||
|       req: IApiRoomJoinReq, |  | ||||||
|       res: IApiRoomJoinRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiRoomLeave]: { |  | ||||||
|       req: IApiRoomLeaveReq, |  | ||||||
|       res: IApiRoomLeaveRes, |  | ||||||
|     } |  | ||||||
|     [ApiMsgEnum.ApiGameStart]: { |  | ||||||
|       req: IApiGameStartReq, |  | ||||||
|       res: IApiGameStartRes, |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   msg: { |  | ||||||
|     [ApiMsgEnum.MsgPlayerList]: IMsgPlayerList |  | ||||||
|     [ApiMsgEnum.MsgRoomList]: IMsgRoomList, |  | ||||||
|     [ApiMsgEnum.MsgRoom]: IMsgRoom, |  | ||||||
|     [ApiMsgEnum.MsgGameStart]: IMsgGameStart, |  | ||||||
|     [ApiMsgEnum.MsgClientSync]: IMsgClientSync, |  | ||||||
|     [ApiMsgEnum.MsgServerSync]: IMsgServerSync, |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,10 +9,15 @@ export enum ConnectionEventEnum { | |||||||
|   Close = 'Close', |   Close = 'Close', | ||||||
| } | } | ||||||
|  |  | ||||||
|  | interface IItem { | ||||||
|  |   cb: Function; | ||||||
|  |   ctx: unknown; | ||||||
|  | } | ||||||
|  |  | ||||||
| export class Connection extends EventEmitter { | export class Connection extends EventEmitter { | ||||||
|   server: MyServer |   server: MyServer | ||||||
|   ws: WebSocket |   ws: WebSocket | ||||||
|   msgMap: Map<ApiMsgEnum, Function[]> = new Map() |   msgMap: Map<ApiMsgEnum, Array<IItem>> = new Map() | ||||||
|   playerId?: number; |   playerId?: number; | ||||||
|  |  | ||||||
|   constructor(server: MyServer, ws: WebSocket) { |   constructor(server: MyServer, ws: WebSocket) { | ||||||
| @@ -34,7 +39,7 @@ export class Connection extends EventEmitter { | |||||||
|         if (this.server.apiMap.has(name)) { |         if (this.server.apiMap.has(name)) { | ||||||
|           try { |           try { | ||||||
|             const cb = this.server.apiMap.get(name) |             const cb = this.server.apiMap.get(name) | ||||||
|             const res = cb?.(this, data) |             const res = cb.call(null, data) | ||||||
|             this.sendMsg(name, { |             this.sendMsg(name, { | ||||||
|               success: true, |               success: true, | ||||||
|               res, |               res, | ||||||
| @@ -45,31 +50,34 @@ export class Connection extends EventEmitter { | |||||||
|               error: (error as Error)?.message, |               error: (error as Error)?.message, | ||||||
|             }) |             }) | ||||||
|           } |           } | ||||||
|           return |         } else { | ||||||
|         } |           try { | ||||||
|  |  | ||||||
|             if (this.msgMap.has(name)) { |             if (this.msgMap.has(name)) { | ||||||
|           this.msgMap.get(name)?.forEach(cb => cb(data)) |               this.msgMap.get(name)?.forEach(({ cb, ctx }) => cb.call(ctx, data)) | ||||||
|             } |             } | ||||||
|           } catch (error) { |           } catch (error) { | ||||||
|         // console.log(`解析失败,${str}不是合法的JSON格式:`, error) |  | ||||||
|             console.log(error) |             console.log(error) | ||||||
|           } |           } | ||||||
|  |         } | ||||||
|  |       } catch (error) { | ||||||
|  |         console.log(`解析失败,不是合法的JSON格式:`, error) | ||||||
|  |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void) { |   listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) { | ||||||
|     if (this.msgMap.has(name)) { |     if (this.msgMap.has(name)) { | ||||||
|       this.msgMap.get(name)?.push(cb) |       this.msgMap.get(name)?.push({ cb, ctx }) | ||||||
|     } else { |     } else { | ||||||
|       this.msgMap.set(name, [cb]) |       this.msgMap.set(name, [{ cb, ctx }]) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void) { |   unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) { | ||||||
|     if (this.msgMap.has(name)) { |     if (this.msgMap.has(name)) { | ||||||
|       const index = this.msgMap.get(name)?.indexOf(cb) || -1 |       const items = this.msgMap.get(name) | ||||||
|       index > -1 && this.msgMap.get(name)?.splice(index, 1) |       const index = items.findIndex(i => cb === i.cb && i.ctx === ctx); | ||||||
|  |       index > -1 && items.splice(index, 1) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -80,7 +88,7 @@ export class Connection extends EventEmitter { | |||||||
|     }) |     }) | ||||||
|     const view = binaryEncode(name, data) |     const view = binaryEncode(name, data) | ||||||
|     const buffer = Buffer.from(view.buffer) |     const buffer = Buffer.from(view.buffer) | ||||||
|     console.log(`${getTime()}发送|字节数${buffer.length}|${this.playerId || -1}|${msg}`) |     console.log(`${getTime()}发送|字节数${buffer.length}|${this.playerId || -1}|内存${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)}MB|${msg}`) | ||||||
|     this.ws.send(buffer) |     this.ws.send(buffer) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -2,7 +2,7 @@ import { Connection, MyServer, MyServerEventEnum } from './Core'; | |||||||
| import PlayerManager from './Biz/PlayerManager'; | import PlayerManager from './Biz/PlayerManager'; | ||||||
| import RoomManager from './Biz/RoomManager'; | import RoomManager from './Biz/RoomManager'; | ||||||
| import { getTime, symlinkCommon } from './Utils'; | import { getTime, symlinkCommon } from './Utils'; | ||||||
| import { ApiMsgEnum, IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes, IModel } from './Common'; | import { ApiMsgEnum, IApiGameEndReq, IApiGameEndRes, IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes, IModel } from './Common'; | ||||||
|  |  | ||||||
| const server = new MyServer({ port: 8888 }) | const server = new MyServer({ port: 8888 }) | ||||||
|  |  | ||||||
| @@ -31,7 +31,6 @@ server.setApi(ApiMsgEnum.ApiPlayerJoin, (connection: Connection, { nickname }: I | |||||||
|   } |   } | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  |  | ||||||
| server.setApi(ApiMsgEnum.ApiRoomList, (connection: Connection, data: IApiRoomListReq): IApiRoomListRes => { | server.setApi(ApiMsgEnum.ApiRoomList, (connection: Connection, data: IApiRoomListReq): IApiRoomListRes => { | ||||||
|   return { list: RoomManager.Instance.getRoomsView() } |   return { list: RoomManager.Instance.getRoomsView() } | ||||||
| }) | }) | ||||||
| @@ -114,6 +113,28 @@ server.setApi(ApiMsgEnum.ApiGameStart, (connection: Connection, data: IApiGameSt | |||||||
|   } |   } | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | server.setApi(ApiMsgEnum.ApiGameEnd, (connection: Connection, data: IApiGameEndReq): IApiGameEndRes => { | ||||||
|  |   if (connection.playerId) { | ||||||
|  |     const player = PlayerManager.Instance.getPlayerById(connection.playerId) | ||||||
|  |     if (player) { | ||||||
|  |       const rid = player.rid | ||||||
|  |       if (rid) { | ||||||
|  |         RoomManager.Instance.closeRoom(rid) | ||||||
|  |         PlayerManager.Instance.syncPlayers() | ||||||
|  |         RoomManager.Instance.syncRooms() | ||||||
|  |         return {} | ||||||
|  |       } else { | ||||||
|  |         throw new Error("ApiGameEnd 玩家不在房间") | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       throw new Error("ApiGameEnd 玩家不存在") | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     throw new Error("ApiGameEnd 玩家未登录") | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
| // start!! | // start!! | ||||||
| server.start().then(() => { | server.start().then(() => { | ||||||
|   symlinkCommon() |   symlinkCommon() | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ | |||||||
|     // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ |     // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ | ||||||
|     "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ |     "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ | ||||||
|     /* Type Checking */ |     /* Type Checking */ | ||||||
|     "strict": true, /* Enable all strict type-checking options. */ |     // "strict": true, /* Enable all strict type-checking options. */ | ||||||
|     // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */ |     // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */ | ||||||
|     // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */ |     // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */ | ||||||
|     // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ |     // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ | ||||||
|   | |||||||
| @@ -5,5 +5,10 @@ | |||||||
|   "version": "1.0.0", |   "version": "1.0.0", | ||||||
|   "workspaces": [ |   "workspaces": [ | ||||||
|     "apps/*" |     "apps/*" | ||||||
|   ] |   ], | ||||||
|  |   "scripts": { | ||||||
|  |     "lint": "eslint .", | ||||||
|  |     "lint:fix": "eslint . --fix", | ||||||
|  |     "dev": "yarn workspace @game/server run dev" | ||||||
|  |   } | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user