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

26 篇文章 14 订阅

继续上一次的一般消息流转,那么这次,我们来走一遍ET的另一核心——Actor消息机制

建议先看ETBook的Actor消息机制介绍,地址:

继续上次,我们回到客户端

// 创建一个ETModel层的Session,并且保存到ETModel.SessionComponent中
ETModel.Session gateSession = ETModel.Game.Scene.GetComponent<NetOuterComponent>().Create(r2CLogin.Address);
//添加ETModel.SessionComponent组件,并对Session赋值
ETModel.Game.Scene.AddComponent<ETModel.SessionComponent>().Session = gateSession;
				
// 创建一个ETHotfix层的Session, 并且保存到ETHotfix.SessionComponent中,
// 目前为止,所有客户端的消息的收发都将被GateSession管理
//(Model层和Hotfix层都有各自的GateSession,
// 本质上还是ETModel.Session和ETHotfix.Session)
Game.Scene.AddComponent<SessionComponent>().Session = ComponentFactory.Create<Session, ETModel.Session>(gateSession);
				
//向服务端请求登录进gate服务器,如果登录成功,此后与服务端的通信都将通过gate服务器这个中介者
G2C_LoginGate g2CLoginGate = (G2C_LoginGate)await SessionComponent.Instance.Session.Call(new C2G_LoginGate() { Key = r2CLogin.Key });

Log.Info("登陆gate成功!");

然后回到服务端

//从已经分发的KEY里面寻找,如果没找到,说明非法用户,不给他连接gate服务器
string account = Game.Scene.GetComponent<GateSessionKeyComponent>().Get(message.Key);
if (account == null)
{
	response.Error = ErrorCode.ERR_ConnectGateKeyError;
	response.Message = "Gate key验证失败!";
	reply(response);
	return;
}
//专门给这个玩家创建一个Player对象
Player player = ComponentFactory.Create<Player, string>(account);
//注册到PlayerComponent,方便管理
Game.Scene.GetComponent<PlayerComponent>().Add(player);

//给这个session安排上Player
session.AddComponent<SessionPlayerComponent>().Player = player;
//添加邮箱组件表示该session是一个Actor,接收的消息将会队列处理
session.AddComponent<MailBoxComponent, string>(MailboxType.GateSession);

response.PlayerId = player.Id;
				
//回复客户端的连接gate服务器请求
reply(response);

//向客户端发送热更层信息
session.Send(new G2C_TestHotfixMessage() { Info = "recv hotfix message success" });

再回到客户端

Log.Info("登陆gate成功!");

// 创建Player
Player player = ETModel.ComponentFactory.CreateWithId<Player>(g2CLoginGate.PlayerId);
PlayerComponent playerComponent = ETModel.Game.Scene.GetComponent<PlayerComponent>();
playerComponent.MyPlayer = player;

//分发登录完成的事件
Game.EventSystem.Run(EventIdType.LoginFinish);

// 测试消息有成员是class类型
G2C_PlayerInfo g2CPlayerInfo = (G2C_PlayerInfo) await SessionComponent.Instance.Session.Call(new C2G_PlayerInfo());
Debug.Log("测试玩家信息为" + g2CPlayerInfo.Message);

这下我们不用再回到服务端了,因为一般消息的流转我们了解的已经差不多了,我们直接来到下一个重要的阶段

来到MapHelper.cs类,查看登录Map服务器相关代码

// 获取资源组件
ResourcesComponent resourcesComponent = ETModel.Game.Scene.GetComponent<ResourcesComponent>();
// 加载Unit资源
await resourcesComponent.LoadBundleAsync($"unit.unity3d");

// 加载场景资源
await ETModel.Game.Scene.GetComponent<ResourcesComponent>().LoadBundleAsync("map.unity3d");
// 切换到map场景
using (SceneChangeComponent sceneChangeComponent = ETModel.Game.Scene.AddComponent<SceneChangeComponent>())
{
     await sceneChangeComponent.ChangeSceneAsync(SceneType.Map);
}
				
//请求登录Map服务器
G2C_EnterMap g2CEnterMap = await ETModel.SessionComponent.Instance.Session.Call(new C2G_EnterMap()) as G2C_EnterMap;

好了,我们又要去服务端了,注意,下面的消息是属于服务器内部的消息流通,所以不用网络层的传输,直接进行内部数据传输最后被响应Handler处理

//获取Player对象引用
Player player = session.GetComponent<SessionPlayerComponent>().Player;
// 在map服务器上创建战斗Unit
IPEndPoint mapAddress = StartConfigComponent.Instance.MapConfigs[0].GetComponent<InnerConfig>().IPEndPoint;
Session mapSession = Game.Scene.GetComponent<NetInnerComponent>().Get(mapAddress);
                
