任务36:后端出牌请求的Handler及前端收到广播有效出牌的Handler

服务端添加前端出牌、不出、获取提示牌请求对应的Handler

注意下牌序组件,出牌缓存组件是如何在这些handler中起作用的

GamerPlayCard_Handler

\Server\Hotfix\Landlords\Handler\Map\GamerPlayCard_Handler.cs

这个比较好理解,每次有人出牌,跟上家的出牌进行比较,符合规则清除上家的出牌缓存,此出牌加入到出牌缓存中。

//如果符合将牌从手牌移到出牌缓存区
deskCardsCache.Clear();
deskCardsCache.Rule = type;
HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>();
foreach (var card in request.Cards)
{
         handCards.PopCard(card);
         deskCardsCache.AddCard(card);
}


GamerPlayCard_Handler完整代码

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ETModel;

namespace ETHotfix
{
    [ActorMessageHandler(AppType.Map)]
    public class GamerPlayCard_Handler: AMActorRpcHandler<Gamer, Actor_GamerPlayCard_Req, Actor_GamerPlayCard_Back>
    {
        protected override async ETTask Run(Gamer gamer, Actor_GamerPlayCard_Req request, Actor_GamerPlayCard_Back response, Action reply)
        {
            try
            {
                Room room = Game.Scene.GetComponent<LandMatchComponent>().GetGamingRoom(gamer);

                GameControllerComponent gameController = room.GetComponent<GameControllerComponent>();
                DeskCardsCacheComponent deskCardsCache = room.GetComponent<DeskCardsCacheComponent>();
                OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();

                //检测是否符合出牌规则
                if (CardHelper.PopEnable(To.Array(request.Cards), out CardsType type))
                {
                    //当前出牌牌型是否比牌桌上牌型的权重更大
                    bool isWeightGreater = CardHelper.GetWeight(To.Array(request.Cards), type) > deskCardsCache.GetTotalWeight();
                    //当前出牌牌型是否和牌桌上牌型的数量一样
                    bool isSameCardsNum = request.Cards.Count == deskCardsCache.GetAll().Length;
                    //当前出牌玩家是否是上局最大出牌者
                    bool isBiggest = orderController.Biggest == orderController.CurrentAuthority;
                    //当前牌桌牌型是否是顺子
                    bool isStraight = deskCardsCache.Rule == CardsType.Straight || deskCardsCache.Rule == CardsType.DoubleStraight || deskCardsCache.Rule == CardsType.TripleStraight;
                    //当前出牌牌型是否和牌桌上牌型一样
                    bool isSameCardsType = type == deskCardsCache.Rule;

                    if (isBiggest ||    //先手出牌玩家
                        type == CardsType.JokerBoom ||  //王炸
                        type == CardsType.Boom && isWeightGreater ||    //更大的炸弹
                        isSameCardsType && isStraight && isSameCardsNum && isWeightGreater ||   //更大的顺子
                        isSameCardsType && isWeightGreater)     //更大的同类型牌
                    {
                        if (type == CardsType.JokerBoom)
                        {
                            //王炸翻4倍
                            gameController.Multiples *= 4;
                            room.Broadcast(new Actor_SetMultiples_Ntt() { Multiples = gameController.Multiples });
                        }
                        else if (type == CardsType.Boom)
                        {
                            //炸弹翻2倍
                            gameController.Multiples *= 2;
                            room.Broadcast(new Actor_SetMultiples_Ntt() { Multiples = gameController.Multiples });
                        }
                    }
                    else
                    {
                        response.Error = ErrorCode.ERR_PlayCardError;
                        reply();
                        return;
                    }
                }
                else
                {
                    response.Error = ErrorCode.ERR_PlayCardError;
                    reply();
                    return;
                }

                //如果符合将牌从手牌移到出牌缓存区
                deskCardsCache.Clear();
                deskCardsCache.Rule = type;
                HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>();
                foreach (var card in request.Cards)
                {
                    handCards.PopCard(card);
                    deskCardsCache.AddCard(card);
                }

                reply();

                //转发玩家出牌消息
                room.Broadcast(new Actor_GamerPlayCard_Ntt() { UserID = gamer.UserID, Cards = request.Cards });

                //游戏控制器继续游戏
                gameController.Continue(gamer);

                await ETTask.CompletedTask;
            }
            catch (Exception e)
            {
                ReplyError(response, e, reply);
            }
        }
    }
}

