ET framework---MatchComponent study notes

MatchComponent

Please follow me on Weibo: @NormanLin_BadPixel Bad Pixel


The author notes that this is a matching component .

/// <summary>
/// 匹配组件,匹配逻辑在MatchComponentSystem扩展
/// </summary>
public class MatchComponent : Component
{
    //游戏中匹配对象列表
    public readonly Dictionary<long, long> Playing = new Dictionary<long, long>();

    //匹配成功队列
    public readonly Queue<Matcher> MatchSuccessQueue = new Queue<Matcher>();

    //创建房间消息加锁,避免因为延迟重复发多次创建房间消息
    public bool CreateRoomLock { get; set; }
}

Let's take a quick look at the Matcher .

/// <summary>
/// 匹配对象
/// </summary>
public sealed class Matcher : Entity
{
    //用户ID(唯一)
    public long UserID { get; private set; }
    //玩家GateActorID
    public long PlayerID { get; set; }
    //客户端与网关服务器的SessionID
    public long GateSessionID { get; set; }
    ...
}

A very simple class. Let's take a look at the extension of MatchComponent .

As we can see, it subscribes to the Update event for the MatchComponent component . The Update event is called every frame.

And there is a While loop in Update . Let's see where this cycle ends.

  1. Ends directly when no player is matched
  2. When there is no room available, it will try to create a new room and end

Note that the end of this loop can only indicate that the matching logic of this frame ends, not that it is no longer matched. Because Update is called every frame.

OK, let's see how it matches.

MatcherComponent matcherComponent = Game.Scene.GetComponent<MatcherComponent>();

MatcherComponent study notes

MatchRoomComponent study notes

...
Room room = roomManager.GetReadyRoom();
...
if (room == null && matchers.Count >= 3)
{
    //当还有一桌匹配玩家且没有可加入房间时使用空房间
    room = roomManager.GetIdleRoom();
}
...

What can we know from this code? This matching mechanism will give priority to filling unfilled rooms, and only one room will be filled before the next room is filled. Also a very simple mechanism.

Before looking at the next code, let's take a look at the JoinRoom and CreateRoom methods.

if (room != null)
{
    //当有准备状态房间且房间还有空位时匹配玩家直接加入填补空位
    while (matchers.Count > 0 && room.Count < 3)
    {
        self.JoinRoom(room, matcherComponent.Remove(matchers.Dequeue().UserID));
    }
}
else if (matchers.Count >= 3)
{
    //当还有一桌匹配玩家且没有空房间时创建新房间
    self.CreateRoom();
    break;
}
else
{
    break;
}

//移除匹配成功玩家
while (self.MatchSuccessQueue.Count > 0)
{
    matcherComponent.Remove(self.MatchSuccessQueue.Dequeue().UserID);
}

These codes, the author's comments are very detailed. However, everyone should pay attention here that in the last step of each matching loop logic execution, it will traverse the list of players that have been successfully matched in this loop, and remove them from the matcherComponent component. However, we know that when the player joins the room, the matcherComponent.Remove method is used, which has been removed. Will this be a repeated operation? For now, I think yes.

public static async void JoinRoom(this MatchComponent self, Room room, Matcher matcher)
{
    //玩家加入房间,移除匹配队列
    self.Playing[matcher.UserID] = room.Id;
    self.MatchSuccessQueue.Enqueue(matcher);

    //向房间服务器发送玩家进入请求
    ActorProxy actorProxy = Game.Scene.GetComponent<ActorProxyComponent>().Get(room.Id);
    Actor_PlayerEnterRoom_Ack actor_PlayerEnterRoom_Ack = await actorProxy.Call(new Actor_PlayerEnterRoom_Req()
    {
        PlayerID = matcher.PlayerID,
        UserID = matcher.UserID,
        SessionID = matcher.GateSessionID
    }) as Actor_PlayerEnterRoom_Ack;

    Gamer gamer = GamerFactory.Create(matcher.PlayerID, matcher.UserID, actor_PlayerEnterRoom_Ack.GamerID);
    room.Add(gamer);

    ActorProxyComponent actorProxyComponent = Game.Scene.GetComponent<ActorProxyComponent>();

    //向玩家发送匹配成功消息
    ActorProxy gamerActorProxy = actorProxyComponent.Get(gamer.PlayerID);
    gamerActorProxy.Send(new Actor_MatchSucess_Ntt() { GamerID = gamer.Id });
}

First, modify its own attribute data. Because the room server is distributed, we use ActorProxy to pass the request. How the server will deal with this message will be discussed later when we talk about the entire game process.

The same is true for creating a room. It will send a request to create a room, and then use the reply Id to create a Room to manage it. However, it should be noted here that the "lock" of CreateRoomLock is used here. Why use this? As we said before, the matching logic for each frame is an infinite loop, and each frame starts a new loop. And our operation of creating a room is asynchronous and requires network transmission. Before we get the remote reply, the matching logic is still running. When it finds that it still has no new room, it will continue to send a request to create a room. Therefore, when we send the create request for the first time, it will Marked with this lock, I've sent a create request, and I'm still waiting, you don't send it any more. Until we asynchronously get the reply from the remote end and create a new room, we will unlock the lock and start receiving new room creation requests.

public static async void CreateRoom(this MatchComponent self)
{
    if (self.CreateRoomLock)
    {
        return;
    }

    //消息加锁,避免因为延迟重复发多次创建消息
    self.CreateRoomLock = true;

    //发送创建房间消息
    IPEndPoint mapIPEndPoint = Game.Scene.GetComponent<AllotMapComponent>().GetAddress().GetComponent<InnerConfig>().IPEndPoint;
    Session mapSession = Game.Scene.GetComponent<NetInnerComponent>().Get(mapIPEndPoint);
    MP2MH_CreateRoom_Ack createRoomRE = await mapSession.Call(new MH2MP_CreateRoom_Req()) as MP2MH_CreateRoom_Ack;

    Room room = ComponentFactory.CreateWithId<Room>(createRoomRE.RoomID);
    Game.Scene.GetComponent<MatchRoomComponent>().Add(room);

    //解锁
    self.CreateRoomLock = false;
}

The specific processing of these messages will be discussed later.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325815557&siteId=291194637