服务器——UID

亦凉 2023-02-19 10:20 141阅读 0赞

一、介绍

在rpg这类游戏中,有大量的实体存在,实体包括玩家、NPC、怪物、坐骑、宠物等等,每天实体有一个id,这个id是在实体创建的时候生成的,我们称之为uid,通过uid我们可以获取到实体对象。(对于玩家实体它们还有一个id,是在玩家注册账号的时候db生成的id,我们称之为dbid,用于数据库中记录玩家唯一标记。)

二、uid设计

uid是实体的唯一标记,通过uid我们需要查询到实体对象。uid设计重要考虑的是怎样通过uid查询到实体对象。这里有几种设计方案:

方案一:map存储

map的key值为uid,value为实体对象指针。查询时间复杂度lg(n),map底层是红黑数当实体创建或删除的时候红黑树需要进行调整,当实体删除或创建频繁的时候性能消耗也会增大。

方案二:数组索引

uid是服务器自己生成的,那我们可以让uid从1连续递增生成,通过索引搜索效率可以为常数级。当有实体创建的时候可以一次创建一批,供后续实体创建使用,实体删除可以将uid回收用于后续新创建的实体使用。

实现过程,定义一个数组,用于记录当前服务器中创建的实体,通过uid可以直接搜索到实体对象指针,再定义一个列表用于记录空闲的实体,当我们需要一个uid对象的时候,我们去列表中获取一个,如果列表为空,我们将数组进行扩容,并将新创建的空闲实体添加到列表中。

总结,通过方案一和方案二对比,方案二效果跟好。

三、类结构演示

3.1 结构定义

下图为一个实现例子。

  • CGlobalServer: 服务器全局对象,服务器的主对象。
  • CEntityWorld:实体世界,管理整个服务器的实体。
  • IEntity:实体接口。
  • ConcreteEntity:一个具体的实体,可能是NPC、怪物、坐骑、宠物等等。
  • SEntity:一个实体序列号和实体指针组合,我们可以将其转为一个64位整数,也就是定义的uid。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pZTIzMTQ1NTA0NDE_size_16_color_FFFFFF_t_70

20200620002514901.png

一个uid定义如下,UID 和 SEntity结构是等价的可以相互转换。

  1. typedef LONGLONG UID;
  2. struct ___UID
  3. {
  4. DWORD dwSerialNo; // 序列号,不可逆,单通过此ID也可以标识对像
  5. DWORD dwHandle; // 对像句柄,可重复的(此成员需放后面,uid小点)
  6. };
  7. // 分解出序列号
  8. #define ANALYZEUID_SERIALNO(uid) (((___UID *)&uid)->dwSerialNo)
  9. // 分解出实体句柄
  10. #define ANALYZEUID_HANDLE(uid) (((___UID *)&uid)->dwHandle)

#

3.2 uid构建和或取对象

uid构建

一个具体的实体ConcreteEntity,创建完成会把自己添加到实体世界中,也就是调用函数CEntityWorld::Add(),CEntityWorld::Add()会调用BuildUID(),为实体构建一个uid。构建uid过程,先判断m_listUsableEntity中是否还有对象,如果有弹出一个用于当前新创建的实体,如果没有先对数组m_pEntityArray进行扩容(可以一次加1W个),将之前数据添加到新的数组中,并将新创建的对象添加到m_listUsableEntity中,用于新创建的对象。当一个对象使用完毕,将对象uid添加到m_listUsableEntity中用于后续创建的实体对象。

通过uid获取实体对象,直接看代码,直观清晰。

  1. IEntity * CEntityWorld::Get(LONGLONG uid)
  2. {
  3. if(uid == INVALID_UID)
  4. {
  5. return NULL;
  6. }
  7. // 解析
  8. DWORD dwSerialNo = ANALYZEUID_SERIALNO(uid);
  9. DWORD dwHandle = ANALYZEUID_HANDLE(uid);
  10. // 句柄越过了,非法
  11. if(dwHandle >= m_dwHandleMaxCount)
  12. {
  13. return NULL;
  14. }
  15. IEntity * pEntity = m_pEntityArray[dwHandle].pEntity;
  16. if(pEntity == NULL)
  17. {
  18. return NULL;
  19. }
  20. // 要判断序列号
  21. if(m_pEntityArray[dwHandle].dwSerialNo != dwSerialNo)
  22. {
  23. return NULL;
  24. }
  25. return pEntity;
  26. }

发表评论

表情:
评论列表 (有 0 条评论,141人围观)

还没有评论,来说两句吧...

相关阅读

    相关 服务器——UID

    一、介绍 在rpg这类游戏中,有大量的实体存在,实体包括玩家、NPC、怪物、坐骑、宠物等等,每天实体有一个id,这个id是在实体创建的时候生成的,我们称之为uid,通过u