游戏好友系统与邮件系统实现

好友系统实现:

每个玩家在内存上都会有自己的一个map记录他的好友信息。

这个结构体大致如下:

struct FriendData
{
    uint32_t rid;
    //目前我们之间的状态
    uint32_t status;

    //记录对方的data
    uint32_t peerRid;
    uint32_t peerName;
    uint32_t peerLevel;
    uint32_t peerVip;
    ....
    ....
};

map<uint32_t, FriendData> m_myFriend;

假设A玩家添加了B玩家位他的好友,那么除了A玩家的内存上要增加B玩家的数据外,B玩家也应该会有A玩家的数据。

一个好的设计原则是:彼此不操作对方的内存数据

从内存上的实现会需要以下几个静态变量(只需要一份即可):

//发送好友申请的玩家数据,这样对方同意好友申请的时候才知道发起者的数据
struct RequestSenderInfo
{
    //发起好友请求的玩家的数据
    uint32_t rid;
    string name;
    uint32_t level;
    ...
    ...
};
//我目前收到的好友申请
static map<uint32_t, vector<RequestSenderInfo>> m_applyList;

//我发起的好友申请后收到的回应,其中FriendData就是回应者的数据; 
static map<uint32_t, vector<FriendData>> m_responseList;

//我目前收到的好友删除申请。
static map<uint32_t, vector<uint32_t>> m_deleteList;

假设A玩家给B玩家发起了一条好友申请:

1.A玩家会操作m_applyList,将B玩家的Rid作为Key,打包自己A玩家的数据放入m_applyList中;

2.B玩家通过定时器或者前端请求的方式去查找m_applyList知道B玩家有了好友申请。

  1.B玩家拒绝A玩家的好友申请:B玩家会操作m_responseList以A玩家作为Key,将拒绝的结果打包在FriendData的status中放入m_responseList

  2.B玩家同意A玩家的好友申请:B玩家会操作m_responseLIst以A玩家作为Key,将自己B玩家的数据和同意的结果打包进FriendData中放入m_responseList

3.A玩家通过定时器或者前端请求的方式去查找m_responseList知道了B玩家的是接受还是拒绝,以此来是否将B玩家放入自己的m_myFriend中;

当B玩家从好友列表中删除A玩家后:

1.B玩家会操作m_deleteList,以A玩家的Rid为Key,将自己B玩家的Rid放入m_deleteList中;

2.A玩家通过定时器或者前端请求的方式去查找m_deleteList发现了B玩家删除了自己,自己A玩家也从m_myFriend中删除B玩家。

 

以上就是好友系统的内存操作,简洁明了。A玩家不操作B玩家的内存数据,同理B玩家也不操作A玩家的内存数据,因此无需关心对方的数据是否已经从数据库载入内存;

数据库表的结构如下:

当B玩家同意好友的时候往数据库写两条数据。

一条是A玩家中B玩家的数据,一条是B玩家中A玩家的数据。这个设计感觉不是特别好,但是目前没有想出特别好的方法;

 

邮件系统实现:

邮件系统的实现有几个问题需要解决:

一、邮件Id的唯一性

二、如果每个玩家的内存单独维护一个邮件Id。就会遇到一个问题:排行榜发奖的时候,如果玩家的数据不在内存上,如何知道这个玩家邮件的Id。就要存在Load这个玩家档的情况。

三、全服邮件如何发给每一个玩家

我的实现是:普通邮件采用全服唯一邮件mailId的形式。系统邮件采用另一个全服唯一邮件sysMailId的形式

系统邮件在数据库的存储位置是:以rid=服务器id的形式分数据库、指定sysMailId字段的形式存储到数据库表内

数据结构设计为:

struct DataMail
{
    uint32_t rid
    uint32_t mailId;
    uint32_t sysMailId;
    uint32_t readTs;
    uint32_t sendTime;
    char send[19];
    char title[100];
    char text[512];
    char attachments[512];
};
static uint32_t nextSysMailId;
static vector<DataMail> vSystemMail;
static uint32_t nextMailId;
map<uint32_t, DataMail> m_userMail;

对于问题一如何做到全服唯一的普通邮件mailId:

进程一启动的时候不可能加载本服所有邮件然后对最后一封邮件mailId++的形式来拿到最大的mailId;因此会在另一个表Attr表内rid=本服Id且type=xx存一个nextMailId,每个玩家在新增一封邮件的时候都会修改这个值。

如果发的是普通邮件(玩家通关某个关卡),会设置Rid、mailId且sysMailId=0存入数据库中;

如果普通邮件的发放玩家不在内存上时,由于普通邮件采用的是全服唯一的mailId,因此依然能指定Rid和mailId存入数据库内;

如果通过后台发的是全服(更新补偿、服务器异常补偿)邮件,会单独将rid设置为本服(例如1服为1),mailId和sysMailId相等存到数据库中;

玩家如何拿到这份全服邮件

玩家登录Load档完自己邮件的数据以后会遍历系统邮件,判断自己是否有sysMailId的邮件,如果没有则走普通邮件的流程给自己的数据库表中添加一封邮件;

邮件数据库表的设计结构为:

 

posted @ 2020-04-19 21:25  只取一瓢饮  阅读(1284)  评论(0编辑  收藏  举报