初探基于GameProtocol和NetFrame的RPG服务器

最近海涛大神分享了一个用于Unity的游戏服务器RPGDemoServer,基于.net开发.目前开始记录学习.

总体框架

服务器端

在这里插入图片描述
在这里插入图片描述

客户端

在这里插入图片描述
此框架比较庞大,应用于rpg项目基本业务是足够了.
在这里插入图片描述
服务器通讯部分主要是上面Net包,里面有注册,登陆,背包,好友系统,副本,技能,组队等模块.
它是以线程驱动NGUI的形式进行的,新版本的unity默认是无法运行的.
但是根据我的需求,目前精简到下面就够了,有些留在后面研究:
在这里插入图片描述
上面有注册模块,还有聊天模块.后面也许会加入组队模块.

服务器是如何开始的

新建一个服务器

			ServerStart ss = new ServerStart(9999);
           ss.Decode = MessageEncoding.Decode;
           ss.Encode = MessageEncoding.Encode;
           ss.LengthDecode = LengthEncoding.Decode;
           ss.LengthEncode = LengthEncoding.Encode;
           ss.HandlerCenter =new MessageHandlerCenter();
           ss.Start(1234);
           Console.WriteLine("服务启动成功");

这看起来是一个基本的服务器实例化代码
9999 是最大连接数.
1234 代表端口号.
中间有几行看起来是加密和解密,还有消息处理的地方.

基于事件驱动

 		public override void ClientClose(UserToken userToken, string error)
        {
            Console.WriteLine("有客户端断开连接!");
            try
            {
                _mapHandler.ClientClose(userToken);
            }
            finally
            {
                _userHandler.ClientClose(userToken);
                _loginHandler.ClientClose(userToken);
            }

        }
		public override void ClientConnect(UserToken userToken)
        {
            Console.WriteLine("有客户端连接进来了!");
        }

我很喜欢这种事件驱动.

 		public override void MessageReceive(UserToken userToken, object message)
       {
          SocketModel socketModel = message as SocketModel;
           if(socketModel!=null)
           switch (socketModel.Type)
           {
                   case Protocol.TYPE_LOGIN:
                       _loginHandler.MessageReceive(userToken, socketModel);
                       break;
                   case Protocol.TYPE_USER:
                       _userHandler.MessageReceive(userToken, socketModel);
                       break;
                   case Protocol.TYPE_MAP:
                       _mapHandler.MessageReceive(userToken,socketModel);
                       break;
                   case Protocol.TYPE_RAID:
                       _raidHandler.MessageReceive(userToken,socketModel);
                       break;
                   case Protocol.TYPE_CHAT:
                       _chatHandler.MessageReceive(userToken,socketModel);
                       break;
           }
       }

我不太喜欢这种以二进制的形式来通讯,这样就无法直接通过调试工具进行查看和测试.

注册模块和登陆模块

		 public void MessageReceive(UserToken userToken, SocketModel message)
        {
            switch (message.Command)
            {
                case LoginProtocol.LOGIN_CREQ:
                    Console.WriteLine("登陆");
                    Login(userToken, message.GetMessage<AccountDTO>());
                    break;
                case LoginProtocol.REG_CREQ:
                    Console.WriteLine("注册");
                    Reg(userToken, message.GetMessage<AccountDTO>());
                    break;
                case LoginProtocol.OFFLINE_CREQ:
                    ClientClose(userToken);
                    break;
            }
        }
        public void ClientClose(UserToken userToken)
        {
            ExecutorPool.Instance.Executor(delegate ()
            {
                _accountBiz.Close(userToken);
            });
        }

        private void Login(UserToken userToken ,AccountDTO value)
        {
            ExecutorPool.Instance.Executor(delegate()
            {
                int result = _accountBiz.AccountLogin(userToken, value.Account, value.Password);
                Console.WriteLine("登陆结果=" + result);
                Write(userToken,Protocol.TYPE_LOGIN,0,LoginProtocol.LOGIN_SRES,result);
            });
        }
        private void Reg(UserToken userToken ,AccountDTO value)
        {
            ExecutorPool.Instance.Executor(delegate ()
            {
                int result = _accountBiz.CreateAccount(userToken, value.Account, value.Password);
                Console.WriteLine("注册结果="+ result);
                Write(userToken, Protocol.TYPE_LOGIN, 0, LoginProtocol.REG_SRES, result);
            });
        }

里面是怎么判断的 ,就不进去看了,目前只要结果就行了.

新建一个客户端

基础模块

我新建了一个unity项目来尝试和服务端进行通讯测试,基本的项目如下:
在这里插入图片描述

在这里插入图片描述
global 是全局项目,用来存储一些信息.
NetManager是用来跟服务器通讯的工具.我加入了登陆/注册,聊天模块.

NetIO

主要socket代码都在里面,应该是在NetManagerUtil 的update 里被激活的.如果没有连上服务器,貌似就在假死状态,所以这里可以做下调整.

注册/登陆模块