//由gate服务器向map服务器发送创建战斗单位请求,这里的session.InstanceId将由IdGenerater创建,
//用以保证不会冲突
M2G_CreateUnit createUnit =
(M2G_CreateUnit) await mapSession.Call(new G2M_CreateUnit() { PlayerId = player.Id, GateSessionId = session.InstanceId });

那我们直接到它的Handler这里吧

//创建战斗单位(小骷髅给劲哦)
Unit unit = ComponentFactory.CreateWithId<Unit>(IdGenerater.GenerateId());
//增加移动组件
unit.AddComponent<MoveComponent>();
//增加寻路相关组件
unit.AddComponent<UnitPathComponent>();
//设置小骷髅位置
unit.Position = new Vector3(-10, 0, -10);
				
//给小骷髅添加信箱组件,队列处理收到的消息
await unit.AddComponent<MailBoxComponent>().AddLocation();
//添加同gate服务器通信基础组件,主要是赋予ID
unit.AddComponent<UnitGateComponent, long>(message.GateSessionId);
//将这个小骷髅维护在Unit组件里
Game.Scene.GetComponent<UnitComponent>().Add(unit);
//设置回复消息的ID
response.UnitId = unit.Id;
				
// 广播创建的unit
M2C_CreateUnits createUnits = new M2C_CreateUnits();
Unit[] units = Game.Scene.GetComponent<UnitComponent>().GetAll();
foreach (Unit u in units)
{
	UnitInfo unitInfo = new UnitInfo();
	unitInfo.X = u.Position.x;
	unitInfo.Y = u.Position.y;
	unitInfo.Z = u.Position.z;
	unitInfo.UnitId = u.Id;
	createUnits.Units.Add(unitInfo);
}
//广播所有小骷髅信息
MessageHelper.Broadcast(createUnits); 
				
//广播完回复客户端,这边搞好了
reply(response);

 注意,这里面的MessageHelper.Broadcast(createUnits); 就是我们的核心Actor机制的体现了,我们只要把消息发到gatesession,gatesession将会自动根据id转发消息到相应客户端,而里面涉及到的相关ID,我们在gate服务器向map服务器发送创建战斗单位请求的时候,已经传好参数了

// 从Game.Scene上获取ActorSenderComponent,然后通过InstanceId获取ActorMessageSender
ActorSenderComponent actorSenderComponent = Game.Scene.GetComponent<ActorSenderComponent>();
ActorMessageSender actorMessageSender = actorSenderComponent.Get(unitGateComponent.GateSessionActorId);
// send
actorMessageSender.Send(message);

// rpc
var response = actorMessageSender.Call(message);

好了,回到客户端

//设置UnitID
PlayerComponent.Instance.MyPlayer.UnitId = g2CEnterMap.UnitId;
				
//增加。。。emmm不知道怎么翻译这个组件好,他负责点击地面控制小骷髅移动
Game.Scene.AddComponent<OperaComponent>();
				
//分发进入正式游戏成功事件
Game.EventSystem.Run(EventIdType.EnterMapFinish);

然后我们突然想起来,刚刚亡灵领主出生的时候向别的小骷髅广播了一下来着,我们看会做什么操作

foreach (UnitInfo unitInfo in message.Units)
{
	if (unitComponent.Get(unitInfo.UnitId) != null)
	{
		continue;
	}
	//根据不同ID,创建小骷髅
	Unit unit = UnitFactory.Create(unitInfo.UnitId);
	unit.Position = new Vector3(unitInfo.X, unitInfo.Y, unitInfo.Z);
}

好了 ,小骷髅都安排好了,该向服务端发消息了,也就是寻路,还记得我们之前添加的OperaComponent,他就是负责寻路的

//发送点击地图消息
ETModel.SessionComponent.Instance.Session.Send(frameClickMap);
 |
 |
 |
\|/
//服务端Frame_ClickMapHandler处理位置信息
Vector3 target = new Vector3(message.X, message.Y, message.Z);
unit.GetComponent<UnitPathComponent>().MoveTo(target).Coroutine();
 |
 |
 |
\|/
//移动到指定位置
await self.MoveAsync(self.ABPath.Result);
 |
 |
 |
\|/
// 每移动3个点发送下3个点给客户端
if (i % 3 == 1)
{
     self.BroadcastPath(path, i, 3);
}
 |
 |
 |
\|/
// 客户端处理服务端的同步信息,利用寻路组件进行寻路
unitPathComponent.StartMove(message).Coroutine();

后记

至此,连接服务器,创建小骷髅,并且自动寻路的操作就完成了,我中间很多细节没有讲,其实没必要讲(观众:懒还有理了???),那些东西需要大家自行理解和体会的,而到现在master的Demo解读也该告一段落了。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值