Unity进阶之ET网络游戏开发框架 07-修正游客登录的异步BUG

版权申明:

  • 本文原创首发于以下网站:
  1. 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123
  2. 优梦创客的官方博客:https://91make.top
  3. 优梦创客的游戏讲堂:https://91make.ke.qq.com
  4. 『优梦创客』的微信公众号:umaketop
  • 您可以自由转载,但必须加入完整的版权声明!

由来

  • 我的上一篇博文中的OnStartClick方法采用的是async异步方法,但是由于微软并未保证async创建的方法一定在其调用线程中执行,所以不能保证程序是单线程的
  • ET整个框架都是基于多进程单线程这一设计思想的(为了避免多线程带来的性能损失和逻辑错误),所以为了避免async造成的多线程陷阱,ET自定义了一套多线程任务系统,其返回值类型都是以ET开头的,例如:
    • Task → ETTask
    • void → ETVoid
    • Task → ETTask
    • ET作者说过这么一句话:async方法的返回值永远不要用.NET原生的Task,全部采用ETTask
  • 配套的,我们需要修改原有的代码,如下:
public class MyStartUIComponent : Component
{
	GameObject goStartButton;

	public void OnAwake()
	{
		var rc = this.Parent.GameObject.GetComponent<ReferenceCollector>();
		goStartButton = rc.Get<GameObject>("StartButton");
		goStartButton.GetComponent<Button>().onClick.AddListener(OnStartClick);
	}

	private void OnStartClick()
	{
		// Coroutine()方法模拟将OnStartClickAsync()作为协程执行的效果(确保在单线程中执行)
		OnStartClickAsync().Coroutine();
	}

	private async ETVoid OnStartClickAsync()
	{
		// 处理游客登录点击
		try
		{
			// 1: 创建一个realmSession,并利用此session去call一个rpc消息(模型层session表示具体网络参数和连接,热更层负责通信逻辑,它调用模型层)
			ETModel.Session session = ETModel.Game.Scene.GetComponent<NetOuterComponent>().Create(GlobalConfigComponent.Instance.GlobalProto.Address);
			Session realmSession = ComponentFactory.Create<Session, ETModel.Session>(session);

			// 2:若登录失败,会收到异常;若成功,则会得到认证信息(模型层没有C2R_Login的类定义,所以必须配套由热更层的session去call)
			var r2cLogin = await realmSession.Call(new C2R_Login()
			{
				Account = Guid.NewGuid().ToString(),
				Password = "111111",
			}) as R2C_Login;

			// 3:再利用此认证信息中的网关服务器地址,去创建gateSession
			session = ETModel.Game.Scene.GetComponent<NetOuterComponent>().Create(r2cLogin.Address);
			Session gateSession = ComponentFactory.Create<Session, ETModel.Session>(session);

			// 4:用gateSession去登录gate服(传入登录key)
			var g2cLoginGate = await gateSession.Call(new C2G_LoginGate()
			{
				Key = r2cLogin.Key
			}) as G2C_LoginGate;

			// 5:登录成功后,用返回的playerId,创建Player对象
			var p = ETModel.ComponentFactory.CreateWithId<Player>(g2cLoginGate.PlayerId);
			ETModel.Game.Scene.GetComponent<PlayerComponent>().MyPlayer = p;

			// 6:发送登录完成事件
			Game.EventSystem.Run(MyEventType.MyLoginFinish);
		}
		catch (Exception e)
		{
			Log.Error(e);
		}
	}
}
原文地址:https://www.cnblogs.com/raymondking123/p/11369723.html