任务12:后端-注册登录需要创建的实体类

ETCore是怎么通信的

框架有一个Sesion对象,提供了Send(),Call()方法,玩家与服务器之间的通信就是通过Session来发起的。

那么为什么玩家、电脑或手机,能向服务器 & 服务器能向玩家、电脑或手机发送消息呢?

每一个电脑、手机,包括我们的服务器,都是一台终端,只要知道这个终端的IP地址,还有某个程序的端口(端口就对应着某一个程序,所以我们会遇到某个端口如果被占用,那需要用到这个端口的程序就启动不了了),就能向这台终端,这个端口的这个程序发消息了。

Session对象就是用发送目标的IP地址与端口构建的对象,所以我们前面发送消息给服务端的例子中,就是用配置文件中配置的服务器地址与端口构建了Session实例,再发送消息给服务器的。

//测试发送给服务端一条文本消息
Session session = Game.Scene.GetComponent<NetOuterComponent>().Create(GlobalConfigComponent.Instance.GlobalProto.Address);
G2C_TestMessage g2CTestMessage = (G2C_TestMessage) await session.Call(new C2G_TestMessage() { Info = "==>>服务端的朋友,你好!收到请回答" });

普通消息:如果只是发送一条消息,不需要对方作响应(返回消息),那就是一条普通消息。用Session对象的Send方法。

RPC消息:如果发送一条消息,还需要对方响应,这叫RPC消息,我们把RPC叫远程调用,对方肯定接收你的消息后,要调用一系列方法进行处理,再返回你一个结果。用Session对象的Call方法。

开始斗地主服务端登录、注册实现 \Server\ET.Core\Landlords

先把数据库实体,网关实体,地图实体梳理一下

查询,提交数据到MongoDB,数据库实体类的属性与数据表中的字段是对应的

在网关服务中用到的Entity对象,我就把他叫Gate Entity

在地图服务中用到的Entity对象,我就把他叫Map Entity

提示:至于什么是,为什么要Gate网关,Realm认证,Map地图几个服务?先用起来,日后慢慢体会(如果是在一台主机上,就把他们当几种不同的服务来理解,如果是不同的物理主机,他们就是具有这些服务功能的服务器,如gate服务器,map服务器)。

某种服务就是由相配合的一组实体,组件,System对象共同运作。

数据库实体:AccountInfo,UserInfo

AccountInfo包含用户名与密码

public string Account { get; set; } 

public string Password { get; set; }

UserInfo包含角色昵称,等级,还有多少金币

public string UserName { get; set; }

public int Level { get; set; }

public long Money { get; set; }

网关实体:User

User是用户登录网关认证后创建的对象,持有:

UserID 数据库上此用户的UserID

GateAppID 用户所在的Gate服务器的AppID

GateSessionID 用户在网关上的GateSessionID

ActorID 用于Actor消息

地图实体:Gamer,Room

Gamer 玩家进入map后的实例

Gamer是进入地图后创建的对象,地图中需要能向网关User通信,向客户端通信

UserID 来自数据库中的永久ID

GActorID 玩家GateActorID

isOffline (Session断开/离开房间时触发离线)

Room 房间在map中的实例

Dictionary<long, int> seats 房间3个座位

Gamer[] gamers = new Gamer[3] 进入房间3玩家

bool[] isReadys = new bool[3] 进入房间3玩家是否准备

Count 房间中玩家的数量

提示:每个用户登录网关和认证后就会有一个 User实例,用户进入地图后就会有一个Gamer实例,进入匹配的用户每多于3的倍数,就会有一个Room实例

每有一个用户注册或登录就会有一个AccountInfo实例,提交查询数据库获取到用户更多信息后就会有一个UserInfo实例

你能明白为什么要有一个账号信息,又有一个用户信息吗?比如我们在魔兽世界中的账号名可能是一个邮箱+密码,然而我们的用户名可能是 天线宝宝#1232

以上多看几次,自己在本子上画一画,反复思考,理解记忆!

AccountInfo.cs

\Server\ET.Core\Landlords\Entity\DB\AccountInfo.cs

using MongoDB.Bson.Serialization.Attributes;

namespace ETModel
{
    /// <summary>
    /// 账号信息
    /// </summary>
    public class AccountInfo : Entity
    {
        //用户名
        public string Account { get; set; }

        //密码
        public string Password { get; set; }
    }
}

UserInfo.cs

\Server\ET.Core\Landlords\Entity\DB\UserInfo.cs

using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;

namespace ETModel
{
    [ObjectSystem]
    public class UserInfoAwakeSystem : AwakeSystem<UserInfo, string>
    {
        public override void Awake(UserInfo self, string name)
        {
            self.Awake(name);
        }
    }