GamerDontPlay_Handler

\Server\Hotfix\Landlords\Handler\Map\ToGamer\GamerDontPlay_Landlords.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ETModel;

namespace ETHotfix
{
    [ActorMessageHandler(AppType.Map)]
    public class GamerDontPlay_Handler : AMActorHandler<Gamer, Actor_GamerDontPlayCard_Ntt >
    {
        protected override async ETTask Run(Gamer gamer, Actor_GamerDontPlayCard_Ntt  message)
        {
            Room room = Game.Scene.GetComponent<LandMatchComponent>().GetGamingRoom(gamer);
            OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();
            if (orderController.CurrentAuthority == gamer.UserID)
            {
                //转发玩家不出牌消息
                Actor_GamerDontPlayCard_Ntt  transpond = new Actor_GamerDontPlayCard_Ntt ();
                transpond.UserID = gamer.UserID;
                room.Broadcast(transpond);

                //轮到下位玩家出牌
                orderController.Turn();

                //判断是否先手
                bool isFirst = orderController.CurrentAuthority == orderController.Biggest;
                if (isFirst)
                {
                    room.GetComponent<DeskCardsCacheComponent>().Clear();
                }
                room.Broadcast(new Actor_AuthorityPlayCard_Ntt() { UserID = orderController.CurrentAuthority, IsFirst = isFirst });
            }
            await ETTask.CompletedTask;
        }
    }
}

GamerPrompt_Handler

\Server\Hotfix\Landlords\Handler\Map\ToGamer\GamerPrompt_Landlords.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ETModel;

namespace ETHotfix
{
    [ActorMessageHandler(AppType.Map)]
    public class GamerPrompt_Handler: AMActorRpcHandler<Gamer, Actor_GamerPrompt_Req, Actor_GamerPrompt_Back>
    {
        protected override async ETTask Run(Gamer gamer, Actor_GamerPrompt_Req request, Actor_GamerPrompt_Back response, Action reply)
        {
            try
            {
                Room room = Game.Scene.GetComponent<LandMatchComponent>().GetGamingRoom(gamer);
                OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();
                DeskCardsCacheComponent deskCardsCache = room.GetComponent<DeskCardsCacheComponent>();

                List<Card> handCards = new List<Card>(gamer.GetComponent<HandCardsComponent>().GetAll());
                CardHelper.SortCards(handCards);

                if (gamer.UserID == orderController.Biggest)
                {
                    response.Cards = To.RepeatedField(handCards.Where(card => card.CardWeight == handCards[handCards.Count - 1].CardWeight).ToArray());
                }
                else
                {
                    List<Card[]> result = await CardHelper.GetPrompt(handCards, deskCardsCache, deskCardsCache.Rule);

                    if (result.Count > 0)
                    {
                        response.Cards = To.RepeatedField(result[RandomHelper.RandomNumber(0, result.Count)]);
                    }
                }

                reply();
            }
            catch (Exception e)
            {
                ReplyError(response, e, reply);
            }
        }
    }
}

在 GameControllerComponentSystem 中添加 Continue方法

每次收到出牌请求都判断是继续游戏或有玩家牌出完了结束游戏。

本节还没讲到游戏结束逻辑先把相关代码注释或空着

\Server\Hotfix\Landlords\System\GameControllerComponentSystem.cs

        /// <summary>
        /// 判断出牌后游戏继续or结束
        /// </summary>
        public static void Continue(this GameControllerComponent self, Gamer lastGamer)
        {
            Room room = self.GetParent<Room>();
            OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();

            //是否结束,当前出牌者手牌数为0时游戏结束
            bool isEnd = lastGamer.GetComponent<HandCardsComponent>().CardsCount == 0;
            if (isEnd)
            {
                //当前最大出牌者为赢家
                Identity winnerIdentity = room.GetGamerFromUserID(orderController.Biggest).GetComponent<HandCardsComponent>().AccessIdentity;
                //List<GamerScore> gamersScore = new List<GamerScore>();

                //游戏结束所有玩家摊牌
                //...
                //self.GameOver(gamersScore, winnerIdentity);
            }
            else
            {
                //轮到下位玩家出牌
                orderController.Biggest = lastGamer.UserID;
                orderController.Turn();
                room.Broadcast(new Actor_AuthorityPlayCard_Ntt() { UserID = orderController.CurrentAuthority, IsFirst = false });
            }
        }

