CD Code Digest Hub /GTA V

网络脚本、复制数据、权限与主机迁移

6 分钟阅读 8 个章节

1. 网络能力位于宿主框架#

SanScript 没有从语法层自动把任意变量复制给其他玩家。脚本调用 NETWORK_SET_THIS_SCRIPT_IS_NETWORK_SCRIPT 等 Native 注册网络身份,再由 scriptHandlerNetComponent、网络数组管理器、游戏对象系统完成参与者管理、广播和迁移。[S1][S2]

这意味着同一个语言程序可以运行在不同机器上,但执行实例、PC、局部栈不会因此自动同步。该模型不是已证明的确定性 lockstep,也不能从客户端源码推定完整权威服务端的规则和部署。

2. 至少区分四种数据#

数据作用同步方式
线程静态/局部变量本地流程与临时状态默认不自动联网
GLOBALS本机脚本间共享名称是 GLOBAL 也不代表网络广播
Host / Player broadcast data复制脚本状态显式注册内存区域,由数组系统发送
网络实体车辆、角色等原生对象状态网络对象 ID、所有权和对象同步系统

脚本事件则是另一条消息路径,应与“持续复制当前状态”区分。对需要到场后恢复最新值的状态,广播更自然;对一次行为请求,事件/消息更自然,但可靠性、排序和重复处理必须遵循具体接口,不能只凭名称保证。

3. 广播注册与数据布局#

Host 注册接收 STRUCT& Address, INT Size,C++ 将 Size 乘 sizeof(scrValue),然后注册到当前网络脚本组件。Player 注册通常接收按参与者排列的数组,扣除数组长度槽、验证元素数与最大参与者数,再按参与者拆分。[S3]

这把编译布局与联网布局直接联系起来:脚本给 SIZE_OF 的单位是槽,Native 需要转成字节;聚合包含长度头;各端必须对结构大小和字段含义达成一致。源码中仍有“script word 四字节”的旧注释,理解时应优先看使用 sizeof(scrValue) 的实际转换。

广播保存的是一个连续数据区域,不具备自动 schema 驱动的字段名反射或逐字段语义压缩。不能把 STRING 指针、任意函数地址或本地句柄原样广播后当成远端有效值。

4. 序列化粒度与带宽成本#

CBroadcastDataElement 包含四个 unsigned 单元,在该实现中形成 16 字节的数据元素;Serialise 使用 datablock 序列化有效单元,末尾元素可标记未用单元。数组层提供 dirty、当前/影子状态比较、索引和更新序列等机制。[S4]

因此脚本字段变化的成本可能按“同步元素”而非单个 BOOL 计费。相关字段的布局、更新频率、参与者范围和主机角色都会影响发送量。源码有 high-frequency 数组数量与大小限制,说明更新频率是显式稀缺预算;不能据此给出所有平台固定的线上 kbps。[S3][S4]

可用于分析的成本模型:

text
发送成本 ≈ 变化元素有效数据
         + 元素索引/协议头/序列与确认开销
         + 重发或迁移初始化开销
         按接收范围与更新频率累积

本次没有抓包,不能把这个结构模型当成实际网络负载报告。

5. 脚本主机不是永远固定的一台机器#

网络组件维护参与者、主机、迁移计时、主机请求和广播数据归属。注册的广播数据在退出/组件销毁时必须取消注册,否则会保留对过期脚本内存的依赖。[S2]

脚本主机身份、某个车辆实体的网络所有者、本地脚本实例是三个概念。创建 host object 会检查当前主机权限;获取控制权、迁移和退出还由对应游戏/网络系统处理。NETWORK_IS_HOST_OF_THIS_SCRIPT() 的一次真值不能证明 WAIT 之后仍持有同样权力。

6. 实际案例:net_jacking_soaktest#

该开发压力脚本:

  1. 注册网络脚本,执行初始化握手。
  2. 等待主任务活动状态。
  3. 注册 GlobalServerBD_JST 的 host broadcast 区域。
  4. 等待首次广播,失败则结束。
  5. 请求 POLICE 模型并跨帧等待加载。
  6. 由脚本主机预留容量、创建车辆,将 VEH_TO_NET 的网络标识放入广播数据。
  7. 在每帧循环中处理机器人/车辆行为及终止条件。[S5]

这是语言与宿主协作的完整例子:普通 IF/REPEAT 表达逻辑,WAIT 表达协作等待,网络权限由 Native 检查,实体转换为网络 ID 再传输。广播变量名带 Global 并不是语言自动复制的证据,注册调用才是关键。

测试中的“只保留一个 WAIT”注释是该控制循环的编码约定,不是文法限制;它有助于让每次循环对应一个清晰更新阶段。

7. 对新语言的建议#

为复制状态提供显式 schema:字段 ID、类型、量化范围、权威方、更新频率、默认值与版本。分开 replicated state、message 和 local state,编译期禁止广播本地指针和无效跨机句柄。

API 应明确区分 script authority、entity authority 和 permission;迁移后重新获取权力,并通过版本/epoch 避免旧操作重复执行。是否采用确定性模拟是独立架构选择,需同步约束随机数、时钟、浮点和 Native 副作用;当前语言结构本身不提供这些保证。

源码证据#

  • S1 — 网络脚本和广播声明。
  • S2 — scriptHandlerNetComponent;广播注册。
  • S3 — RegisterHost/PlayerBroadcastVariables。
  • S4 — CBroadcastDataElement;基础数组状态比较接口。
  • S5 — soaktest 注册与主循环;主机建车。