我们来了解一下引擎是怎么管理实体的吧!我们这里就说说服务端的实体(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 的,留到下一篇文章吧!

【HLSDK系列】服务端实体 edict_t 和 控制类的更多相关文章

  1. 前端学习 node 快速入门 系列 —— 服务端渲染

    其他章节请看: 前端学习 node 快速入门 系列 服务端渲染 在简易版 Apache一文中,我们用 node 做了一个简单的服务器,能提供静态资源访问的能力. 对于真正的网站,页面中的数据应该来自服 ...

  2. Nacos源码系列—服务端那些事儿

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 nacos,即可免费获取源码 前言 在上节课中,我们讲解了客户端注册服 ...

  3. TCP连接建立系列 — 服务端接收ACK段(一)

      http://blog.csdn.net/zhangskd/article/details/17923917 分类: Linux TCP/IP Linux Kernel 2014-01-07 09 ...

  4. TCP连接建立系列 — 服务端发送SYNACK段

    本文主要分析:服务器端如何构造和发送SYNACK段. 内核版本:3.6 Author:zhangskd @ csdn blog 发送入口 tcp_v4_send_synack()用于发送SYNACK段 ...

  5. TCP连接建立系列 — 服务端接收SYN段

    本文主要分析:服务器端接收到SYN包时的处理路径. 内核版本:3.6 Author:zhangskd @ csdn blog 接收入口 1. 状态为ESTABLISHED时,用tcp_rcv_esta ...

  6. TCP连接建立系列 — 服务端接收ACK段(二)

    本文主要分析:三次握手中最后一个ACK段到达时,服务器端的处理路径. 内核版本:3.6 Author:zhangskd @ csdn blog 创建新sock 协议族相关的操作函数,我们要看的是TCP ...

  7. 【HLSDK系列】服务端 AddToFullPack 函数

    服务端会给客户端发送一些数据,其中两大种类数据是 clientdata_t 和 entity_state_t 这里我们说说 entity_state_t 这个结构体. 你在丢在地上的枪.C4等等是服务 ...

  8. 【HLSDK系列】HL引擎入门篇

    如果你打算拿HL的源码(也就是HLSDK)来改出一个自己的游戏,那你就非常有必要理解一些HL引擎的工作方式. HL引擎分成两个部分,服务端和客户端.服务端管理所有玩家的状态和游戏规则,客户端负责显示U ...

  9. cocos2d-lua ARPG手机游戏《烈焰遮天》(客户端+服务端+数据库)发布说明

    服务器发布流程及其规范1,环境准备        a, mvn命令行:从\\10.21.210.161\share\tools\apache-maven-3.1.1-bin.tar.gz取出安装包,  ...

随机推荐

  1. Servlet——web.xml的配置

    <servlet>: <servlet-name>: 名称 <servlet-class>: 类名 <init-param>: 初始化参数(只有本ser ...

  2. day5 if while for

    .注意点: ctrl + n 自动补全 18行报错,直接定位18行 逻辑运算符and or not 复合赋值运算符 += .if-elif 判断星期几 猜拳游戏 .while循环 )3大执行流程 )什 ...

  3. django使用流程

    1.安装django包 (命令行)>pip install django # conda install django 2.安装成功后,可以新建django项目 1(命令行)>django ...

  4. 一个奇怪的JS函数

    今天在分析一个jQuery插件源码的时候,发现了一个奇怪的函数. 这个函数的目的是为数字补零,如传入7,输出07,传入12输出12.由于是对时间补零,只截取后两位. // add leading ze ...

  5. STM32L431驱动带UC1698芯片调试记录

    1, 数据线连接方式,这次使用的是8080格式的接口,如下 2. 主要是信号和数据引脚 DATA0-DATA7  并口的数据 RST 复位信号 WR 写信号 RD 读信号 C/D 数据还是命令 CS片 ...

  6. springmvc @Valid 接收实体类时出现bean为null的问题

    这是因为传到后端之后,全部以全小写形式处理了 所以前端也需要把name设置为全小写,否则后端不识别,导致接收不到,导致为null

  7. JavaScript 中函数的参数

    functionName(parameter1, parameter2, parameter3) { // 要执行的代码…… } 参数规则 JavaScript 函数定义时形参没有指定数据类型. Ja ...

  8. JavaScript查找元素的方法

    1.根据id获取元素 document.getElementById("id属性的值"); 2.根据标签名字获取元素 document.getElementsByTagName(& ...

  9. Linux 安装Redis<集群版>(使用Mac远程访问)

    阅读本文需要先阅读安装Redis<准备> 一 架构细节 所有的redis节点彼此互联(PING-PONG机制) 内部使用二进制协议优化传输速度和带宽 节点的fail是通过集群中超过半数的节 ...

  10. GitHub 多人协作开发 三种方式:

    GitHub 多人协作开发 三种方式: 一.Fork 方式 网上介绍比较多的方式(比较大型的开源项目,比如cocos2d-x) 开发者 fork 自己生成一个独立的分支,跟主分支完全独立,pull代码 ...