本节相关的消息定义

\Proto\OuterMessage.proto

放在这前已经添加的Actor_GamerDontPlayCard_Ntt后面


message Actor_GamerPlayCard_Ntt // IActorMessage
{
    int32 RpcId = 90;
    int64 ActorId = 93;
    int64 UserID = 1;
    repeated ETModel.Card Cards = 2;
}

利用前端proto工具生成消息文件,复制到服务端,编译运行服务端项目看看有没有报错。

出牌:前端收到Actor_GamerPlayCard_Ntt消息的处理Handler

房间有玩家出牌通过服务端的规则判断出牌有效果,即会广播到每个玩家客户端这次的出牌内容。

前端收到Actor_GamerPlayCard_Ntt消息后,判断:

  • 如果是刚刚自己的出牌,就只需要关闭出牌按钮
  • 如果是其它玩家的出牌,就更新他的出牌界面显示出来

\Assets\Model\Landlords\Handler\Actor10_PlayCardGamer_NttHandler.cs

namespace ETModel
{
    [MessageHandler]
    public class Actor_GamerPlayCard_NttHandler : AMHandler<Actor_GamerPlayCard_Ntt>
    {
        protected override async ETTask Run(ETModel.Session session, Actor_GamerPlayCard_Ntt message)
        {
            UI uiRoom = Game.Scene.GetComponent<UIComponent>().Get(LandUIType.LandRoom);
            LandRoomComponent room = uiRoom.GetComponent<LandRoomComponent>();
            Gamer gamer = room.GetGamer(message.UserID);
            if (gamer != null)
            {
                gamer.GetComponent<LandlordsGamerPanelComponent>().ResetPrompt();

                //本地玩家清空选中牌 关闭出牌按钮
                if (gamer.UserID == LandRoomComponent.LocalGamer.UserID)
                {
                    LandInteractionComponent interaction = uiRoom.GetComponent<LandRoomComponent>().Interaction;
                    interaction.Clear();
                    interaction.EndPlay();
                }

                //出牌后更新玩家手牌
                HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>();
                Card[] Tcards = new Card[message.Cards.Count];
                for (int i = 0; i < message.Cards.Count; i++)
                {
                    Tcards[i] = message.Cards[i];
                }
                handCards.PopCards(Tcards);
            }

            await ETTask.CompletedTask;
        }
    }
}

不出:前端收到Actor_GamerDontPlayCard_Ntt消息的处理Handler

\Assets\Model\Landlords\Handler\Actor11_DontPlayCardGamer_NttHandler.cs

using System;
using System.Collections.Generic;

namespace ETModel
{
    [MessageHandler]
    public class Actor_GamerDontPlayCard_NttHandler : AMHandler<Actor_GamerDontPlayCard_Ntt>
    {
        protected override async ETTask Run(ETModel.Session session, Actor_GamerDontPlayCard_Ntt message)
        {
            UI uiRoom = Game.Scene.GetComponent<UIComponent>().Get(LandUIType.LandRoom);
            LandRoomComponent room = uiRoom.GetComponent<LandRoomComponent>();
            Gamer gamer = room.GetGamer(message.UserID);
            if (gamer != null)
            {
                if (gamer.UserID == LandRoomComponent.LocalGamer.UserID)
                {
                    uiRoom.GetComponent<LandRoomComponent>().Interaction.EndPlay();
                }
                gamer.GetComponent<HandCardsComponent>().ClearPlayCards();
                gamer.GetComponent<LandlordsGamerPanelComponent>().SetDiscard();
            }

            await ETTask.CompletedTask;
        }
    }
}

LandlordsGamerPanelComponent组件中增加玩家不出牌的方法

\Assets\Model\Landlords\Component\LandlordsGamerPanelComponent.cs

        /// <summary>
        /// 玩家不出
        /// </summary>
        public void SetDiscard()
        {
            prompt.text = "不出";
        }

接下来就可以进行出牌与牌型、出牌规则大小判断的测试了。

posted @ 2023-02-18 09:03  Domefy  阅读(25)  评论(0编辑  收藏  举报