TL;DR: 在100 Hz服务器帧速率下,高延迟玩家因每次世界更新中过多的小模型而出现卡顿。服务器现在会跳过那些在玩家视野中只占极小角度的实体,阈值会根据每位玩家的负载自动适配,玩家可以通过单个 cvars 进行覆盖。

Alien Arena 7.72(“Project 100”)在100 Hz帧速率下运行服务器。这既流畅,也意味着服务器每秒向每个客户端构建并发送100次世界更新。本文描述了由于此设置出现的问题,以及在 Alien Arena 7.72.2 中如何解决该问题。

问题

在100 Hz 时,每次更新的数据量比旧的较低帧速率时重要得多。在包含大量视野内模型(物品、装饰、道具)的地图中,每个客户端的每次更新包含大量实体。对网络状况良好的玩家而言这无所谓;但对延迟较高(150 ms 及以上)的玩家则导致明显的卡顿。

罪魁祸首并非地图几何本身,它是 cheap(廉价)的。真正导致卡顿的是大量即使远处且几乎不可见的小模型被发送到客户端。

思路:不发送几乎不可见的内容

服务器已经会跳过完全不可见的实体(所在其他房间、被墙体遮挡、关闭的门)。新增的是对“虽可见但体积极小”的实体进行跳过。

对每个实体,服务器会比较其大小与其距离玩家的距离,得到其在玩家视野中占据的角度。如果该角度小于阈值,则不发送该实体。例如:远在图中、体积很小的物品占据的角度极小,只有靠近时才会被发送。

为了防止误删导致视觉上的“闪烁”,有几条规则:

  • 地图结构(门、平台)以及关键 gameplay 实体永不被删除。
  • 一旦实体被发送给玩家,只要玩家靠近或保持静止,它仍保持可见,只有当玩家明显远离它时才会再次成为可删除对象。这样可以避免实体频繁出现和消失。

阈值以度为单位。阈值越高,越积极删除;阈值越低,显示的实体越多。

为了感受数值,可以想象伸直手臂,小指宽度约 1°,拇指约 2°,拳头闭合约 10°。默认最小值为 1°,小于小指宽度的实体不被发送;默认最大值为 10°,小于拳头宽度的实体不被发送。

服务器不知道实体是从哪一侧观察到的,也不关注十字准星的指向。它使用模型文件中读取的最长侧的固定尺寸(模型的包围盒最长边)作为简化。这是一种妥协,倾向于安全:实体会被视作从其最宽侧观察,从而不会因不利视角而被错误删除。

适配机制

固定阈值是一种妥协:阈值过低会在繁忙地图上重新出现问题,阈值过高则在安静地图上显得稀疏。

因此,服务器会 ** per‑client** 测量如果不进行角度裁剪时会发送的实体数量,并据此调整阈值:

  • 实体数量低于预算(默认 80 实体/100 帧)时,阈值保持最小(默认 1°)。
  • 实体数量在 80 到 150 之间时,阈值线性增长。
  • 实体数量达到 150 实体或更多时,阈值达到最大(默认 10°)。

实际细节:

  • 计数每秒检查一次,使用该秒内出现的最小计数,因此短暂的峰值不会触发变化。
  • 只有在连续两次繁忙秒后,裁剪才会加强;而在出现一秒的平静后,裁剪会放宽。不确定时,系统倾向于显示更多而非更少。
  • 负载在应用角度裁剪之前测量。若在裁剪后测量,会形成反馈循环(更多裁剪 → 更少实体 → 看起来正常 → 更少裁剪 → 循环),导致实体每几秒闪烁一次。
  • 预算会根据服务器使用的帧速率自动缩放(非 100 Hz 时)。

因为系统实时查看每位玩家当前实际可见的内容,它会自动适应地图和玩家位置,而不需要为每张地图单独设置。

客户端覆盖

自动值是一个良好的默认,但它无法了解玩家的全部连接情况或偏好。因此客户端可以自行设置值:

entity_cull 10
  • 0(默认):使用服务器的自动值。
  • 任意大于 0 的值:使用该角度(度)作为精确阈值,并对该玩家关闭自动调整。

该覆盖仅影响该玩家的接收范围,不影响服务器上的其他玩家。

服务器设置

服务器管理员可以调节自动行为:

  • sv_entity_cull(默认 1.0):最小角度(度)。0 完全禁用裁剪。
  • sv_entity_cull_max(默认 10.0):自动系统能够提升的最大角度。
  • sv_entity_budget(默认 80):每位客户端(100 帧)可见实体数,在该数量以下阈值保持最小。
  • sv_entity_budget_max(默认 150):每位客户端(100 帧)可见实体数,在该数量以上阈值达到最大。
  • sv_entity_cull_vel_away_dot(默认 0.0):玩家必须多清楚地远离实体后,该实体才能再次被裁剪。

命令 sv_entity_cull_status 会打印每位已连接玩家的当前角度、实体计数以及数值来源(服务器自动或玩家覆盖),便于观察系统行为。

是否有效?

两个真实案例:

  • Memorial Tournament:延迟超过 150 ms 的玩家出现卡顿,将裁剪设为 10 后得到改善。当时该设置是全局的,对网络状况良好的玩家不理想。
  • CTF:延迟约 100 ms 的玩家在某些地图上难以游玩,设置 entity_cull 为 10 或 20 后,该玩家即可流畅进行游戏。服务器上其他玩家未受影响。

这些是个人报告,非正式基准测试,但符合思路:减少小实体数量可使更新更小,对大更新受影响的连接最为有利。

与其他游戏的区别

大多数同一家族的引擎(如 Quake 2/3)会通过视野集(PVS)和固定距离来裁剪,部分引擎允许为物体类型配置固定距离。据我所知,以下做法较少见:

  1. 以视觉大小而非仅距离进行裁剪,即大物体在远处仍可见,小物体即使近也可能不可见。
  2. 阈值会 per‑client 自动适配实际负载。
  3. 让玩家自行选择裁剪激进程度,可向上或向下调节。

我不声称此方案优于所有其他做法。它适配本引擎和此问题,且实现简洁、易于理解和调节。

总结

  • 问题:100 Hz 帧速率加上大量小模型导致高延迟玩家卡顿。
  • 解决:不发送那些在玩家视野中只占极小角度的实体,阈值随每位玩家负载自适应。
  • 灵活性:管理员可通过 cvars 调节自动行为,玩家可通过 entity_cull 自行设定更激进或更保守的值。
  • 自 Alien Arena 7.72.2 起可用。

对其他开发者的提问

  • 其他引擎是否允许玩家自行设置裁剪激进程度?如果允许,玩家实际使用情况如何?
  • 与固定阈值相比,per‑client 自适应阈值是否属于过度设计,或在实际中表现良好?
  • 是否有更佳的负载衡量方式,而非可见实体数量,例如更新大小(字节数)?

源码

此内容来源于 Alien Arena,一个开源免费射击竞技场 FPS。引擎开源(游戏资源受其他许可证约束),可在 GitHub 上查看实际实现代码。

如有实现细节方面的问题,我很乐意解答。