服务端会给客户端发送一些数据,其中两大种类数据是 clientdata_t 和 entity_state_t 这里我们说说 entity_state_t 这个结构体。

你在丢在地上的枪、C4等等是服务端实体(edict_t),并且你能在客户端看到它们(废话),这些实体们是怎样发送到你的客户端的呢?

引擎不可能原原本本地把 edict_t 发送出去的,所以就有了 entity_state_t 这个结构体,它表示了一个可见实体所有必要的数据。

接上面:如果实体不可见,那何必发到客户端呢?:-)

所以 entity_state_t 只保存跟实体显示有关的数据,例如 origin、angles、model 这些,引擎只需要把这些数据发到客户端就行了。

引擎里有一个叫做 FullPack 的包(实际上就是数组),这个包里有全部需要发送给客户端的实体的 entity_state_t。

引擎会逐个检查服务端的所有实体,并且添加到包里,准备发送给客户端。

那引擎是不是默认就把能看见的实体都添加到包里了呢?并不是,因为引擎提供了一个接口让我们自己决定哪些实体可以被添加到包里!

你可以在 mp.dll 的源码里找到 AddToFullPack 这函数,可以看到这样的代码:

int AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet)
{
if ((ent->v.effects == EF_NODRAW) && ent != host)
return ; // 有EF_NODRAW这个标记的实体是不可见的,不添加到包里。 if (!ent->v.modelindex || !STRING(ent->v.model))
return ; // 没有模型的实体是不可见的,不添加到包里。 if ((ent->v.flags & FL_SPECTATOR) && ent != host)
return ; // 观察者也是不可见的,不添加到包里。 // ... if (ent != host)
{
// 在可视范围(PVS)外的实体是看不到的,不添加到包里。
if (!CheckEntityRecentlyInPVS(hostindex, e, gpGlobals->time))
{
if (!ENGINE_CHECK_VISIBILITY((const struct edict_s *)ent, pSet))
{
MarkEntityInPVS(hostindex, e, gpGlobals->time, true);
return ;
} MarkEntityInPVS(hostindex, e, gpGlobals->time);
}
} // ...
}

参数 state 是将要添加到包里的 entity_state_t ,参数 ent 是正在处理的实体,参数 host 是包要发送到的那个玩家(的客户端)!

如果这个函数返回 0 (FALSE)引擎就不会把这个实体添加到包里,这个实体自然也就不会被发送到那个客户端(看不到)。

你甚至可以在这个函数里自定义需要发送的实体的数据!我们可以看到这样的代码:

int AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet)
{
// ... state->number = e;
state->entityType = ENTITY_NORMAL; state->animtime = (int)(1000.0 * ent->v.animtime) / 1000.0; memcpy(state->origin, ent->v.origin, * sizeof(float));
memcpy(state->angles, ent->v.angles, * sizeof(float));
memcpy(state->mins, ent->v.mins, * sizeof(float));
memcpy(state->maxs, ent->v.maxs, * sizeof(float));
memcpy(state->startpos, ent->v.startpos, * sizeof(float));
memcpy(state->endpos, ent->v.endpos, * sizeof(float)); state->impacttime = ent->v.impacttime;
state->starttime = ent->v.starttime;
state->modelindex = ent->v.modelindex;
state->frame = ent->v.frame; // ...
}

你可以看到它从服务端实体(edict_t)抽出必要的数据填充到 entity_state_t 里!

最后返回 1(TRUE)引擎将会把我们填充好的 entity_state_t 添加到包里,发送给客户端。

这个函数真的很有用对吧,我们可以做一些有趣的功能,让一个实体可以被玩家A看到,玩家B却看不到!

我们只需要检查当前正在处理的实体(ent)是那个我们不让玩家B看到的实体,然后判断 host 是不是玩家B,如果是,就返回 0 不让这个实体发送给玩家B!

你甚至可以设置一个玩家(玩家也是实体)不让其它玩家看到!(玩家实体必须被发送,所以如果要隐藏一个玩家,请使用EF_NODRAW这个FLAG)

注意,引擎里的包最多只能容纳 256 个实体!如果超出了这个数量,引擎将会忽略超出部分的实体!

【HLSDK系列】服务端 AddToFullPack 函数的更多相关文章

  1. 2.live555源码分析----服务端doEventLoop()函数分析

    上一篇博客说道,live555服务端main函数做的最后一件事就是调用如下代码陷入死循环: env->taskScheduler().doEventLoop(); // does not ret ...

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

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

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

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

  4. 【HLSDK系列】服务端 UpdateClientData 函数

    首先说明下,这个函数是写在 mp.dll 里的. 服务器会给每个客户端发送一些数据,其中两大数据种类就是 clientdata_t 和 entity_state_t 这里要说的是 clientdata ...

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

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

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

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

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

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

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

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

  9. 解决有关flask-socketio中服务端和客户端回调函数callback参数的问题(全网最全)

    由于工作当中需要用的flask_socketio,所以自己学习了一下如何使用,查阅了有关文档,当看到回调函数callback的时候,发现文档里都描述的不太清楚,最后终于琢磨出来了,分享给有需要的朋友 ...

随机推荐

  1. combotree -下拉框树异步加载

    问题: 下拉树数据比较多时,全加载会产生页面延迟,需要实现异步加载 方案: 点击事件加载:先加载部分,点击节点时再展开并追加子节点 onBeforeExpand事件:在展开树前加载,感觉这种方式比较优 ...

  2. 【LG3244】[HNOI2015]落忆枫音

    题面 洛谷 题解 20pts 枚举每一条边是否在树中即可. 另10pts 我们考虑一张\(DAG\)中构成树的方法数,每个点选一个父亲即可,那么有 \[Ans=\prod_{i=1}^{n} deg_ ...

  3. 3060 抓住那头奶牛 USACO

    3060 抓住那头奶牛 USACO 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 农夫约翰被告知一头逃跑奶牛的位置,想要立即抓住它, ...

  4. 【JUC源码解析】ConcurrentLinkedQueue

    简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...

  5. linux下汇编语言开发总结

    汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影.但是这并不表示汇编语言就已经没有 ...

  6. moment.js使用方法总结

    Moment.js是一个轻量级的JavaScript时间库,它方便了日常开发中对时间的操作,提高了开发效率.日常开发中,通常会对时间进行下面这几个操作:比如获取时间,设置时间,格式化时间,比较时间等等 ...

  7. TPO 02 - Early Cinema

    TPO 02 - Early Cinema NOTE: 主要意思(大概就是主谓宾)用粗体标出:重要的其它用斜体: []中的是大致意思,可能与原文有关也可能无关,但不会离题 目的为训练句子/段落总结能力 ...

  8. MobSF 框架安装使用部署

    1.MobSF 简介 MobSF是Mobile Security Framework的缩写,这是一款智能化的开源移动应用(Android.IOS.Windows)测试框架,可以对应用进行动态.静态分析 ...

  9. 转载笔记:DropDownList无限级分类(灵活控制显示形式)

    主要使用递归实现,数据库结构: 最终样式:  1protected void Page_Load(object sender, EventArgs e) 2    { 3        if (!Pa ...

  10. 两张神图介绍python3和 2.x与 3.x 的区别

    有感与第一张图, 做了第二张图.