using UnityEngine;
using System.Collections;
using GameProtocol;
using GameProtocol.Auto;

public class LoginHandler : MonoBehaviour {
    public delegate void loginEventHandler(int ms);
    public event loginEventHandler LoginEvent;
    public delegate void RegEventHandler(int ms);
    public event RegEventHandler RegEvent;
    public void MessageReceive(SocketModel socketModel)
    {
        switch (socketModel.Command)
        {
            case 0:
                Debug.Log("登陆信息");
                LoginAccount(socketModel.GetMessage<int>());
                break;
            case 2:
                Debug.Log("注册信息");
                RegAccount(socketModel.GetMessage<int>());
                break;
        } 
    }

    private void RegAccount(int result)
    {
        switch (result)
        {
            case -1:
                Debug.Log("账号重复!");
                if (RegEvent != null)
                {
                    RegEvent(0);
                }
               
                break; 
            case 0:
                if (RegEvent != null)
                {
                    RegEvent(1);
                }
                Debug.Log("注册成功!");
               
                break;    
        }
    }

    private void LoginAccount(int result)
    {
        switch (result)
        {
            case 0:
                Global.Instance.IsOnline = true;
                Debug.Log("登陆成功");
                if(LoginEvent!=null)
                {
                    LoginEvent (1);
                }
                break;
                
            case -1:
                if (LoginEvent != null)
                {
                    LoginEvent(0);
                }
                Debug.Log("账号不存在!");
              
                break;   
            case -2:
                if (LoginEvent != null)
                {
                    LoginEvent(2);
                }
                Debug.Log("账号在线!");
              
                break;   
            case -3:
                if (LoginEvent != null)
                {
                    LoginEvent(3);
                }
                Debug.Log("账号或密码错误!");
              
                break;   
            case -4:
                if (LoginEvent != null)
                {
                    LoginEvent(4);
                }
                Debug.Log("账号密码为空!");
              
                break;    
        }
    }
}

我给它加了注册事件还有登陆事件.

NetManager

using UnityEngine;
using System.Collections;
using GameProtocol;
using GameProtocol.Auto;

public class NetManagerUtil : MonoBehaviour
{

    private LoginHandler _loginHandler;
   
    private ChatHandler _chatHandler;

    void Start()
    {
         DontDestroyOnLoad(this.gameObject);
        _loginHandler = this.GetComponent<LoginHandler>();
       
        _loginHandler.LoginEvent += handleLoginEvent;
        _loginHandler.RegEvent += handleRegEvent;


        _chatHandler = this.GetComponent<ChatHandler>();


        zhuce();

   

    }

    private void handleLoginEvent(int result)
    {
        Debug.Log("登陆结果="+result);
    }

    private void handleRegEvent(int result)
    {
        Debug.Log("注册结果=" + result);
        if(result==1)
        {
            login();
        }
    }

    void zhuce()
    {
       // yield return new WaitForSeconds(2f);
        AccountDTO accountDto = new AccountDTO();
        accountDto.Account = "abc";
        accountDto.Password = "123";
        this.Write(Protocol.TYPE_LOGIN, 0, LoginProtocol.REG_CREQ, accountDto);
        Global.Instance.Account = "abc";
        Global.Instance.Password = "123";
    }

    void login()
    {
        AccountDTO accountDto = new AccountDTO();
        accountDto.Account = Global.Instance.Account;
        accountDto.Password = Global.Instance.Password;
        this.Write(Protocol.TYPE_LOGIN, 0, LoginProtocol.LOGIN_CREQ, accountDto);
    }


    void Update()
    {
        while (NetIO.Instance.MessageList.Count > 0)
        {
            SocketModel socketModel = NetIO.Instance.MessageList[0];
            StartCoroutine("MessageReceive", socketModel);
            NetIO.Instance.MessageList.RemoveAt(0);
        }
    }

    private void MessageReceive(SocketModel socketModel)
    {
        switch (socketModel.Type)
        {
            case 0:
                _loginHandler.MessageReceive(socketModel);
                break;
            case 1:
               
                break;
            case 2:
                
                break;
            case 3:
              
                break;
            case 4:
                _chatHandler.MessageReceive(socketModel);
                break;
        }
    }
}

目前加入了自动注册和登陆,现在看来一切结果都在预期之中.

开始聊天

聊天失败

我先在登陆结果的地方直接输入聊天内容,服务器是收到了,但是客户端并没有收到

 private void handleLoginEvent(int result)
    {
        Debug.Log("登陆结果="+result);
        if (result == 1)
        {
            ChatDTO dto = new ChatDTO(Global.Instance.UserDto, "世上没有一件工作不辛苦,没有一处人事不复杂。不要随意发脾气,谁都不欠你的。学会低调,取舍间必有得失,不用太计较。学着踏实而务实,越努力越幸运。当一个人有了足够的内涵和物质做后盾,人生就会变得底气十足。若是美好,叫做精彩,若是糟糕,叫做经历。——互勉", ChatType.System, null);
            this.Write(Protocol.TYPE_CHAT, 0, ChatProtocol.CHAT_TALK_CREQ, dto);
        }
    }

