• 【HLSDK系列】服务端实体 edict_t 和 控制类


    我们来了解一下引擎是怎么管理实体的吧!我们这里就说说服务端的实体(edict_t)

    服务端用 edict_t 这个结构体来保存一个实体,可以说一个 edict_t 就是一个 服务端实体,下文简称实体。

    我们在 mp.dll 的源码里经常看到的那些 CBaseXXX 又和 edict_t 有什么关系呢?

    引擎只管理小部分实体的功能,更多功能需要我们自己写代码去实现,这里就引入了 实体控制类 这个东西(就是那些 CBaseXXX),类就是C++的那个类。下文简称控制类。

    接下来我们就分析 edict_t 到底是怎么跟 控制类 挂上勾的。

    我们通常用 CREATE_NAMED_ENTITY( MAKE_STRING("weapon_mp5") ); 来创建一个 weapon_mp5 的武器实体,那我们就来分析这个函数到底做了什么吧!

    1. 用户调用 CREATE_NAMED_ENTITY。

    2. 引擎在 mp.dll (的导出函数)里查找名为“weapon_mp5”的函数。(你可能会有疑问:我从来没写过这个函数啊?别急,下文分析)

    3. 引擎调用“weapon_mp5”函数来创建出一个CMP5类实例。“weapon_mp5”还调用了 CREATE_ENTITY 来创建出一个 edict_t。(用数学老师的话说:CMP5就是实体weapon_mp5的控制类)

    4. 引擎把类实例的指针赋值到 edict_t 的 pvPrivateData 成员变量里。

    5. 引擎返回 edict_t 给用户。

    看了上面的步骤,你一定注意到非常关键的一步,“weapon_mp5”函数到底是怎么一回事。

    打开 mp5.cpp 你会发现有一行

    LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 );

    这行就是关键,它会生成一个函数,这个函数起了类似如下代码的作用:

    注:实际上不是这么简单的,只是为了更容易理解。

    CMP5 *weapon_mp5()
    {
        return new CMP5();
    }

    再往回看上面的步骤3和4,能理解了吧。

    引擎先创建一个 edict_t 然后又 new CMP5 把指针存到 pvPreivateData 这个变量里,到此一个实体就创建出来了。

    然后我们还要了解控制类是怎么工作的。首先请你打开 cbase.cpp 你会看到一堆 Dispatch 开头的函数,下文简称派遣函数。

    派遣函数用来干嘛呢?当一个实体要 Think 的时候,引擎就会调用 mp.dll 里的 DispatchThink 这个函数,它有一个参数 edict_t *pent 就是要 Think 的实体!

    接着才是关键!

    我们来看 DispatchThink 的源码:

    void DispatchThink( edict_t *pent )
    {
        CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);
        if (pEntity)
        {
            // ...
            pEntity->Think();
        }
    }

    顺便还有 GET_PRIVATE 的源码:

    inline void *GET_PRIVATE( edict_t *pent )
    {
        if ( pent )
            return pent->pvPrivateData;
        return NULL;
    }

    我们可以看到它获取了 edict_t 里面的 pvPrivateData 变量,你一定还记得这个变量是怎么来的吧!不记得请马上往回看!

    没错,之前引擎创建实体的时候,把 控制类 的 指针 存这变量里了,我们这里就把这个 控制类 拿出来而已!

    接着它检查了一下 控制类 是不是 NULL,然后它在 if 里面调用了 控制类 的 Think 函数!

    整个过程就是这样的:引擎 -> 派遣函数 -> 控制类 也就是说,引擎是不管 控制类 的,为让 控制类 工作,我们还需要在派遣函数里写东西(虽然HLSDK已经写好了,但是你一定要去看看他是怎么写的)。

    如果你写过 AMXX 你肯定会认识 FM_Think FM_Spawn 这些东西,它们就是HOOK了这些派遣函数!

    本来还想仔细讲解 LINK_ENTITY_TO_CLASS 的,留到下一篇文章吧!

  • 相关阅读:
    前端开发神器
    React表单明文密文切换,携带禁止浏览器自动回填,简单验证提示功能
    webapp 虚拟键盘隐藏留下空白解决办法
    jQuery常用表单事件执行顺序
    localStorage+cookie实现存取表单历史记录
    js.cookie.js使用方法
    H5超细边框
    JS删除数组中某个元素
    JS获取地址栏参数(支持中文)
    React书写规范
  • 原文地址:https://www.cnblogs.com/crsky/p/6881146.html
Copyright © 2020-2023  润新知