ET篇:master消息机制介绍(一般消息的流转)

26 篇文章 14 订阅

终于到了核心部分之一了——消息机制

既然讲到消息,我们要到消息的源头——客户端

来到Unity.Hotfix的Init文件,并定位到这一句

Game.EventSystem.Run(EventIdType.InitSceneStart);

 他会执行这里的Run代码(不知道为何的去复习ETBook的EventSystem哦)

进入UILoginFactory,他是登录UI的工厂类,在这个工厂将完成一系列的操作

//获取资源组件,用以加载资源
ResourcesComponent resourcesComponent = ETModel.Game.Scene.GetComponent<ResourcesComponent>();
//加载UI的AB包
resourcesComponent.LoadBundle(UIType.UILogin.StringToAB());
//获取到登录UI
GameObject bundleGameObject = (GameObject)resourcesComponent.GetAsset(UIType.UILogin.StringToAB(), UIType.UILogin);
//实例化登录UI
GameObject gameObject = UnityEngine.Object.Instantiate(bundleGameObject);
//在组件工厂创建UI(主要是为了能给游戏物体添加上组件做准备)
UI ui = ComponentFactory.Create<UI, string, GameObject>(UIType.UILogin, gameObject, false);
//为UI添加登录UI组件
ui.AddComponent<UILoginComponent>();

然后我们知道添加一个组件会执行其的Awake函数(如果存在并写明了继承自AwakeSystem的类),我们看到,他在Awake里面从其挂载的ReferenceCollector取得自身子物体的引用,并且为Button添加了点击事件

public void Awake()
{
	ReferenceCollector rc = this.GetParent<UI().GameObject.GetComponent<ReferenceCollector>();
	loginBtn = rc.Get<GameObject>("LoginBtn");
	loginBtn.GetComponent<Button>().onClick.Add(OnLogin);
	this.account = rc.Get<GameObject>("Account");
}

public void OnLogin()
{
	LoginHelper.OnLoginAsync(this.account.GetComponent<InputField>().text).Coroutine();
}

那么我们去看OnLoginAsync函数 ,知道我为什么在最后空两行吗?(观众:装起来了???)

是因为这里用的await 和 Session.Call方法,await是阻塞方法,在返回结果之前不会继续往下走,而Call是要求有反馈消息的,综上只有在收到消息或者遇到异常才会有可能(异常的话程序将停止运行)执行到R2C_Login reCLogin这里,然后才会走最后一行

// 创建一个ETModel层的Session
ETModel.Session session = ETModel.Game.Scene.GetComponent<NetOuterComponent>().Create(GlobalConfigComponent.Instance.GlobalProto.Address);
// 创建一个ETHotfix层的Session, ETHotfix的Session会通过ETModel层的Session发送消息
Session realmSession = ComponentFactory.Create<Session, ETModel.Session>(session);
//发送登录请求,账号,密码均为传来的参数(理应这样,但这是例子,就无所谓了)
R2C_Login r2CLogin = (R2C_Login) await realmSession.Call(new C2R_Login() { Account = account, Password = "111111" });
                
                
//释放realmSession
realmSession.Dispose();

注意 第二句的Awake注册了消息回调函数,并且这里的Session是ETHotfix的,与ETModel下的Session有区别

public override void Awake(Session self, ETModel.Session session)
{
	self.session = session;
	SessionCallbackComponent sessionComponent = self.session.AddComponent<SessionCallbackComponent>();
	sessionComponent.MessageCallback = (s, opcode, memoryStream) => { self.Run(s, opcode, memoryStream); };
	sessionComponent.DisposeCallback = s => { self.Dispose(); };
}

好,既然消息发走了,我们就去看服务端了 

我们直接从NetworkComponent看起吧(事实上客户端和服务端用的是同一个NetworkComponent,所以这里的NetworkComponent组件看完就不需要重复看客户端的了)

// 外网消息组件
Game.Scene.AddComponent<NetOuterComponent, string>(outerConfig.Address);
 |
 |
\|/
K component = ComponentFactory.CreateWithParent<K, P1>(this, p1, this.IsFromPool);
 |
 |
\|/
Game.EventSystem.Awake(component, a);
 |
 |
\|/
[ObjectSystem]
public class NetOuterComponentAwake1System : AwakeSystem<NetOuterComponent, string>
{
	public override void Awake(NetOuterComponent self, string address)
	{
	}
}
 |
 |
\|/
public void Awake(NetworkProtocol protocol, string address, int packetSize = Packet.PacketSizeLength2)
{
}

 因为默认是TCP,所以绑定OnAccept(当收到消息,他会被调用)

public void OnAccept(AChannel channel)
 |
 |
\|/
//ETModel.Session.cs
public void Awake(AChannel aChannel)
 |
 |
\|/
注册收到消息回调函数
//ETModel.Session.cs
public void OnRead(MemoryStream memoryStream)
 |
 |
\|/
//TChannel.cs
public override void Start()
 |
 |
\|/
开始接收消息
//TChannel.cs
private void StartRecv()
 |
 |
\|/
接收消息完毕,解析好收到的信息,通过消息回调函数处理消息,
如果是热更层的消息,就调用ETHotfix.Session里注册的回调函数处理,
否则就用ETModel.Session里的函数处理,
(其实两者也是大同小异,大家可以自行查看各个Session的Run函数)
这里面又涉及到消息分发组件MessageDispatcherComponent以及requestCallback的细节,
大家可以自行查看
最后发送消息
 |
 |
\|/
//TChannel.cs
public void StartSend()

更多细节我会在之后介绍,我们这里的Handler是C2R_LoginHandler.cs

//这里是进行数据库验证,作为例子,这里去掉了验证
//if (message.Account != "abcdef" || message.Password != "111111")
//{
//	response.Error = ErrorCode.ERR_AccountOrPasswordError;
//	reply(response);
//	return;
//}

// 随机分配一个Gate
StartConfig config = Game.Scene.GetComponent<RealmGateAddressComponent>().GetAddress();
//Log.Debug($"gate address: {MongoHelper.ToJson(config)}");

//读取内部服务器地址
IPEndPoint innerAddress = config.GetComponent<InnerConfig>().IPEndPoint;

//从地址缓存中取Session,如果没有则创建一个新的Session,并且保存到地址缓存中
Session gateSession = Game.Scene.GetComponent<NetInnerComponent>().Get(innerAddress);

// 向gate服务器请求一个key,客户端可以拿着这个key连接gate
G2R_GetLoginKey g2RGetLoginKey = (G2R_GetLoginKey)await gateSession.Call(new R2G_GetLoginKey() {Account = message.Account});

//上述过程已完成,将执行这句,获取外部服务器地址
string outerAddress = config.GetComponent<OuterConfig>().Address2;

//设置返回的信息
response.Address = outerAddress;
response.Key = g2RGetLoginKey.Key;
//回复客户端的登录请求
reply(response);

好了,服务端的消息发过来了,我们客户端要响应吧,再回到客户端,这时候r2CLogin已经被赋好值了,可以进行下面的操作了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值