以下是聊天模块:

 public void MessageReceive(SocketModel socketModel)
    {
        switch (socketModel.Command)
        {
            case 1:

                break;
            case 2:
                ChatDTO dto = socketModel.GetMessage<ChatDTO>();
                switch (dto.Type)
                {
                    case ChatType.System:
                        SystemChatList.Add(dto);
                        Debug.Log("System="+dto.PlayerDto.Name+":"+ dto.ChatValue);
                        break;
                    case ChatType.Team:
                        string text = string.Format("[ff0000]【队伍】[-] [ffff00]{0}[-] :{1}", dto.PlayerDto.Name,
                            dto.ChatValue);
                        Debug.Log("Team=" + dto.PlayerDto.Name + ":" + dto.ChatValue);
                        /* if (BottomEnumPanel.Instance != null)
                         {
                             BottomEnumPanel.Instance.TextList.Clear();
                             BottomEnumPanel.Instance.TextList.Add(text);
                         }*/
                        TeamChatList.Add(dto);
                       // CreateChatItem(1, dto);
                        break;
                    case ChatType.World:
                        string value = string.Format("[ff0000]【世界】[-] [ffff00]{0}[-] :{1}", dto.PlayerDto.Name,
                            dto.ChatValue);
                        /* if (BottomEnumPanel.Instance != null)
                        {
                            BottomEnumPanel.Instance.TextList.Clear();
                            BottomEnumPanel.Instance.TextList.Add(value);
                        }*/
                        WorldChatList.Add(dto);
                        //CreateChatItem(0,dto);
                        break;   
                }
                AllChatList.Add(dto);
                break;    
        }
    }

以上并没有被触发.

服务端没有角色信息

 private void Talk(UserToken userToken , ChatDTO dto)
        {
            switch (dto.Type)
            {
                case ChatType.World:
                    Console.WriteLine("世界频道");

                    break;
                case ChatType.System:
                    int[] playerIds = _userBiz.GetAllOnlinePlayerId(userToken);
                    Console.WriteLine("系统频道");

                    Console.WriteLine("playerIds length="+ playerIds.Length);
                    for (int i=0;i<playerIds.Length;i++)
                    {
                        Console.WriteLine("id="+playerIds[i]);
                    }
                    this.Write(playerIds, Protocol.TYPE_CHAT,0,ChatProtocol.CHAT_TALK_BRO, dto);
                    break;
                 case ChatType.Team:
                    Console.WriteLine("组队频道");
                    this.Write(dto.TeamId, Protocol.TYPE_CHAT, 0, ChatProtocol.CHAT_TALK_BRO, dto);
                    break;
            }
            Console.WriteLine("文字内容="+dto.ChatValue);
        }

检查这里,原来playerIds length=0;

新建一个角色

应该是因为没有角色,所以才没有办法发给客户端.那还是加入角色模块吧,先新建一个:

 private void addUser()
    {
        UserDTO userDto = new UserDTO();
        userDto.Name = "战士";
        userDto.JobId = 0;
        this.Write(Protocol.TYPE_USER, 0, UserProtocol.Create_CREQ, userDto);
    }

    private void handleLoginEvent(int result)
    {
        Debug.Log("登陆结果="+result);
        if (result == 1)
        {
            addUser();
           
        }
    }

UserHandler下改成这样:

...
 Debug.Log("socketModel.Command="+ socketModel.Command);
        switch (socketModel.Command)
        {
            case 1:
                //创建角色

                Debug.Log("创建角色");
                Create(socketModel.GetMessage<bool>());
                break;
            case 3:
                //获取角色信息
                Debug.Log("获取角色信息");
                GetPlayerIdList(socketModel.GetMessage<List<int>>());
                break;
            case 5:
                //获取角色数据
                Debug.Log("获取角色数据");
                _userDtos = socketModel.GetMessage<List<UserDTO>>();
                for(int i=0;i<_userDtos.Count;i++)
                {
                    UserDTO userD = _userDtos[i];
                    Debug.Log("name="+ userD.Name);
                    Debug.Log("id=" + userD.Id);
                    Debug.Log("job=" + userD.JobId);
                }
                //UIMgr.Instance.Destory(PanelType.SelectPlayerPanel);
                // UIMgr.Instance.ShowPanel(PanelType.SelectPlayerPanel, _userDtos);
                break;
            case 13:
                Global.Instance.UserDto = socketModel.GetMessage<UserDTO>();
                if (OnPlayerInfoChange != null)
                    OnPlayerInfoChange();
                break;

...

运行结果:
在这里插入图片描述
新建角色成功.再来试试聊天吧.

成功收到信息

 _userHandler.OnPlayerCreate += userCreated;
  private void userCreated()
    {
        Debug.Log("角色新建成功");
        talk();
    }

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值