任务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类,加上消息类与消息调用方法,才能运转,要经历几节课有点抽象但大家其实也熟悉的东西。
提示:可能有点小晕了没关系 ,加上后面几天的课一起实现了就好,随着再开发更多功能,会体会越来越深,慢慢使用自如!