    /// <summary>
    /// 用户信息
    /// </summary>
    public class UserInfo : Entity
    {
        //昵称
        public string UserName { get; set; }

        //等级
        public int Level { get; set; }

        //余额
        public long Money { get; set; }


        //上次游戏角色序列 1/2/3
        public int LastPlay { get; set; }

        //public List<Ca>
        public void Awake(string name)
        {
            UserName = name;
            Level = 1;
            Money = 10000;
            LastPlay = 0;
        }

    }
}

User.cs

\Server\ET.Core\Landlords\Entity\Gate\User.cs

namespace ETModel
{
    [ObjectSystem]
    public class UserAwakeSystem : AwakeSystem<User,long>
    {
        public override void Awake(User self, long id)
        {
            self.Awake(id);
        }
    }

    /// <summary>
    /// 玩家对象 在C2G_LoginGate_Handler中初始化参数
    /// </summary>
    public sealed class User : Entity
    {
        /// <summary>
        /// 读取自数据库中的永久ID
        /// 本程序中出现的UserID字样变量均代表此意
        /// </summary>
        public long UserID { get; private set; }
 
        /// <summary>
        /// 玩家所在的Gate服务器的AppID
        /// </summary>    
        public int GateAppID { get; set; }

        /// <summary>
        /// 玩家所绑定的Seesion.Id 用于给客户端发送消息
        /// </summary>
        public long GateSessionID { get; set; }
        
        /// <summary>
        /// 为客户端转发Actor消息到指定目标
        /// 未进入地图时ActorID=0,进入地图后ActorID=GamerID
        /// </summary>
        public long ActorID { get; set; }
        
        public void Awake(long id)
        {
            this.UserID = id;
        }

        public override void Dispose()
        {
            if (this.IsDisposed)
            {
                return;
            }

            base.Dispose();
            
            this.UserID = 0;
            this.GateAppID = 0;
            this.GateSessionID = 0;
            this.ActorID = 0;
        }
    }
}

Gamer.cs

\Server\ET.Core\Landlords\Entity\Map\Gamer.cs

using MongoDB.Bson.Serialization.Attributes;
namespace ETModel
{
    [ObjectSystem]
    public class GamerAwakeSystem : AwakeSystem<Gamer, long>
    {
        public override void Awake(Gamer self, long userid)
        {
            self.Awake(userid);
        }
    }

    /// <summary>
    /// 房间玩家对象
    /// </summary>
    public sealed class Gamer : Entity
    {
        /// <summary>
        /// 来自数据库中的永久ID
        /// </summary>
        public long UserID { get; private set; }
        
        /// <summary>
        /// 玩家GateActorID
        /// </summary>
        public long GActorID { get; set; }

        /// <summary>
        /// 默认为假 Session断开/离开房间时触发离线
        /// </summary>
        public bool isOffline { get; set; }

        public void Awake(long userid)
        {
            this.UserID = userid;
        }

        public override void Dispose()
        {
            if(this.IsDisposed)
            {
                return;
            }

            base.Dispose();

            this.UserID = 0;
            this.GActorID = 0;
            this.isOffline = false;
        }
    }
}

Room.cs

D:\Users\taikr008\Desktop\Landlords_Server02_03\Server\ET.Core\Landlords\Entity\Map\Room.cs

using System.Collections.Generic;
using System.Linq;

namespace ETModel
{
    /// <summary>
    /// 房间对象
    /// </summary>
    public sealed class LandlordsRoom : Entity
    {
        /// <summary>
        /// 当前房间的3个座位 UserID/seatIndex
        /// </summary>
        public readonly Dictionary<long, int> seats = new Dictionary<long, int>();
        /// <summary>
        /// 当前房间的所有所有玩家 空位为null
        /// </summary>
        public readonly Gamer[] gamers = new Gamer[3];
        public readonly bool[] isReadys = new bool[3];
        
        /// <summary>
        /// 房间中玩家的数量
        /// </summary>
        public int Count { get { return seats.Values.Count; } }

        public override void Dispose()
        {
            if (this.IsDisposed)
            {
                return;
            }

            base.Dispose();

            seats.Clear();

            for (int i = 0; i < gamers.Length; i++)
            {
                if (gamers[i] != null)
                {
                    gamers[i].Dispose();
                    gamers[i] = null;
                }
            }

            for(int i = 0;i<isReadys.Length;i++)
            {
                isReadys[i] = false;
            }
        }
    }
}

我们接下来几节,分别讲相关的组件类,System类,加上消息类与消息调用方法,才能运转,要经历几节课有点抽象但大家其实也熟悉的东西。

提示:可能有点小晕了没关系 ,加上后面几天的课一起实现了就好,随着再开发更多功能,会体会越来越深,慢慢使用自如!

posted @ 2023-02-01 09:47  Domefy  阅读(39)  评论(0编辑  收藏  举报