ActorComponent
请大家关注我的微博:@NormanLin_BadPixel坏像素
/// <summary>
/// 挂上这个组件表示该Entity是一个Actor, 它会将Entity位置注册到Location Server, 接收的消息将会队列处理
/// </summary>
这是作者对这个组件的注释。
public IEntityActorHandler entityActorHandler;
public long actorId;
// 队列处理消息
public Queue<ActorMessageInfo> queue;
public TaskCompletionSource<ActorMessageInfo> tcs;
这是它的属性,我们去看看它的扩展方法。
首先有两个Awake方法,一个传入IEntityActorHandler指定entityActorHandler,一个没有,使用默认的entityActorHandler。
我们来看看默认的entityActorHandler。
public class CommonEntityActorHandler : IEntityActorHandler
{
public async Task Handle(Session session, Entity entity, uint rpcId, ActorRequest message)
{
await Game.Scene.GetComponent<ActorMessageDispatherComponent>().Handle(session, entity, rpcId, message);
}
}
ActorMessageDispatherComponent学习笔记
顺便把其他的处理器也看了吧。
/// <summary>
/// gate session收到的消息直接转发给客户端
/// </summary>
public class GateSessionEntityActorHandler : IEntityActorHandler
{
public async Task Handle(Session session, Entity entity, uint rpcId, ActorRequest message)
{
ActorResponse response = new ActorResponse();
try
{
((Session)entity).Send((IMessage)message.AMessage);
session.Reply(rpcId, response);
await Task.CompletedTask;
}
catch (Exception e)
{
response.Error = ErrorCode.ERR_SessionActorError;
response.Message = $"session actor error {e}";
session.Reply(rpcId, response);
throw;
}
}
}
我们知道,传入的session是这次代理发送的会话Session,而传到这个处理器的entity是gate session,既Gate服务器与客户端的会话Session。通过这个Session可以直接跟客户端对话,所以可以直接转发。
/// <summary>
/// 玩家收到帧同步消息交给帧同步组件处理
/// </summary>
public class MapUnitEntityActorHandler : IEntityActorHandler
{
public async Task Handle(Session session, Entity entity, uint rpcId, ActorRequest message)
{
if (message.AMessage is IFrameMessage aFrameMessage)
{
// 客户端发送不需要设置Frame消息的id,在这里统一设置,防止客户端被破解发个假的id过来
aFrameMessage.Id = entity.Id;
Game.Scene.GetComponent<ServerFrameComponent>().Add(aFrameMessage);
ActorResponse response = new ActorResponse();
session.Reply(rpcId, response);
return;
}
await Game.Scene.GetComponent<ActorMessageDispatherComponent>().Handle(session, entity, rpcId, message);
}
}
回到ActorComponent,我们发现热更的处理也有不同。
// 热更新要重新创建接口,以便接口也能实现热更新
public static void Load(this ActorComponent self)
{
self.entityActorHandler = (IEntityActorHandler) HotfixHelper.Create(self.entityActorHandler);
}
HotfixHelper.Create的作用是从热更层的程序集里找到一个同名的类并返回一个实例。
AddLocation跟RemoveLocation方法是将自己的ID跟所在的服务器地址注册到(移除出)地址服务器。
后面的几个方法,则是对Actor消息的处理。
在添加ActorComponent组件的时候,就调用了HandleAsync方法,这个方法会等待有消息传入,如果有了,则开始处理这个消息,等消息处理完了,再开始等待下一个消息。
因为消息有个等待上一个消息处理完的过程,所以我们要把收到的消息存入队列中,处理完一个消息后,再从队列里获取。