重构NetManager支持MessagePair,新增TSRPCWsClient。
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import { find } from "cc";
|
import { find } from "cc";
|
||||||
import { BaseState } from "../../Framework/FSM/BaseState";
|
import { BaseState } from "../../Framework/FSM/BaseState";
|
||||||
|
import { NetConfig, NetProtocolType } from "../../Framework/Net/NetConfig";
|
||||||
|
import { NetEvent } from "../../Framework/Net/NetEvent";
|
||||||
import { NetManager } from "../../Framework/Net/NetManager";
|
import { NetManager } from "../../Framework/Net/NetManager";
|
||||||
import { UIMgr } from "../../Framework/UI/UIMgr";
|
import { UIMgr } from "../../Framework/UI/UIMgr";
|
||||||
|
import { serviceProto } from "../../Shared/protocols/serviceProto";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用启动状态
|
* 应用启动状态
|
||||||
@@ -15,15 +18,15 @@ export class AppStatusBoot extends BaseState {
|
|||||||
constructor(fsm: any) {
|
constructor(fsm: any) {
|
||||||
super(fsm, "Boot");
|
super(fsm, "Boot");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 进入启动状态
|
* 进入启动状态
|
||||||
*/
|
*/
|
||||||
async onEnter(params?: any): Promise<void> {
|
async onEnter(params?: any): Promise<void> {
|
||||||
super.onEnter(params);
|
super.onEnter(params);
|
||||||
|
|
||||||
console.log("[AppStatusBoot] 开始初始化应用...");
|
console.log("[AppStatusBoot] 开始初始化应用...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 初始化UI
|
// 初始化UI
|
||||||
console.log("[AppStatusBoot] 初始化UI管理器...");
|
console.log("[AppStatusBoot] 初始化UI管理器...");
|
||||||
@@ -31,32 +34,71 @@ export class AppStatusBoot extends BaseState {
|
|||||||
|
|
||||||
// 1. 初始化并连接网络
|
// 1. 初始化并连接网络
|
||||||
await this.initAndConnectNet();
|
await this.initAndConnectNet();
|
||||||
|
|
||||||
// 2. 初始化完成,切换到登录状态
|
// 2. 初始化完成,切换到登录状态
|
||||||
console.log("[AppStatusBoot] 启动完成,切换到登录状态");
|
console.log("[AppStatusBoot] 启动完成,切换到登录状态");
|
||||||
this._fsm.changeState("Login");
|
this._fsm.changeState("Login");
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[AppStatusBoot] 初始化失败:", error);
|
console.error("[AppStatusBoot] 初始化失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化并连接网络
|
* 初始化并连接网络
|
||||||
*/
|
*/
|
||||||
private async initAndConnectNet(): Promise<void> {
|
private async initAndConnectNet(): Promise<void> {
|
||||||
console.log("[AppStatusBoot] 初始化网络管理器...");
|
console.log("[AppStatusBoot] 初始化网络管理器...");
|
||||||
|
|
||||||
// TODO: 从配置文件读取服务器地址
|
// 1. 获取网络管理器实例
|
||||||
// import { serviceProto } from '../../Shared/protocols/serviceProto';
|
const netManager = NetManager.getInstance();
|
||||||
// const netManager = NetManager.getInstance();
|
|
||||||
// netManager.setServiceProto(serviceProto);
|
// 2. 设置服务协议 (必须在 init 之前调用)
|
||||||
// netManager.init({ serverUrl: 'http://localhost:3000' });
|
netManager.setServiceProto(serviceProto);
|
||||||
// await netManager.connect();
|
|
||||||
|
// 3. 监听网络事件
|
||||||
console.log("[AppStatusBoot] 网络连接完成(待配置)");
|
netManager.on(NetEvent.Connected, () => {
|
||||||
|
console.log('✅ 网络已连接');
|
||||||
|
this.onConnected();
|
||||||
|
});
|
||||||
|
|
||||||
|
netManager.on(NetEvent.Disconnected, () => {
|
||||||
|
console.log('❌ 网络已断开');
|
||||||
|
});
|
||||||
|
|
||||||
|
netManager.on(NetEvent.Reconnecting, (count: number) => {
|
||||||
|
console.log(`🔄 正在重连... (${count})`);
|
||||||
|
});
|
||||||
|
|
||||||
|
netManager.on(NetEvent.Error, (error: any) => {
|
||||||
|
console.error('⚠️ 网络错误:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
const config: NetConfig = {
|
||||||
|
serverUrl: 'http://localhost:3000', // TODO: 替换为实际服务器地址
|
||||||
|
protocolType: NetProtocolType.WebSocket,
|
||||||
|
timeout: 30000,
|
||||||
|
autoReconnect: true,
|
||||||
|
reconnectInterval: 3000,
|
||||||
|
maxReconnectTimes: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5. 初始化
|
||||||
|
netManager.init(config);
|
||||||
|
// 6. 连接服务器 (HttpClient 创建即可用)
|
||||||
|
const success = await netManager.connect();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
console.log('[AppStatusBoot]✅ 网络初始化成功');
|
||||||
|
} else {
|
||||||
|
console.error('[AppStatusBoot]❌ 网络初始化失败');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onConnected() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出启动状态
|
* 退出启动状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { find } from "cc";
|
||||||
import { BaseState } from "../../Framework/FSM/BaseState";
|
import { BaseState } from "../../Framework/FSM/BaseState";
|
||||||
import { UIMgr } from "../../Framework/UI/UIMgr";
|
import { UIMgr } from "../../Framework/UI/UIMgr";
|
||||||
|
import { PlayerInfo } from "../../Shared/protocols/MsgResLogin";
|
||||||
import { UIGame } from "../Game/UIGame";
|
import { UIGame } from "../Game/UIGame";
|
||||||
import { World } from "../Game/World";
|
import { World } from "../Game/World";
|
||||||
import { PlayerInfo } from "../../Shared/protocols/PtlLogin";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用游戏状态
|
* 应用游戏状态
|
||||||
@@ -16,19 +17,19 @@ export class AppStatusGame extends BaseState {
|
|||||||
private _player: PlayerInfo = null;
|
private _player: PlayerInfo = null;
|
||||||
private _isNewPlayer: boolean = false;
|
private _isNewPlayer: boolean = false;
|
||||||
private _uiGame: UIGame = null;
|
private _uiGame: UIGame = null;
|
||||||
|
|
||||||
constructor(fsm: any) {
|
constructor(fsm: any) {
|
||||||
super(fsm, "Game");
|
super(fsm, "Game");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 进入游戏状态
|
* 进入游戏状态
|
||||||
*/
|
*/
|
||||||
async onEnter(params?: any): Promise<void> {
|
async onEnter(params?: any): Promise<void> {
|
||||||
super.onEnter(params);
|
super.onEnter(params);
|
||||||
|
|
||||||
console.log("[AppStatusGame] 进入游戏世界");
|
console.log("[AppStatusGame] 进入游戏世界");
|
||||||
|
|
||||||
// 保存玩家信息
|
// 保存玩家信息
|
||||||
if (params) {
|
if (params) {
|
||||||
this._player = params.player || null;
|
this._player = params.player || null;
|
||||||
@@ -36,82 +37,82 @@ export class AppStatusGame extends BaseState {
|
|||||||
console.log(`[AppStatusGame] 玩家信息:`, this._player);
|
console.log(`[AppStatusGame] 玩家信息:`, this._player);
|
||||||
console.log(`[AppStatusGame] 是否新玩家: ${this._isNewPlayer}`);
|
console.log(`[AppStatusGame] 是否新玩家: ${this._isNewPlayer}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 加载游戏场景
|
// 1. 加载游戏场景
|
||||||
await this.loadGameScene();
|
await this.loadGameScene();
|
||||||
|
|
||||||
// 2. 初始化游戏
|
// 2. 初始化游戏
|
||||||
await this.initGame();
|
await this.initGame();
|
||||||
|
|
||||||
// 3. 开始监听服务器广播
|
// 3. 开始监听服务器广播
|
||||||
this.listenServerMessages();
|
this.listenServerMessages();
|
||||||
|
|
||||||
// 4. 开始游戏
|
// 4. 开始游戏
|
||||||
this.startGame();
|
this.startGame();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[AppStatusGame] 进入游戏失败:", error);
|
console.error("[AppStatusGame] 进入游戏失败:", error);
|
||||||
// 返回登录
|
// 返回登录
|
||||||
this._fsm.changeState("Login");
|
this._fsm.changeState("Login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载游戏场景
|
* 加载游戏场景
|
||||||
*/
|
*/
|
||||||
private async loadGameScene(): Promise<void> {
|
private async loadGameScene(): Promise<void> {
|
||||||
console.log("[AppStatusGame] 加载游戏场景...");
|
console.log("[AppStatusGame] 加载游戏场景...");
|
||||||
|
|
||||||
// 加载游戏UI
|
// 加载游戏UI
|
||||||
this._uiGame = await UIMgr.getInstance().load(UIGame);
|
this._uiGame = await UIMgr.getInstance().load(UIGame);
|
||||||
|
|
||||||
console.log("[AppStatusGame] 游戏场景加载完成");
|
console.log("[AppStatusGame] 游戏场景加载完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化游戏
|
* 初始化游戏
|
||||||
*/
|
*/
|
||||||
private async initGame(): Promise<void> {
|
private async initGame(): Promise<void> {
|
||||||
console.log("[AppStatusGame] 初始化游戏...");
|
console.log("[AppStatusGame] 初始化游戏...");
|
||||||
|
|
||||||
if (!this._uiGame) {
|
if (!this._uiGame) {
|
||||||
throw new Error("UIGame 未加载");
|
throw new Error("UIGame 未加载");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取世界根节点
|
// 获取世界根节点
|
||||||
const worldRoot = this._uiGame.getWorldRoot();
|
const worldRoot = find("Game")
|
||||||
if (!worldRoot) {
|
if (!worldRoot) {
|
||||||
throw new Error("世界根节点未找到");
|
throw new Error("世界根节点未找到");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化世界,传入本地玩家信息
|
// 初始化世界,传入本地玩家信息
|
||||||
await World.getInstance().init(worldRoot, this._player);
|
await World.getInstance().init(worldRoot, this._player);
|
||||||
|
|
||||||
console.log("[AppStatusGame] 游戏初始化完成");
|
console.log("[AppStatusGame] 游戏初始化完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听服务器广播消息
|
* 监听服务器广播消息
|
||||||
*/
|
*/
|
||||||
private listenServerMessages(): void {
|
private listenServerMessages(): void {
|
||||||
console.log("[AppStatusGame] 开始监听服务器广播...");
|
console.log("[AppStatusGame] 开始监听服务器广播...");
|
||||||
|
|
||||||
// 网络消息监听已在 World 中注册
|
// 网络消息监听已在 World 中注册
|
||||||
// World 会自动处理 MsgPlayerJoin 和 MsgPlayerMove
|
// World 会自动处理 MsgPlayerJoin 和 MsgPlayerMove
|
||||||
|
|
||||||
console.log("[AppStatusGame] 服务器广播监听已设置");
|
console.log("[AppStatusGame] 服务器广播监听已设置");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始游戏
|
* 开始游戏
|
||||||
*/
|
*/
|
||||||
private startGame(): void {
|
private startGame(): void {
|
||||||
console.log("[AppStatusGame] 游戏开始!");
|
console.log("[AppStatusGame] 游戏开始!");
|
||||||
|
|
||||||
// 游戏已启动,玩家可以通过 WASD 控制角色移动
|
// 游戏已启动,玩家可以通过 WASD 控制角色移动
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新游戏状态(每帧调用)
|
* 更新游戏状态(每帧调用)
|
||||||
*/
|
*/
|
||||||
@@ -122,7 +123,7 @@ export class AppStatusGame extends BaseState {
|
|||||||
// - 更新敌人AI
|
// - 更新敌人AI
|
||||||
// - 同步网络状态
|
// - 同步网络状态
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 暂停游戏
|
* 暂停游戏
|
||||||
*/
|
*/
|
||||||
@@ -132,7 +133,7 @@ export class AppStatusGame extends BaseState {
|
|||||||
// - 停止游戏更新
|
// - 停止游戏更新
|
||||||
// - 显示暂停菜单
|
// - 显示暂停菜单
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 恢复游戏
|
* 恢复游戏
|
||||||
*/
|
*/
|
||||||
@@ -142,60 +143,60 @@ export class AppStatusGame extends BaseState {
|
|||||||
// - 继续游戏更新
|
// - 继续游戏更新
|
||||||
// - 隐藏暂停菜单
|
// - 隐藏暂停菜单
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 玩家死亡
|
* 玩家死亡
|
||||||
*/
|
*/
|
||||||
onPlayerDeath(): void {
|
onPlayerDeath(): void {
|
||||||
console.log("[AppStatusGame] 玩家死亡");
|
console.log("[AppStatusGame] 玩家死亡");
|
||||||
|
|
||||||
// TODO: 处理玩家死亡
|
// TODO: 处理玩家死亡
|
||||||
// - 显示死亡界面
|
// - 显示死亡界面
|
||||||
// - 显示复活选项或返回登录
|
// - 显示复活选项或返回登录
|
||||||
|
|
||||||
// 延迟后返回登录
|
// 延迟后返回登录
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this._fsm.changeState("Login");
|
this._fsm.changeState("Login");
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出游戏(返回登录)
|
* 退出游戏(返回登录)
|
||||||
*/
|
*/
|
||||||
quitGame(): void {
|
quitGame(): void {
|
||||||
console.log("[AppStatusGame] 退出游戏");
|
console.log("[AppStatusGame] 退出游戏");
|
||||||
|
|
||||||
// TODO: 断开连接或通知服务器
|
// TODO: 断开连接或通知服务器
|
||||||
// const netManager = NetManager.getInstance();
|
// const netManager = NetManager.getInstance();
|
||||||
// await netManager.disconnect();
|
// await netManager.disconnect();
|
||||||
|
|
||||||
// 返回登录
|
// 返回登录
|
||||||
this._fsm.changeState("Login");
|
this._fsm.changeState("Login");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟辅助函数
|
* 延迟辅助函数
|
||||||
*/
|
*/
|
||||||
private delay(ms: number): Promise<void> {
|
private delay(ms: number): Promise<void> {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出游戏状态
|
* 退出游戏状态
|
||||||
*/
|
*/
|
||||||
onExit(): void {
|
onExit(): void {
|
||||||
super.onExit();
|
super.onExit();
|
||||||
console.log("[AppStatusGame] 离开游戏状态");
|
console.log("[AppStatusGame] 离开游戏状态");
|
||||||
|
|
||||||
// 清理世界
|
// 清理世界
|
||||||
World.clear();
|
World.clear();
|
||||||
|
|
||||||
// 卸载游戏UI
|
// 卸载游戏UI
|
||||||
if (this._uiGame) {
|
if (this._uiGame) {
|
||||||
UIMgr.getInstance().unload(UIGame);
|
UIMgr.getInstance().unload(UIGame);
|
||||||
this._uiGame = null;
|
this._uiGame = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._player = null;
|
this._player = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Node, Vec3, instantiate, Prefab } from 'cc';
|
import { instantiate, Node, Prefab } from 'cc';
|
||||||
import { NetManager } from '../../Framework/Net/NetManager';
|
import { NetManager } from '../../Framework/Net/NetManager';
|
||||||
import { ResMgr } from '../../Framework/ResMgr/ResMgr';
|
import { ResMgr } from '../../Framework/ResMgr/ResMgr';
|
||||||
import { MsgPlayerJoin } from '../../Shared/protocols/MsgPlayerJoin';
|
import { MsgPlayerJoin } from '../../Shared/protocols/MsgPlayerJoin';
|
||||||
import { MsgPlayerMove } from '../../Shared/protocols/MsgPlayerMove';
|
import { MsgPlayerMove } from '../../Shared/protocols/MsgPlayerMove';
|
||||||
import { PlayerInfo } from '../../Shared/protocols/PtlLogin';
|
import { PlayerInfo } from '../../Shared/protocols/MsgResLogin';
|
||||||
|
import { CameraController } from './CameraController';
|
||||||
import { PlayerController } from './PlayerController';
|
import { PlayerController } from './PlayerController';
|
||||||
import { RemotePlayer } from './RemotePlayer';
|
import { RemotePlayer } from './RemotePlayer';
|
||||||
|
|
||||||
@@ -33,7 +34,10 @@ export class World {
|
|||||||
/** 玩家模型预制体 */
|
/** 玩家模型预制体 */
|
||||||
private playerPrefab: Prefab = null;
|
private playerPrefab: Prefab = null;
|
||||||
|
|
||||||
private constructor() {}
|
/** 摄像机控制器 */
|
||||||
|
private cameraController: CameraController = null;
|
||||||
|
|
||||||
|
private constructor() { }
|
||||||
|
|
||||||
public static getInstance(): World {
|
public static getInstance(): World {
|
||||||
if (!World.instance) {
|
if (!World.instance) {
|
||||||
@@ -68,7 +72,7 @@ export class World {
|
|||||||
*/
|
*/
|
||||||
private async loadPlayerPrefab(): Promise<void> {
|
private async loadPlayerPrefab(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.playerPrefab = await ResMgr.getInstance().load('resources', 'res://Actor/M1/M1', Prefab);
|
this.playerPrefab = await ResMgr.getInstance().load('res', 'Actor/M1/M1', Prefab);
|
||||||
console.log('[World] 玩家模型预制体加载成功');
|
console.log('[World] 玩家模型预制体加载成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[World] 加载玩家模型预制体失败:', error);
|
console.error('[World] 加载玩家模型预制体失败:', error);
|
||||||
@@ -113,6 +117,10 @@ export class World {
|
|||||||
this.localPlayerController = this.localPlayerNode.addComponent(PlayerController);
|
this.localPlayerController = this.localPlayerNode.addComponent(PlayerController);
|
||||||
this.localPlayerController.init(this.localPlayer);
|
this.localPlayerController.init(this.localPlayer);
|
||||||
|
|
||||||
|
// 创建并绑定摄像机控制器(只有本地玩家需要)
|
||||||
|
this.cameraController = this.worldRoot.addComponent(CameraController) as CameraController;
|
||||||
|
this.cameraController.setTarget(this.localPlayerNode);
|
||||||
|
|
||||||
console.log('[World] 本地玩家创建完成:', this.localPlayer.name);
|
console.log('[World] 本地玩家创建完成:', this.localPlayer.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +206,12 @@ export class World {
|
|||||||
}
|
}
|
||||||
this.localPlayerController = null;
|
this.localPlayerController = null;
|
||||||
|
|
||||||
|
// 销毁摄像机控制器
|
||||||
|
if (this.cameraController) {
|
||||||
|
this.cameraController.node.removeComponent(CameraController);
|
||||||
|
this.cameraController = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 销毁所有远程玩家
|
// 销毁所有远程玩家
|
||||||
this.remotePlayers.forEach((remotePlayer) => {
|
this.remotePlayers.forEach((remotePlayer) => {
|
||||||
remotePlayer.destroy();
|
remotePlayer.destroy();
|
||||||
|
|||||||
9
client/assets/scripts/App/Msg.meta
Normal file
9
client/assets/scripts/App/Msg.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "9f8d42c2-cee9-4156-b0ee-992cb5d66317",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
76
client/assets/scripts/App/Msg/MessagePairBase.ts
Normal file
76
client/assets/scripts/App/Msg/MessagePairBase.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* 消息对定义基类
|
||||||
|
* 用于定义成对出现的请求和响应消息
|
||||||
|
*/
|
||||||
|
export abstract class MessagePair<TReq, TRes> {
|
||||||
|
/** 请求消息名称 */
|
||||||
|
abstract readonly requestName: string;
|
||||||
|
|
||||||
|
/** 响应消息名称 */
|
||||||
|
abstract readonly responseName: string;
|
||||||
|
|
||||||
|
/** 请求消息类型检查 */
|
||||||
|
abstract isValidRequest(msg: any): msg is TReq;
|
||||||
|
|
||||||
|
/** 响应消息类型检查 */
|
||||||
|
abstract isValidResponse(msg: any): msg is TRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息对注册表
|
||||||
|
* 用于管理所有的消息对
|
||||||
|
*/
|
||||||
|
export class MessagePairRegistry {
|
||||||
|
private static _instance: MessagePairRegistry;
|
||||||
|
private _pairs: Map<string, MessagePair<any, any>> = new Map();
|
||||||
|
|
||||||
|
static getInstance(): MessagePairRegistry {
|
||||||
|
if (!this._instance) {
|
||||||
|
this._instance = new MessagePairRegistry();
|
||||||
|
}
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册消息对
|
||||||
|
* @param pair 消息对实例
|
||||||
|
*/
|
||||||
|
register(pair: MessagePair<any, any>): void {
|
||||||
|
this._pairs.set(pair.requestName, pair);
|
||||||
|
console.log(`[MessagePairRegistry] Registered message pair: ${pair.requestName} -> ${pair.responseName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据请求消息名获取响应消息名
|
||||||
|
* @param requestName 请求消息名
|
||||||
|
* @returns 响应消息名,如果未找到返回null
|
||||||
|
*/
|
||||||
|
getResponseName(requestName: string): string | null {
|
||||||
|
const pair = this._pairs.get(requestName);
|
||||||
|
return pair ? pair.responseName : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据请求消息名获取消息对
|
||||||
|
* @param requestName 请求消息名
|
||||||
|
* @returns 消息对实例,如果未找到返回null
|
||||||
|
*/
|
||||||
|
getPair(requestName: string): MessagePair<any, any> | null {
|
||||||
|
return this._pairs.get(requestName) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否为已注册的请求消息
|
||||||
|
* @param msgName 消息名
|
||||||
|
*/
|
||||||
|
isRegisteredRequest(msgName: string): boolean {
|
||||||
|
return this._pairs.has(msgName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已注册的消息对
|
||||||
|
*/
|
||||||
|
getAllPairs(): MessagePair<any, any>[] {
|
||||||
|
return Array.from(this._pairs.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"ver": "4.0.24",
|
"ver": "4.0.24",
|
||||||
"importer": "typescript",
|
"importer": "typescript",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "db7f0511-7e71-4088-9822-186f68082db6",
|
"uuid": "3ba46d91-073d-44d6-8157-05f1af758121",
|
||||||
"files": [],
|
"files": [],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {}
|
"userData": {}
|
||||||
23
client/assets/scripts/App/Msg/MessagePairInit.ts
Normal file
23
client/assets/scripts/App/Msg/MessagePairInit.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { MessagePairRegistry } from './MessagePairBase';
|
||||||
|
import { LoginMessagePair } from './Pair/LoginMessagePair';
|
||||||
|
import { MoveMessagePair } from './Pair/MoveMessagePair';
|
||||||
|
import { SendMessagePair } from './Pair/SendMessagePair';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息对初始化
|
||||||
|
* 在应用启动时调用此函数注册所有消息对
|
||||||
|
*/
|
||||||
|
export function initMessagePairs(): void {
|
||||||
|
const registry = MessagePairRegistry.getInstance();
|
||||||
|
|
||||||
|
// 注册登录消息对
|
||||||
|
registry.register(new LoginMessagePair());
|
||||||
|
|
||||||
|
// 注册移动消息对
|
||||||
|
registry.register(new MoveMessagePair());
|
||||||
|
|
||||||
|
// 注册发送消息对
|
||||||
|
registry.register(new SendMessagePair());
|
||||||
|
|
||||||
|
console.log('[MessagePairs] All message pairs registered successfully');
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"ver": "4.0.24",
|
"ver": "4.0.24",
|
||||||
"importer": "typescript",
|
"importer": "typescript",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "b5331a2b-20fa-4653-8013-deb54bad8d2e",
|
"uuid": "9b552413-09a9-4ec6-b389-ea371b734a41",
|
||||||
"files": [],
|
"files": [],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {}
|
"userData": {}
|
||||||
84
client/assets/scripts/App/Msg/MsgExample.ts
Normal file
84
client/assets/scripts/App/Msg/MsgExample.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import { initMessagePairs } from './MessagePairInit';
|
||||||
|
import { MsgManager } from './MsgManager';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息系统使用示例
|
||||||
|
*/
|
||||||
|
export class MsgExample {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化消息系统
|
||||||
|
* 应在游戏启动时调用
|
||||||
|
*/
|
||||||
|
static init(): void {
|
||||||
|
// 初始化消息对注册表
|
||||||
|
initMessagePairs();
|
||||||
|
|
||||||
|
console.log('[MsgExample] Message system initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录示例
|
||||||
|
*/
|
||||||
|
static async loginExample(): Promise<void> {
|
||||||
|
const msgMgr = MsgManager.getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await msgMgr.login({
|
||||||
|
playerId: 'player123',
|
||||||
|
playerName: 'TestPlayer'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.success) {
|
||||||
|
console.log('登录成功:', response.player);
|
||||||
|
} else {
|
||||||
|
console.log('登录失败:', response?.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('登录请求异常:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动示例
|
||||||
|
*/
|
||||||
|
static async moveExample(): Promise<void> {
|
||||||
|
const msgMgr = MsgManager.getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await msgMgr.move({
|
||||||
|
x: 100,
|
||||||
|
y: 200
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.success) {
|
||||||
|
console.log('移动成功:', response.position);
|
||||||
|
} else {
|
||||||
|
console.log('移动失败:', response?.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('移动请求异常:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息示例
|
||||||
|
*/
|
||||||
|
static async sendMessageExample(): Promise<void> {
|
||||||
|
const msgMgr = MsgManager.getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await msgMgr.send({
|
||||||
|
content: 'Hello, World!'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
console.log('消息发送成功:', response.time);
|
||||||
|
} else {
|
||||||
|
console.log('消息发送失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送消息异常:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"ver": "4.0.24",
|
"ver": "4.0.24",
|
||||||
"importer": "typescript",
|
"importer": "typescript",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "9fdf30ed-1223-4112-81f6-75339229fd1b",
|
"uuid": "4c559445-88e3-4fe2-a87c-8c9ef390aa60",
|
||||||
"files": [],
|
"files": [],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {}
|
"userData": {}
|
||||||
55
client/assets/scripts/App/Msg/MsgManager.ts
Normal file
55
client/assets/scripts/App/Msg/MsgManager.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { NetManager } from '../../Framework/Net/NetManager';
|
||||||
|
import { MsgReqLogin } from '../../Shared/protocols/MsgReqLogin';
|
||||||
|
import { MsgReqMove } from '../../Shared/protocols/MsgReqMove';
|
||||||
|
import { MsgReqSend } from '../../Shared/protocols/MsgReqSend';
|
||||||
|
import { MsgResLogin } from '../../Shared/protocols/MsgResLogin';
|
||||||
|
import { MsgResMove } from '../../Shared/protocols/MsgResMove';
|
||||||
|
import { MsgResSend } from '../../Shared/protocols/MsgResSend';
|
||||||
|
import { LoginMessagePair } from './Pair/LoginMessagePair';
|
||||||
|
import { MoveMessagePair } from './Pair/MoveMessagePair';
|
||||||
|
import { SendMessagePair } from './Pair/SendMessagePair';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息管理器 - 提供类型安全的消息发送方法
|
||||||
|
*/
|
||||||
|
export class MsgManager {
|
||||||
|
private static _instance: MsgManager;
|
||||||
|
|
||||||
|
static getInstance(): MsgManager {
|
||||||
|
if (!this._instance) {
|
||||||
|
this._instance = new MsgManager();
|
||||||
|
}
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get netManager(): NetManager {
|
||||||
|
return NetManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送登录请求
|
||||||
|
* @param loginData 登录数据
|
||||||
|
* @returns 登录响应
|
||||||
|
*/
|
||||||
|
async login(loginData: MsgReqLogin): Promise<MsgResLogin | null> {
|
||||||
|
return this.netManager.callMsg(new LoginMessagePair(), loginData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送移动请求
|
||||||
|
* @param moveData 移动数据
|
||||||
|
* @returns 移动响应
|
||||||
|
*/
|
||||||
|
async move(moveData: MsgReqMove): Promise<MsgResMove | null> {
|
||||||
|
return this.netManager.callMsg(new MoveMessagePair(), moveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息请求
|
||||||
|
* @param sendData 发送数据
|
||||||
|
* @returns 发送响应
|
||||||
|
*/
|
||||||
|
async send(sendData: MsgReqSend): Promise<MsgResSend | null> {
|
||||||
|
return this.netManager.callMsg(new SendMessagePair(), sendData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"ver": "4.0.24",
|
"ver": "4.0.24",
|
||||||
"importer": "typescript",
|
"importer": "typescript",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "4414c606-7995-4f83-b83c-30c9fe840a6b",
|
"uuid": "871b5daf-492f-4ff7-adac-a13bbf6b82ce",
|
||||||
"files": [],
|
"files": [],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {}
|
"userData": {}
|
||||||
9
client/assets/scripts/App/Msg/Pair.meta
Normal file
9
client/assets/scripts/App/Msg/Pair.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "6f3ea388-fd67-45a4-9bfc-cae858378b7a",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
21
client/assets/scripts/App/Msg/Pair/LoginMessagePair.ts
Normal file
21
client/assets/scripts/App/Msg/Pair/LoginMessagePair.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { MsgReqLogin } from '../../../Shared/protocols/MsgReqLogin';
|
||||||
|
import { MsgResLogin } from '../../../Shared/protocols/MsgResLogin';
|
||||||
|
import { MessagePair } from '../MessagePairBase';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录消息对实现
|
||||||
|
*/
|
||||||
|
export class LoginMessagePair extends MessagePair<MsgReqLogin, MsgResLogin> {
|
||||||
|
readonly requestName = 'ReqLogin';
|
||||||
|
readonly responseName = 'ResLogin';
|
||||||
|
|
||||||
|
isValidRequest(msg: any): msg is MsgReqLogin {
|
||||||
|
return msg && typeof msg.playerId === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidResponse(msg: any): msg is MsgResLogin {
|
||||||
|
return msg &&
|
||||||
|
typeof msg.success === 'boolean' &&
|
||||||
|
typeof msg.message === 'string';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "8a0f8893-e078-4885-8407-70944f67d185",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
23
client/assets/scripts/App/Msg/Pair/MoveMessagePair.ts
Normal file
23
client/assets/scripts/App/Msg/Pair/MoveMessagePair.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { MsgReqMove } from '../../../Shared/protocols/MsgReqMove';
|
||||||
|
import { MsgResMove } from '../../../Shared/protocols/MsgResMove';
|
||||||
|
import { MessagePair } from '../MessagePairBase';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动消息对实现
|
||||||
|
*/
|
||||||
|
export class MoveMessagePair extends MessagePair<MsgReqMove, MsgResMove> {
|
||||||
|
readonly requestName = 'ReqMove';
|
||||||
|
readonly responseName = 'ResMove';
|
||||||
|
|
||||||
|
isValidRequest(msg: any): msg is MsgReqMove {
|
||||||
|
return msg &&
|
||||||
|
typeof msg.x === 'number' &&
|
||||||
|
typeof msg.y === 'number';
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidResponse(msg: any): msg is MsgResMove {
|
||||||
|
return msg &&
|
||||||
|
typeof msg.success === 'boolean' &&
|
||||||
|
typeof msg.message === 'string';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "f95aa765-9371-4644-9694-8eb8dd7d8930",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
19
client/assets/scripts/App/Msg/Pair/SendMessagePair.ts
Normal file
19
client/assets/scripts/App/Msg/Pair/SendMessagePair.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { MsgReqSend } from '../../../Shared/protocols/MsgReqSend';
|
||||||
|
import { MsgResSend } from '../../../Shared/protocols/MsgResSend';
|
||||||
|
import { MessagePair } from '../MessagePairBase';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息对实现
|
||||||
|
*/
|
||||||
|
export class SendMessagePair extends MessagePair<MsgReqSend, MsgResSend> {
|
||||||
|
readonly requestName = 'ReqSend';
|
||||||
|
readonly responseName = 'ResSend';
|
||||||
|
|
||||||
|
isValidRequest(msg: any): msg is MsgReqSend {
|
||||||
|
return msg && typeof msg.content === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidResponse(msg: any): msg is MsgResSend {
|
||||||
|
return msg && msg.time instanceof Date;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "d9ef0dad-c949-4a46-9306-d4a060a40a3b",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* 登录协议类型定义
|
|
||||||
*
|
|
||||||
* 注意: 这是临时定义,实际项目中应该通过 npm run sync-shared
|
|
||||||
* 从服务端同步完整的协议定义到 Shared 目录
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录请求
|
|
||||||
*/
|
|
||||||
export interface ReqLogin {
|
|
||||||
/** 账号 */
|
|
||||||
account: string;
|
|
||||||
/** 密码 (可选) */
|
|
||||||
password?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录响应
|
|
||||||
*/
|
|
||||||
export interface ResLogin {
|
|
||||||
/** 是否成功 */
|
|
||||||
success: boolean;
|
|
||||||
/** 消息 */
|
|
||||||
message?: string;
|
|
||||||
/** 玩家信息 */
|
|
||||||
player?: {
|
|
||||||
/** 玩家ID */
|
|
||||||
id: string;
|
|
||||||
/** 玩家名称 */
|
|
||||||
name: string;
|
|
||||||
/** 位置 */
|
|
||||||
position: { x: number; y: number; z: number };
|
|
||||||
/** 出生点 */
|
|
||||||
spawnPoint: { x: number; y: number; z: number };
|
|
||||||
/** 生命值 */
|
|
||||||
hp: number;
|
|
||||||
/** 最大生命值 */
|
|
||||||
maxHp: number;
|
|
||||||
/** 是否存活 */
|
|
||||||
isAlive: boolean;
|
|
||||||
/** 创建时间 */
|
|
||||||
createdAt: number;
|
|
||||||
/** 最后登录时间 */
|
|
||||||
lastLoginAt: number;
|
|
||||||
};
|
|
||||||
/** 是否新玩家 */
|
|
||||||
isNewPlayer?: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,29 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 网络协议类型
|
||||||
|
*/
|
||||||
|
export enum NetProtocolType {
|
||||||
|
/** HTTP/HTTPS 协议 */
|
||||||
|
Http = "http",
|
||||||
|
|
||||||
|
/** WebSocket 协议 */
|
||||||
|
WebSocket = "websocket"
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络配置接口
|
* 网络配置接口
|
||||||
*/
|
*/
|
||||||
export interface NetConfig {
|
export interface NetConfig {
|
||||||
/** 服务器地址 */
|
/** 服务器地址 */
|
||||||
serverUrl: string;
|
serverUrl: string;
|
||||||
|
|
||||||
|
/** 网络协议类型 默认 Http */
|
||||||
|
protocolType?: NetProtocolType;
|
||||||
|
|
||||||
/** 超时时间(ms) 默认 30000 */
|
/** 超时时间(ms) 默认 30000 */
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
|
||||||
/** 是否自动重连 默认 true */
|
/** 是否自动重连 默认 true */
|
||||||
autoReconnect?: boolean;
|
autoReconnect?: boolean;
|
||||||
|
|
||||||
/** 重连间隔(ms) 默认 3000 */
|
/** 重连间隔(ms) 默认 3000 */
|
||||||
reconnectInterval?: number;
|
reconnectInterval?: number;
|
||||||
|
|
||||||
/** 最大重连次数 默认 5 */
|
/** 最大重连次数 默认 5 */
|
||||||
maxReconnectTimes?: number;
|
maxReconnectTimes?: number;
|
||||||
|
|
||||||
|
/** 是否使用JSON格式 默认 true */
|
||||||
|
json?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认网络配置
|
* 默认网络配置
|
||||||
*/
|
*/
|
||||||
export const DefaultNetConfig: Partial<NetConfig> = {
|
export const DefaultNetConfig: Partial<NetConfig> = {
|
||||||
|
protocolType: NetProtocolType.Http,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
autoReconnect: true,
|
autoReconnect: true,
|
||||||
reconnectInterval: 3000,
|
reconnectInterval: 3000,
|
||||||
maxReconnectTimes: 5
|
maxReconnectTimes: 5,
|
||||||
|
json: true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,24 +2,27 @@
|
|||||||
* 网络事件定义
|
* 网络事件定义
|
||||||
*/
|
*/
|
||||||
export enum NetEvent {
|
export enum NetEvent {
|
||||||
|
/** 正在连接 */
|
||||||
|
Connecting = "net_connecting",
|
||||||
|
|
||||||
/** 连接成功 */
|
/** 连接成功 */
|
||||||
Connected = "net_connected",
|
Connected = "net_connected",
|
||||||
|
|
||||||
/** 连接断开 */
|
/** 连接断开 */
|
||||||
Disconnected = "net_disconnected",
|
Disconnected = "net_disconnected",
|
||||||
|
|
||||||
/** 正在重连 */
|
/** 正在重连 */
|
||||||
Reconnecting = "net_reconnecting",
|
Reconnecting = "net_reconnecting",
|
||||||
|
|
||||||
/** 重连成功 */
|
/** 重连成功 */
|
||||||
ReconnectSuccess = "net_reconnect_success",
|
ReconnectSuccess = "net_reconnect_success",
|
||||||
|
|
||||||
/** 重连失败 */
|
/** 重连失败 */
|
||||||
ReconnectFailed = "net_reconnect_failed",
|
ReconnectFailed = "net_reconnect_failed",
|
||||||
|
|
||||||
/** 网络错误 */
|
/** 网络错误 */
|
||||||
Error = "net_error",
|
Error = "net_error",
|
||||||
|
|
||||||
/** 连接超时 */
|
/** 连接超时 */
|
||||||
Timeout = "net_timeout"
|
Timeout = "net_timeout"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
import { NetConfig, DefaultNetConfig } from './NetConfig';
|
import { MessagePair, MessagePairRegistry } from '../../App/Msg/MessagePairBase';
|
||||||
|
import { DefaultNetConfig, NetConfig, NetProtocolType } from './NetConfig';
|
||||||
import { NetEvent } from './NetEvent';
|
import { NetEvent } from './NetEvent';
|
||||||
import { PlatformAdapter, ClientConfig } from './PlatformAdapter';
|
import { ClientConfig, PlatformAdapter } from './PlatformAdapter';
|
||||||
|
import { INetClient } from './WebSocketClient';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络管理器单例
|
* 网络管理器单例
|
||||||
* 负责管理网络连接和消息通信
|
* 负责管理网络连接和消息通信
|
||||||
|
* 支持 HTTP 和 WebSocket 两种协议
|
||||||
*/
|
*/
|
||||||
export class NetManager {
|
export class NetManager {
|
||||||
private static _instance: NetManager | null = null;
|
private static _instance: NetManager | null = null;
|
||||||
|
|
||||||
/** TSRPC Client 实例 (HttpClient) */
|
/** TSRPC Client 实例 (HttpClient 或 WsClient) */
|
||||||
private _client: any = null;
|
private _client: INetClient | null = null;
|
||||||
|
|
||||||
/** 是否已连接 */
|
/** 是否已连接 */
|
||||||
private _isConnected: boolean = false;
|
private _isConnected: boolean = false;
|
||||||
|
|
||||||
/** 网络配置 */
|
/** 网络配置 */
|
||||||
private _config: NetConfig | null = null;
|
private _config: NetConfig | null = null;
|
||||||
|
|
||||||
/** 重连计数 */
|
/** 重连计数 */
|
||||||
private _reconnectCount: number = 0;
|
private _reconnectCount: number = 0;
|
||||||
|
|
||||||
/** 重连定时器 */
|
/** 重连定时器 */
|
||||||
private _reconnectTimer: any = null;
|
private _reconnectTimer: any = null;
|
||||||
|
|
||||||
/** 事件监听器 */
|
/** 事件监听器 */
|
||||||
private _eventListeners: Map<string, Function[]> = new Map();
|
private _eventListeners: Map<string, Function[]> = new Map();
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单例实例
|
* 获取单例实例
|
||||||
@@ -58,6 +61,7 @@ export class NetManager {
|
|||||||
} as NetConfig;
|
} as NetConfig;
|
||||||
|
|
||||||
console.log('[NetManager] Initialized with config:', this._config);
|
console.log('[NetManager] Initialized with config:', this._config);
|
||||||
|
console.log('[NetManager] Protocol:', this._config.protocolType);
|
||||||
console.log('[NetManager] Platform:', PlatformAdapter.getPlatformInfo());
|
console.log('[NetManager] Platform:', PlatformAdapter.getPlatformInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,46 +70,56 @@ export class NetManager {
|
|||||||
*/
|
*/
|
||||||
async connect(): Promise<boolean> {
|
async connect(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
if (!this._config) {
|
||||||
|
console.error('[NetManager] Config not set, please call init() first');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[NetManager] Connecting to server:', this._config.serverUrl);
|
console.log('[NetManager] Connecting to server:', this._config.serverUrl);
|
||||||
|
|
||||||
// 创建客户端配置
|
// 创建客户端配置
|
||||||
const clientConfig: ClientConfig = {
|
const clientConfig: ClientConfig = {
|
||||||
server: this._config.serverUrl,
|
server: this._config.serverUrl,
|
||||||
json: true,
|
protocolType: this._config.protocolType,
|
||||||
timeout: this._config.timeout
|
json: this._config.json,
|
||||||
|
timeout: this._config.timeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据平台创建对应的客户端
|
// 根据平台和协议类型创建对应的客户端
|
||||||
this._client = PlatformAdapter.createClient(clientConfig);
|
this._client = PlatformAdapter.createClient(clientConfig);
|
||||||
|
|
||||||
// HttpClient 不需要显式连接,创建即可使用
|
// 如果是 WebSocket 客户端,需要显式连接
|
||||||
// 如果未来需要 WebSocket 支持,可以在这里添加 connect() 调用
|
if (this._config.protocolType === NetProtocolType.WebSocket && this._client.connect) {
|
||||||
|
this.emit(NetEvent.Connecting);
|
||||||
|
|
||||||
|
const result = await this._client.connect();
|
||||||
|
if (!result.isSucc) {
|
||||||
|
console.error('[NetManager] WebSocket connection failed:', result.errMsg);
|
||||||
|
this.emit(NetEvent.Error, result.errMsg);
|
||||||
|
|
||||||
|
// 尝试重连
|
||||||
|
if (this._config.autoReconnect) {
|
||||||
|
this.scheduleReconnect();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._isConnected = true;
|
this._isConnected = true;
|
||||||
this._reconnectCount = 0;
|
this._reconnectCount = 0;
|
||||||
|
|
||||||
this.emit(NetEvent.Connected);
|
|
||||||
console.log('[NetManager] Client created successfully');
|
|
||||||
|
|
||||||
// client 可能不需要显式连接
|
|
||||||
// 对于 WsClient 需要调用 connect()
|
|
||||||
|
|
||||||
this._isConnected = true;
|
|
||||||
this._reconnectCount = 0;
|
|
||||||
|
|
||||||
this.emit(NetEvent.Connected);
|
this.emit(NetEvent.Connected);
|
||||||
console.log('[NetManager] Connected successfully');
|
console.log('[NetManager] Connected successfully');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[NetManager] Connection failed:', error);
|
console.error('[NetManager] Connection failed:', error);
|
||||||
this.emit(NetEvent.Error, error);
|
this.emit(NetEvent.Error, error);
|
||||||
|
|
||||||
// 尝试重连
|
// 尝试重连
|
||||||
if (this._config.autoReconnect) {
|
if (this._config?.autoReconnect) {
|
||||||
this.scheduleReconnect();
|
this.scheduleReconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,26 +128,26 @@ export class NetManager {
|
|||||||
* 断开连接
|
* 断开连接
|
||||||
*/
|
*/
|
||||||
disconnect(): void {
|
disconnect(): void {
|
||||||
if (!this._isConnected) {
|
if (!this._isConnected || !this._client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// HttpClient 无需显式断开连接
|
|
||||||
// 如果使用 WebSocket,可以在这里调用 disconnect()
|
console.log('[NetManager] Disconnecting...');
|
||||||
|
|
||||||
this._isConnected = false;
|
// 清除重连定时器
|
||||||
this._client = null;
|
if (this._reconnectTimer) {
|
||||||
if(this._reconnectTimer){
|
clearTimeout(this._reconnectTimer);
|
||||||
this._reconnectTimer = null;
|
this._reconnectTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 调用客户端的断开连接方法
|
// 如果是 WebSocket 客户端,调用断开连接方法
|
||||||
if (this._client && typeof this._client.disconnect === 'function') {
|
if (this._client.disconnect) {
|
||||||
this._client.disconnect();
|
this._client.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isConnected = false;
|
this._isConnected = false;
|
||||||
this._client = null;
|
this._client = null;
|
||||||
|
|
||||||
this.emit(NetEvent.Disconnected);
|
this.emit(NetEvent.Disconnected);
|
||||||
console.log('[NetManager] Disconnected');
|
console.log('[NetManager] Disconnected');
|
||||||
}
|
}
|
||||||
@@ -151,13 +165,12 @@ export class NetManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`[NetManager] Calling API: ${apiName}`, req);
|
console.log(`[NetManager] Calling API: ${apiName}`, req);
|
||||||
|
|
||||||
// TODO: 根据实际的协议定义调用 API
|
|
||||||
const result = await this._client.callApi(apiName, req);
|
const result = await this._client.callApi(apiName, req);
|
||||||
|
|
||||||
if (result.isSucc) {
|
if (result.isSucc) {
|
||||||
console.log(`[NetManager] API ${apiName} success:`, result.res);
|
console.log(`[NetManager] API ${apiName} success:`, result.res);
|
||||||
return result.res;
|
return result.res as Res;
|
||||||
} else {
|
} else {
|
||||||
console.error(`[NetManager] API ${apiName} failed:`, result.err);
|
console.error(`[NetManager] API ${apiName} failed:`, result.err);
|
||||||
return null;
|
return null;
|
||||||
@@ -170,7 +183,7 @@ export class NetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听消息
|
* 监听消息 (仅支持 WebSocket)
|
||||||
* @param msgName 消息名称
|
* @param msgName 消息名称
|
||||||
* @param handler 处理函数
|
* @param handler 处理函数
|
||||||
*/
|
*/
|
||||||
@@ -180,16 +193,91 @@ export class NetManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[NetManager] Listening message: ${msgName}`);
|
if (!this._client.listenMsg) {
|
||||||
|
console.warn('[NetManager] Message listening not supported for HTTP client');
|
||||||
// TODO: 根据实际的 TSRPC 客户端实现监听消息
|
return;
|
||||||
if (typeof this._client.listenMsg === 'function') {
|
|
||||||
this._client.listenMsg(msgName, handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[NetManager] Listening message: ${msgName}`);
|
||||||
|
this._client.listenMsg(msgName, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 取消监听消息 (仅支持 WebSocket)
|
||||||
|
* @param msgName 消息名称
|
||||||
|
* @param handler 处理函数(可选,不传则取消所有该消息的监听)
|
||||||
|
*/
|
||||||
|
unlistenMsg(msgName: string, handler?: Function): void {
|
||||||
|
if (!this._client) {
|
||||||
|
console.error('[NetManager] Client not initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._client.unlistenMsg) {
|
||||||
|
console.warn('[NetManager] Message listening not supported for HTTP client');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[NetManager] Unlisten message: ${msgName}`);
|
||||||
|
this._client.unlistenMsg(msgName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息并等待响应 (基于消息对系统)
|
||||||
|
* @param messagePair 消息对实例
|
||||||
|
* @param requestData 请求消息内容
|
||||||
|
* @returns Promise<响应消息>
|
||||||
|
*/
|
||||||
|
async callMsg<TReq, TRes>(messagePair: MessagePair<TReq, TRes>, requestData: TReq): Promise<TRes | null> {
|
||||||
|
if (!this._isConnected || !this._client) {
|
||||||
|
console.error('[NetManager] Not connected');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestName = messagePair.requestName;
|
||||||
|
const responseName = messagePair.responseName;
|
||||||
|
|
||||||
|
// 验证请求消息格式
|
||||||
|
if (!messagePair.isValidRequest(requestData)) {
|
||||||
|
console.error(`[NetManager] Invalid request data for ${requestName}:`, requestData);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[NetManager] Calling message: ${requestName} -> ${responseName}`, requestData);
|
||||||
|
|
||||||
|
return new Promise<TRes | null>((resolve, reject) => {
|
||||||
|
// 创建一次性响应处理器
|
||||||
|
const responseHandler = (response: TRes) => {
|
||||||
|
// 验证响应消息格式
|
||||||
|
if (!messagePair.isValidResponse(response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消监听
|
||||||
|
this.unlistenMsg(responseName, responseHandler);
|
||||||
|
// 返回响应
|
||||||
|
console.log(`[NetManager] Received response for ${requestName}:`, response);
|
||||||
|
resolve(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听响应
|
||||||
|
this.listenMsg(responseName, responseHandler);
|
||||||
|
|
||||||
|
// 发送请求消息
|
||||||
|
this.sendMsg(requestName, requestData);
|
||||||
|
|
||||||
|
// 设置超时处理
|
||||||
|
const timeout = this._config?.timeout || 30000;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.unlistenMsg(responseName, responseHandler);
|
||||||
|
console.error(`[NetManager] Request timeout for ${requestName}`);
|
||||||
|
resolve(null);
|
||||||
|
}, timeout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息 (仅支持 WebSocket)
|
||||||
* @param msgName 消息名称
|
* @param msgName 消息名称
|
||||||
* @param msg 消息内容
|
* @param msg 消息内容
|
||||||
*/
|
*/
|
||||||
@@ -199,12 +287,13 @@ export class NetManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[NetManager] Sending message: ${msgName}`, msg);
|
if (!this._client.sendMsg) {
|
||||||
|
console.warn('[NetManager] Message sending not supported for HTTP client');
|
||||||
// TODO: 根据实际的 TSRPC 客户端实现发送消息
|
return;
|
||||||
if (typeof this._client.sendMsg === 'function') {
|
|
||||||
this._client.sendMsg(msgName, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[NetManager] Sending message: ${msgName}`, msg);
|
||||||
|
this._client.sendMsg(msgName, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,9 +312,9 @@ export class NetManager {
|
|||||||
|
|
||||||
this._reconnectCount++;
|
this._reconnectCount++;
|
||||||
console.log(`[NetManager] Scheduling reconnect (${this._reconnectCount}/${this._config.maxReconnectTimes})...`);
|
console.log(`[NetManager] Scheduling reconnect (${this._reconnectCount}/${this._config.maxReconnectTimes})...`);
|
||||||
|
|
||||||
this.emit(NetEvent.Reconnecting, this._reconnectCount);
|
this.emit(NetEvent.Reconnecting, this._reconnectCount);
|
||||||
|
|
||||||
this._reconnectTimer = setTimeout(() => {
|
this._reconnectTimer = setTimeout(() => {
|
||||||
this.reconnect();
|
this.reconnect();
|
||||||
}, this._config.reconnectInterval || 3000);
|
}, this._config.reconnectInterval || 3000);
|
||||||
@@ -236,9 +325,9 @@ export class NetManager {
|
|||||||
*/
|
*/
|
||||||
private async reconnect(): Promise<void> {
|
private async reconnect(): Promise<void> {
|
||||||
console.log('[NetManager] Reconnecting...');
|
console.log('[NetManager] Reconnecting...');
|
||||||
|
|
||||||
const success = await this.connect();
|
const success = await this.connect();
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
this.emit(NetEvent.ReconnectSuccess);
|
this.emit(NetEvent.ReconnectSuccess);
|
||||||
} else if (this._config?.autoReconnect) {
|
} else if (this._config?.autoReconnect) {
|
||||||
@@ -301,7 +390,41 @@ export class NetManager {
|
|||||||
/**
|
/**
|
||||||
* 获取客户端实例
|
* 获取客户端实例
|
||||||
*/
|
*/
|
||||||
get client(): any {
|
get client(): INetClient | null {
|
||||||
return this._client;
|
return this._client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取协议类型
|
||||||
|
*/
|
||||||
|
get protocolType(): NetProtocolType | undefined {
|
||||||
|
return this._config?.protocolType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为 WebSocket 连接
|
||||||
|
*/
|
||||||
|
get isWebSocket(): boolean {
|
||||||
|
return this._config?.protocolType === NetProtocolType.WebSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为 HTTP 连接
|
||||||
|
*/
|
||||||
|
get isHttp(): boolean {
|
||||||
|
return this._config?.protocolType === NetProtocolType.Http;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已注册的消息对信息
|
||||||
|
* @returns 消息对列表
|
||||||
|
*/
|
||||||
|
getMessagePairs(): { requestName: string; responseName: string }[] {
|
||||||
|
const registry = MessagePairRegistry.getInstance();
|
||||||
|
return registry.getAllPairs().map(pair => ({
|
||||||
|
requestName: pair.requestName,
|
||||||
|
responseName: pair.responseName
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { sys } from 'cc';
|
import { sys } from 'cc';
|
||||||
// 使用别名导入避免命名冲突
|
// 使用别名导入避免命名冲突
|
||||||
import { BaseServiceType, HttpClient as HttpClientBrowser } from 'tsrpc-browser';
|
import { BaseServiceType, HttpClient as HttpClientBrowser, WsClient as WsClientBrowser } from 'tsrpc-browser';
|
||||||
import { HttpClient as HttpClientMiniapp } from 'tsrpc-miniapp';
|
import { HttpClient as HttpClientMiniapp, WsClient as WsClientMiniapp } from 'tsrpc-miniapp';
|
||||||
|
import { NetProtocolType } from './NetConfig';
|
||||||
|
import { INetClient, WebSocketClientWrapper } from './WebSocketClient';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台类型枚举
|
* 平台类型枚举
|
||||||
@@ -9,10 +11,10 @@ import { HttpClient as HttpClientMiniapp } from 'tsrpc-miniapp';
|
|||||||
export enum PlatformType {
|
export enum PlatformType {
|
||||||
/** 浏览器平台 */
|
/** 浏览器平台 */
|
||||||
Browser = "browser",
|
Browser = "browser",
|
||||||
|
|
||||||
/** 小程序平台 (微信、抖音、QQ等) */
|
/** 小程序平台 (微信、抖音、QQ等) */
|
||||||
MiniApp = "miniapp",
|
MiniApp = "miniapp",
|
||||||
|
|
||||||
/** 未知平台 */
|
/** 未知平台 */
|
||||||
Unknown = "unknown"
|
Unknown = "unknown"
|
||||||
}
|
}
|
||||||
@@ -23,22 +25,29 @@ export enum PlatformType {
|
|||||||
export interface ClientConfig {
|
export interface ClientConfig {
|
||||||
/** 服务器地址 */
|
/** 服务器地址 */
|
||||||
server: string;
|
server: string;
|
||||||
|
|
||||||
|
/** 网络协议类型 */
|
||||||
|
protocolType?: NetProtocolType;
|
||||||
|
|
||||||
/** 是否使用 JSON 格式 (默认 true) */
|
/** 是否使用 JSON 格式 (默认 true) */
|
||||||
json?: boolean;
|
json?: boolean;
|
||||||
|
|
||||||
/** 超时时间(ms) */
|
/** 超时时间(ms) */
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
|
||||||
/** 其他配置 */
|
/** 其他配置 */
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台适配器
|
* 平台适配器
|
||||||
* 根据当前平台返回对应的 TSRPC 客户端实现
|
* 根据当前平台和协议类型返回对应的 TSRPC 客户端实现
|
||||||
*
|
*
|
||||||
* 注意: TSRPC 不同平台的库中 API 是重名的,所以使用别名导入
|
* 支持协议:
|
||||||
|
* - HTTP/HTTPS: 用于无状态的API调用
|
||||||
|
* - WebSocket: 用于实时双向通信
|
||||||
|
*
|
||||||
|
* 支持平台:
|
||||||
* - tsrpc-browser: 用于浏览器和 XMLHttpRequest 兼容的环境
|
* - tsrpc-browser: 用于浏览器和 XMLHttpRequest 兼容的环境
|
||||||
* - tsrpc-miniapp: 用于微信、抖音、QQ 等小程序环境
|
* - tsrpc-miniapp: 用于微信、抖音、QQ 等小程序环境
|
||||||
*/
|
*/
|
||||||
@@ -94,11 +103,12 @@ export class PlatformAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建对应平台的 TSRPC 客户端实例
|
* 创建对应平台和协议的 TSRPC 客户端实例
|
||||||
* @param config 客户端配置
|
* @param config 客户端配置
|
||||||
*/
|
*/
|
||||||
static createClient<T extends BaseServiceType>(config: ClientConfig): HttpClientBrowser<T> | HttpClientMiniapp<T> {
|
static createClient<T extends BaseServiceType>(config: ClientConfig): INetClient<T> {
|
||||||
const platform = this.detectPlatform();
|
const platform = this.detectPlatform();
|
||||||
|
const protocolType = config.protocolType || NetProtocolType.Http;
|
||||||
|
|
||||||
// 默认配置
|
// 默认配置
|
||||||
const defaultConfig: ClientConfig = {
|
const defaultConfig: ClientConfig = {
|
||||||
@@ -115,19 +125,50 @@ export class PlatformAdapter {
|
|||||||
console.warn('[PlatformAdapter] Service protocol not set, please call setServiceProto() first');
|
console.warn('[PlatformAdapter] Service protocol not set, please call setServiceProto() first');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[PlatformAdapter] Creating ${protocolType} client for ${platform}:`, defaultConfig.server);
|
||||||
|
|
||||||
|
// 根据协议类型和平台创建对应的客户端
|
||||||
|
if (protocolType === NetProtocolType.WebSocket) {
|
||||||
|
return this.createWebSocketClient<T>(platform, defaultConfig);
|
||||||
|
} else {
|
||||||
|
return this.createHttpClient<T>(platform, defaultConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 HTTP 客户端
|
||||||
|
*/
|
||||||
|
private static createHttpClient<T extends BaseServiceType>(platform: PlatformType, config: ClientConfig): INetClient<T> {
|
||||||
let client: HttpClientBrowser<T> | HttpClientMiniapp<T>;
|
let client: HttpClientBrowser<T> | HttpClientMiniapp<T>;
|
||||||
|
|
||||||
// 根据平台创建对应的客户端
|
|
||||||
if (platform === PlatformType.MiniApp) {
|
if (platform === PlatformType.MiniApp) {
|
||||||
console.log('[PlatformAdapter] Creating MiniApp client:', defaultConfig.server);
|
client = new HttpClientMiniapp(this._serviceProto, config) as HttpClientMiniapp<T>;
|
||||||
client = new HttpClientMiniapp(this._serviceProto, defaultConfig) as HttpClientMiniapp<T>;
|
|
||||||
} else {
|
} else {
|
||||||
// 浏览器和其他 XMLHttpRequest 兼容环境使用 Browser 客户端
|
client = new HttpClientBrowser(this._serviceProto, config) as HttpClientBrowser<T>;
|
||||||
console.log('[PlatformAdapter] Creating Browser client:', defaultConfig.server);
|
|
||||||
client = new HttpClientBrowser(this._serviceProto, defaultConfig) as HttpClientBrowser<T>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return client;
|
// 包装 HTTP 客户端使其符合 INetClient 接口
|
||||||
|
return {
|
||||||
|
callApi: async <Req, Res>(apiName: string, req: Req) => {
|
||||||
|
return await client.callApi(apiName, req);
|
||||||
|
}
|
||||||
|
} as INetClient<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 WebSocket 客户端
|
||||||
|
*/
|
||||||
|
private static createWebSocketClient<T extends BaseServiceType>(platform: PlatformType, config: ClientConfig): INetClient<T> {
|
||||||
|
let wsClient: WsClientBrowser<T> | WsClientMiniapp<T>;
|
||||||
|
|
||||||
|
if (platform === PlatformType.MiniApp) {
|
||||||
|
wsClient = new WsClientMiniapp(this._serviceProto, config) as WsClientMiniapp<T>;
|
||||||
|
} else {
|
||||||
|
wsClient = new WsClientBrowser(this._serviceProto, config) as WsClientBrowser<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用包装器统一接口
|
||||||
|
return new WebSocketClientWrapper<T>(wsClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,303 +0,0 @@
|
|||||||
# 网络通信模块 (Framework/Net)
|
|
||||||
|
|
||||||
## 📋 模块概述
|
|
||||||
基于 TSRPC 的网络通信层,支持多平台(浏览器、小程序),提供 API 调用和服务器消息监听功能。
|
|
||||||
|
|
||||||
## 🎯 核心特性
|
|
||||||
- ✅ 跨平台支持(浏览器/小程序)
|
|
||||||
- ✅ 自动平台检测和适配
|
|
||||||
- ✅ 服务协议动态配置
|
|
||||||
- ✅ API 调用和消息监听
|
|
||||||
- ✅ 自动重连机制
|
|
||||||
- ✅ 完整的事件系统
|
|
||||||
|
|
||||||
## 📦 依赖包
|
|
||||||
|
|
||||||
| 平台 | NPM 包 |
|
|
||||||
|------|--------|
|
|
||||||
| 浏览器 (Web) | `tsrpc-browser` |
|
|
||||||
| 小程序 (微信/抖音/QQ) | `tsrpc-miniapp` |
|
|
||||||
|
|
||||||
## 🗂️ 文件结构
|
|
||||||
|
|
||||||
```
|
|
||||||
Framework/Net/
|
|
||||||
├── NetManager.ts # 网络管理器(核心)
|
|
||||||
├── PlatformAdapter.ts # 平台适配器
|
|
||||||
├── NetConfig.ts # 网络配置
|
|
||||||
├── NetEvent.ts # 网络事件
|
|
||||||
├── LoginProtocol.ts # 登录协议(临时)
|
|
||||||
└── NetExample.ts # 使用示例
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📘 核心类详解
|
|
||||||
|
|
||||||
### NetManager - 网络管理器
|
|
||||||
|
|
||||||
**职责**: 网络连接管理、消息收发、重连机制
|
|
||||||
|
|
||||||
**核心方法**:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
class NetManager {
|
|
||||||
// 获取单例
|
|
||||||
static getInstance(): NetManager;
|
|
||||||
|
|
||||||
// 设置服务协议(必须在 init 之前调用)
|
|
||||||
setServiceProto(serviceProto: ServiceProto): void;
|
|
||||||
|
|
||||||
// 初始化网络配置
|
|
||||||
init(config: NetConfig): void;
|
|
||||||
|
|
||||||
// 创建客户端实例并连接
|
|
||||||
connect(): Promise<boolean>;
|
|
||||||
|
|
||||||
// 断开连接并清理资源
|
|
||||||
disconnect(): void;
|
|
||||||
|
|
||||||
// 调用 API
|
|
||||||
callApi<Req, Res>(apiName: string, req: Req): Promise<Res | null>;
|
|
||||||
|
|
||||||
// 监听服务器消息
|
|
||||||
listenMsg<T>(msgName: string, handler: (msg: T) => void): void;
|
|
||||||
|
|
||||||
// 取消监听服务器消息
|
|
||||||
unlistenMsg(msgName: string, handler?: Function): void;
|
|
||||||
|
|
||||||
// 发送消息到服务器
|
|
||||||
sendMsg<T>(msgName: string, msg: T): Promise<void>;
|
|
||||||
|
|
||||||
// 监听网络事件
|
|
||||||
on(event: NetEvent, callback: Function): void;
|
|
||||||
|
|
||||||
// 取消监听网络事件
|
|
||||||
off(event: NetEvent, callback: Function): void;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### PlatformAdapter - 平台适配器
|
|
||||||
|
|
||||||
**职责**: 根据运行平台创建对应的 TSRPC 客户端
|
|
||||||
|
|
||||||
**技术实现**:
|
|
||||||
- 使用别名导入: `HttpClient as HttpClientBrowser` 和 `HttpClient as HttpClientMiniapp`
|
|
||||||
- 自动检测 Cocos 平台类型 (`sys.platform`)
|
|
||||||
- 根据平台实例化对应的客户端
|
|
||||||
|
|
||||||
**核心方法**:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
class PlatformAdapter {
|
|
||||||
// 设置服务协议
|
|
||||||
static setServiceProto(serviceProto: ServiceProto): void;
|
|
||||||
|
|
||||||
// 检测当前运行平台
|
|
||||||
static detectPlatform(): string;
|
|
||||||
|
|
||||||
// 创建对应平台的客户端实例
|
|
||||||
static createClient(config: NetConfig): HttpClient | null;
|
|
||||||
|
|
||||||
// 获取当前平台
|
|
||||||
static getCurrentPlatform(): string;
|
|
||||||
|
|
||||||
// 平台判断
|
|
||||||
static isMiniApp(): boolean;
|
|
||||||
static isBrowser(): boolean;
|
|
||||||
|
|
||||||
// 获取平台详细信息
|
|
||||||
static getPlatformInfo(): object;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### NetConfig - 网络配置
|
|
||||||
|
|
||||||
**配置接口**:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface NetConfig {
|
|
||||||
serverUrl: string; // 服务器地址
|
|
||||||
timeout?: number; // 超时时间(ms) 默认 30000
|
|
||||||
autoReconnect?: boolean; // 是否自动重连 默认 true
|
|
||||||
reconnectInterval?: number; // 重连间隔(ms) 默认 3000
|
|
||||||
maxReconnectTimes?: number; // 最大重连次数 默认 5
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认配置
|
|
||||||
const DefaultNetConfig: Partial<NetConfig>;
|
|
||||||
```
|
|
||||||
|
|
||||||
### NetEvent - 网络事件
|
|
||||||
|
|
||||||
**事件类型**:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
enum NetEvent {
|
|
||||||
Connected = "net_connected", // 连接成功
|
|
||||||
Disconnected = "net_disconnected", // 连接断开
|
|
||||||
Reconnecting = "net_reconnecting", // 正在重连
|
|
||||||
ReconnectSuccess = "net_reconnect_success", // 重连成功
|
|
||||||
ReconnectFailed = "net_reconnect_failed", // 重连失败
|
|
||||||
Error = "net_error", // 网络错误
|
|
||||||
Timeout = "net_timeout" // 连接超时
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 使用指南
|
|
||||||
|
|
||||||
### 1. 基础使用流程
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { NetManager } from './Framework/Net/NetManager';
|
|
||||||
import { NetConfig } from './Framework/Net/NetConfig';
|
|
||||||
import { NetEvent } from './Framework/Net/NetEvent';
|
|
||||||
import { serviceProto } from '../Shared/protocols/serviceProto';
|
|
||||||
|
|
||||||
// 1. 获取实例并设置协议
|
|
||||||
const netManager = NetManager.getInstance();
|
|
||||||
netManager.setServiceProto(serviceProto); // 必须在 init 之前
|
|
||||||
|
|
||||||
// 2. 监听网络事件
|
|
||||||
netManager.on(NetEvent.Connected, () => {
|
|
||||||
console.log('✅ 网络已连接');
|
|
||||||
});
|
|
||||||
|
|
||||||
netManager.on(NetEvent.Disconnected, () => {
|
|
||||||
console.log('❌ 网络已断开');
|
|
||||||
});
|
|
||||||
|
|
||||||
netManager.on(NetEvent.Error, (error: any) => {
|
|
||||||
console.error('⚠️ 网络错误:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. 初始化配置
|
|
||||||
const config: NetConfig = {
|
|
||||||
serverUrl: 'http://localhost:3000',
|
|
||||||
timeout: 30000,
|
|
||||||
autoReconnect: true,
|
|
||||||
reconnectInterval: 3000,
|
|
||||||
maxReconnectTimes: 5
|
|
||||||
};
|
|
||||||
netManager.init(config);
|
|
||||||
|
|
||||||
// 4. 连接服务器
|
|
||||||
const success = await netManager.connect();
|
|
||||||
if (success) {
|
|
||||||
console.log('✅ 网络初始化成功');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 调用 API
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { ReqLogin, ResLogin } from '../Shared/protocols/PtlLogin';
|
|
||||||
|
|
||||||
// 调用登录 API
|
|
||||||
const result = await netManager.callApi<ReqLogin, ResLogin>('Login', {
|
|
||||||
username: 'testUser',
|
|
||||||
password: '123456'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
console.log('登录成功:', result);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 监听服务器消息
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { MsgUserJoin } from '../Shared/protocols/MsgUserJoin';
|
|
||||||
|
|
||||||
// 监听用户加入消息
|
|
||||||
netManager.listenMsg<MsgUserJoin>('UserJoin', (msg) => {
|
|
||||||
console.log('有新用户加入:', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 取消监听
|
|
||||||
netManager.unlistenMsg('UserJoin');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 发送消息到服务器
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { MsgChat } from '../Shared/protocols/MsgChat';
|
|
||||||
|
|
||||||
// 发送聊天消息
|
|
||||||
await netManager.sendMsg<MsgChat>('Chat', {
|
|
||||||
content: 'Hello World!'
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 协议同步
|
|
||||||
|
|
||||||
### 同步脚本配置
|
|
||||||
|
|
||||||
**文件**: 项目根目录的 `sync-shared.js`
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 服务端共享目录
|
|
||||||
const serverSharedDir = path.join(__dirname, '../server/src/shared');
|
|
||||||
|
|
||||||
// 客户端目标目录
|
|
||||||
const clientSharedDir = path.join(__dirname, 'assets/scripts/Shared');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 使用步骤
|
|
||||||
|
|
||||||
1. **确保服务端项目位置**: 服务端项目应该在 `../server` 目录
|
|
||||||
2. **运行同步命令**:
|
|
||||||
```bash
|
|
||||||
npm run sync-shared
|
|
||||||
```
|
|
||||||
3. **导入协议**:
|
|
||||||
```typescript
|
|
||||||
import { serviceProto } from '../Shared/protocols/serviceProto';
|
|
||||||
import { ReqLogin, ResLogin } from '../Shared/protocols/PtlLogin';
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚠️ 注意事项
|
|
||||||
|
|
||||||
1. **协议必须先设置**: 在调用 `init()` 之前,必须先调用 `setServiceProto()`
|
|
||||||
2. **连接状态检查**: 调用 API 前确保已连接,否则会返回 null
|
|
||||||
3. **错误处理**: 建议监听 `NetEvent.Error` 事件处理网络错误
|
|
||||||
4. **资源清理**: 应用退出时调用 `disconnect()` 清理资源
|
|
||||||
5. **平台兼容**: PlatformAdapter 会自动处理平台差异,无需手动判断
|
|
||||||
|
|
||||||
## 🔍 调试技巧
|
|
||||||
|
|
||||||
### 启用详细日志
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// NetManager 内部已有详细的 console.log
|
|
||||||
// 可以根据日志前缀过滤:
|
|
||||||
// [NetManager] - 网络管理器日志
|
|
||||||
// [PlatformAdapter] - 平台适配器日志
|
|
||||||
```
|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
**问题1**: `协议未设置` 错误
|
|
||||||
```typescript
|
|
||||||
// 解决: 确保在 init 之前调用 setServiceProto
|
|
||||||
netManager.setServiceProto(serviceProto);
|
|
||||||
netManager.init(config);
|
|
||||||
```
|
|
||||||
|
|
||||||
**问题2**: `API 调用返回 null`
|
|
||||||
```typescript
|
|
||||||
// 解决: 检查网络连接状态
|
|
||||||
netManager.on(NetEvent.Connected, async () => {
|
|
||||||
// 在连接成功后再调用 API
|
|
||||||
const result = await netManager.callApi('Login', data);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**问题3**: 小程序平台客户端创建失败
|
|
||||||
```typescript
|
|
||||||
// 解决: 确保已安装 tsrpc-miniapp
|
|
||||||
npm install tsrpc-miniapp
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📚 参考资料
|
|
||||||
|
|
||||||
- [TSRPC 官方文档](https://tsrpc.cn/)
|
|
||||||
- [Cocos Creator 官方文档](https://docs.cocos.com/creator/manual/zh/)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"ver": "1.0.1",
|
|
||||||
"importer": "text",
|
|
||||||
"imported": true,
|
|
||||||
"uuid": "6eb67b95-26c3-410a-a9ee-441d4fa23371",
|
|
||||||
"files": [
|
|
||||||
".json"
|
|
||||||
],
|
|
||||||
"subMetas": {},
|
|
||||||
"userData": {}
|
|
||||||
}
|
|
||||||
11
client/assets/scripts/Shared/protocols/MsgReqLogin.ts
Normal file
11
client/assets/scripts/Shared/protocols/MsgReqLogin.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 登录请求消息
|
||||||
|
*/
|
||||||
|
export interface MsgReqLogin {
|
||||||
|
/** 玩家ID(用于识别玩家) */
|
||||||
|
playerId: string;
|
||||||
|
|
||||||
|
/** 玩家昵称(可选,新玩家时使用) */
|
||||||
|
playerName?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "24fdb58b-b594-4bcf-8695-2669bd9bf9ca",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
10
client/assets/scripts/Shared/protocols/MsgReqMove.ts
Normal file
10
client/assets/scripts/Shared/protocols/MsgReqMove.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* 移动请求消息
|
||||||
|
*/
|
||||||
|
export interface MsgReqMove {
|
||||||
|
/** X坐标 */
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/** Y坐标 */
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "b244e6e0-857f-41f2-ac85-c6130e61218b",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
7
client/assets/scripts/Shared/protocols/MsgReqSend.ts
Normal file
7
client/assets/scripts/Shared/protocols/MsgReqSend.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 发送消息请求
|
||||||
|
*/
|
||||||
|
export interface MsgReqSend {
|
||||||
|
/** 消息内容 */
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "b6e9ef16-0098-4050-a133-721d339159e5",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,61 +1,50 @@
|
|||||||
import { Position } from './base';
|
import { Position } from './base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录请求
|
* 玩家角色信息
|
||||||
*/
|
*/
|
||||||
export interface ReqLogin {
|
export interface PlayerInfo {
|
||||||
/** 玩家ID(用于识别玩家) */
|
/** 玩家ID */
|
||||||
playerId: string;
|
id: string;
|
||||||
|
|
||||||
/** 玩家昵称(可选,新玩家时使用) */
|
/** 玩家昵称 */
|
||||||
playerName?: string;
|
name: string;
|
||||||
}
|
|
||||||
|
/** 当前位置 */
|
||||||
/**
|
position: Position;
|
||||||
* 玩家角色信息
|
|
||||||
*/
|
/** 出生点 */
|
||||||
export interface PlayerInfo {
|
spawnPoint: Position;
|
||||||
/** 玩家ID */
|
|
||||||
id: string;
|
/** 当前生命值 */
|
||||||
|
hp: number;
|
||||||
/** 玩家昵称 */
|
|
||||||
name: string;
|
/** 最大生命值 */
|
||||||
|
maxHp: number;
|
||||||
/** 当前位置 */
|
|
||||||
position: Position;
|
/** 是否存活 */
|
||||||
|
isAlive: boolean;
|
||||||
/** 出生点 */
|
|
||||||
spawnPoint: Position;
|
/** 创建时间 */
|
||||||
|
createdAt: number;
|
||||||
/** 当前生命值 */
|
|
||||||
hp: number;
|
/** 最后登录时间 */
|
||||||
|
lastLoginAt: number;
|
||||||
/** 最大生命值 */
|
}
|
||||||
maxHp: number;
|
|
||||||
|
/**
|
||||||
/** 是否存活 */
|
* 登录响应消息
|
||||||
isAlive: boolean;
|
*/
|
||||||
|
export interface MsgResLogin {
|
||||||
/** 创建时间 */
|
/** 是否成功 */
|
||||||
createdAt: number;
|
success: boolean;
|
||||||
|
|
||||||
/** 最后登录时间 */
|
/** 消息 */
|
||||||
lastLoginAt: number;
|
message: string;
|
||||||
}
|
|
||||||
|
/** 玩家信息 */
|
||||||
/**
|
player?: PlayerInfo;
|
||||||
* 登录响应
|
|
||||||
*/
|
/** 是否新玩家 */
|
||||||
export interface ResLogin {
|
isNewPlayer?: boolean;
|
||||||
/** 是否成功 */
|
}
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
/** 消息 */
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
/** 玩家信息 */
|
|
||||||
player?: PlayerInfo;
|
|
||||||
|
|
||||||
/** 是否新玩家 */
|
|
||||||
isNewPlayer?: boolean;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "dcefce3e-1a92-45ac-8d63-94fb1370edae",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
15
client/assets/scripts/Shared/protocols/MsgResMove.ts
Normal file
15
client/assets/scripts/Shared/protocols/MsgResMove.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Position } from './base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动响应消息
|
||||||
|
*/
|
||||||
|
export interface MsgResMove {
|
||||||
|
/** 是否成功 */
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
/** 消息 */
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
/** 新位置(成功时返回) */
|
||||||
|
position?: Position;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "e7ba8c78-ba4b-4dc6-a3de-352a5444421a",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
7
client/assets/scripts/Shared/protocols/MsgResSend.ts
Normal file
7
client/assets/scripts/Shared/protocols/MsgResSend.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 发送消息响应
|
||||||
|
*/
|
||||||
|
export interface MsgResSend {
|
||||||
|
/** 发送时间 */
|
||||||
|
time: Date;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "1fecff7f-ad47-4829-b229-e89e6e2e301e",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { Position } from './base';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动请求
|
|
||||||
*/
|
|
||||||
export interface ReqMove {
|
|
||||||
/** 目标位置 X 坐标 */
|
|
||||||
x: number;
|
|
||||||
|
|
||||||
/** 目标位置 Y 坐标 */
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动响应
|
|
||||||
*/
|
|
||||||
export interface ResMove {
|
|
||||||
/** 是否成功 */
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
/** 消息 */
|
|
||||||
message?: string;
|
|
||||||
|
|
||||||
/** 实际移动后的位置 */
|
|
||||||
position?: Position;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// This is a demo code file
|
|
||||||
// Feel free to delete it
|
|
||||||
|
|
||||||
export interface ReqSend {
|
|
||||||
content: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResSend {
|
|
||||||
time: Date
|
|
||||||
}
|
|
||||||
@@ -2,34 +2,32 @@ import { ServiceProto } from 'tsrpc-proto';
|
|||||||
import { MsgChat } from './MsgChat';
|
import { MsgChat } from './MsgChat';
|
||||||
import { MsgPlayerJoin } from './MsgPlayerJoin';
|
import { MsgPlayerJoin } from './MsgPlayerJoin';
|
||||||
import { MsgPlayerMove } from './MsgPlayerMove';
|
import { MsgPlayerMove } from './MsgPlayerMove';
|
||||||
import { ReqLogin, ResLogin } from './PtlLogin';
|
import { MsgReqLogin } from './MsgReqLogin';
|
||||||
import { ReqMove, ResMove } from './PtlMove';
|
import { MsgReqMove } from './MsgReqMove';
|
||||||
import { ReqSend, ResSend } from './PtlSend';
|
import { MsgReqSend } from './MsgReqSend';
|
||||||
|
import { MsgResLogin } from './MsgResLogin';
|
||||||
|
import { MsgResMove } from './MsgResMove';
|
||||||
|
import { MsgResSend } from './MsgResSend';
|
||||||
|
|
||||||
export interface ServiceType {
|
export interface ServiceType {
|
||||||
api: {
|
api: {
|
||||||
"Login": {
|
|
||||||
req: ReqLogin,
|
|
||||||
res: ResLogin
|
|
||||||
},
|
|
||||||
"Move": {
|
|
||||||
req: ReqMove,
|
|
||||||
res: ResMove
|
|
||||||
},
|
|
||||||
"Send": {
|
|
||||||
req: ReqSend,
|
|
||||||
res: ResSend
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
msg: {
|
msg: {
|
||||||
"Chat": MsgChat,
|
"Chat": MsgChat,
|
||||||
"PlayerJoin": MsgPlayerJoin,
|
"PlayerJoin": MsgPlayerJoin,
|
||||||
"PlayerMove": MsgPlayerMove
|
"PlayerMove": MsgPlayerMove,
|
||||||
|
"ReqLogin": MsgReqLogin,
|
||||||
|
"ReqMove": MsgReqMove,
|
||||||
|
"ReqSend": MsgReqSend,
|
||||||
|
"ResLogin": MsgResLogin,
|
||||||
|
"ResMove": MsgResMove,
|
||||||
|
"ResSend": MsgResSend
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const serviceProto: ServiceProto<ServiceType> = {
|
export const serviceProto: ServiceProto<ServiceType> = {
|
||||||
"version": 3,
|
"version": 5,
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
@@ -47,19 +45,34 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"type": "msg"
|
"type": "msg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 6,
|
||||||
"name": "Login",
|
"name": "ReqLogin",
|
||||||
"type": "api"
|
"type": "msg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 7,
|
||||||
"name": "Move",
|
"name": "ReqMove",
|
||||||
"type": "api"
|
"type": "msg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 8,
|
||||||
"name": "Send",
|
"name": "ReqSend",
|
||||||
"type": "api"
|
"type": "msg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "ResLogin",
|
||||||
|
"type": "msg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"name": "ResMove",
|
||||||
|
"type": "msg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"name": "ResSend",
|
||||||
|
"type": "msg"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types": {
|
"types": {
|
||||||
@@ -176,18 +189,18 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"PtlLogin/ReqLogin": {
|
"MsgReqLogin/MsgReqLogin": {
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 0,
|
||||||
"name": "playerId",
|
"name": "playerId",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "String"
|
"type": "String"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 1,
|
||||||
"name": "playerName",
|
"name": "playerName",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "String"
|
"type": "String"
|
||||||
@@ -196,7 +209,38 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"PtlLogin/ResLogin": {
|
"MsgReqMove/MsgReqMove": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "x",
|
||||||
|
"type": {
|
||||||
|
"type": "Number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "y",
|
||||||
|
"type": {
|
||||||
|
"type": "Number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"MsgReqSend/MsgReqSend": {
|
||||||
|
"type": "Interface",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "content",
|
||||||
|
"type": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"MsgResLogin/MsgResLogin": {
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
@@ -214,16 +258,16 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 2,
|
||||||
"name": "player",
|
"name": "player",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Reference",
|
"type": "Reference",
|
||||||
"target": "PtlLogin/PlayerInfo"
|
"target": "MsgResLogin/PlayerInfo"
|
||||||
},
|
},
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 3,
|
||||||
"name": "isNewPlayer",
|
"name": "isNewPlayer",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "Boolean"
|
"type": "Boolean"
|
||||||
@@ -232,7 +276,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"PtlLogin/PlayerInfo": {
|
"MsgResLogin/PlayerInfo": {
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
@@ -302,26 +346,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"PtlMove/ReqMove": {
|
"MsgResMove/MsgResMove": {
|
||||||
"type": "Interface",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": 0,
|
|
||||||
"name": "x",
|
|
||||||
"type": {
|
|
||||||
"type": "Number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "y",
|
|
||||||
"type": {
|
|
||||||
"type": "Number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PtlMove/ResMove": {
|
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
@@ -336,8 +361,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
"name": "message",
|
"name": "message",
|
||||||
"type": {
|
"type": {
|
||||||
"type": "String"
|
"type": "String"
|
||||||
},
|
}
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
@@ -350,19 +374,7 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"PtlSend/ReqSend": {
|
"MsgResSend/MsgResSend": {
|
||||||
"type": "Interface",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": 0,
|
|
||||||
"name": "content",
|
|
||||||
"type": {
|
|
||||||
"type": "String"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PtlSend/ResSend": {
|
|
||||||
"type": "Interface",
|
"type": "Interface",
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user