CD Code Digest Hub /GTA V

SanScript 的定位、研究方法与证据边界

7 分钟阅读 7 个章节 1 张图

分析日期:2026-10-30。基于 D:\Code\GTA5 中的源码快照,仅进行文件读取、静态追踪和文档校验,未编译工程、未运行编译器、未启动游戏,也未执行随附批处理。

1. 研究对象#

本报告承接项目结构与技术栈分析报告,将其中“玩法脚本 → Native → 游戏系统 → RAGE”的路径展开到语言实现层。

对象是工程文件明确命名的 SanScript:以 .sc 为入口、.sch 为公共定义的专用玩法语言。它是显式类型、命令式、面向游戏流程编排的语言,语法接近 BASIC,并加入 C 风格运算符、结构体、引用参数和函数指针。它离线编译为专用字节码,由 RAGE 脚本虚拟机执行,通过 Native 操作 C++ 游戏系统。[S1][S2]

项目中的 Ruby、Python、MaxScript、C# 编辑器和音频脚本系统不应混入这门语言。尤其是 .sch 包含函数实现、数据和条件编译内容,并非只有接口声明。

2. 实现地图#

层核心位置应回答的问题
玩法内容script/dev_ng/{singleplayer,multiplayer,shared,core}团队实际怎样组织游戏逻辑
编译器rage/script/tools/scriptcompiler接受什么语法,如何检查类型和生成代码
资源转换rage/script/tools/scriptrc字节码如何成为平台资源
编辑器rage/script/tools/SanScriptParser2、ragScriptEditor2补全、依赖构建、错误定位如何工作
VMrage/script/src/script槽位、指令、调用栈、挂起、Native ABI
游戏接入game/script、game/script_headers创建线程、清理资源、调用引擎能力
框架网络rage/framework/src/fwscript、fwnet脚本主机、广播变量、资源归属
存档game/SaveLoad/SavegameScriptData数据注册、序列化与恢复

这是离线编译、运行期解释执行的主链路。源码中有 C++ 输出和旧平台二进制脚本路径,但 EXECUTABLE_SCRIPTS 的定义含 0 && ...,不能据此将当前工程描述为 JIT 或默认 AOT 脚本系统。[S3]

3. 规模与抽样#

重新统计 script/dev_ng 下实际 .sc/.sch 文件,物理行数含空行、注释、重复和生成内容,不等于有效代码量或运行时代价:

一级目录.sc 文件.sch 文件合计物理行
singleplayer6369383,314,320
multiplayer3571,6956,119,863
shared14208364,136
core1149245,174
Code45341,340
BGNG14835
Tools026,251
合计1,0542,99910,091,919

此外,game/script_headers 有 68 个 .sch 文件,编译器目录有 115 个 .sc 样例或测试文件。文件统计用 Python 标准库 Path.rglob 和 bytes.splitlines() 完成,未执行内容。

抽样覆盖:入口 main.sc、自动存档控制器、车辆开发测试、多人 net_jacking_soaktest.sc、freemode.sc、Native 车辆创建、网络广播与存档登记。这里不是对一千万行玩法代码的逐行审计,也不把测试脚本当成所有生产脚本的规范。

4. 如何理解报告中的结论#

  • 源码事实:当前文件中明确出现的分支、数据结构、算法和配置。
  • 静态推导:根据这些实现推导出的成本或风险,例如按值传大结构体的槽位复制;不是实测结果。
  • 设计建议:面向新语言提出的方案,不代表 SanScript 已有能力。
  • 未确认:需要具体构建配置、运行环境或测试才能定论的事项。

各篇的 [S编号] 都链接到本地文件及已核对的行号。文末证据入口同时给出关键符号,便于源码变化后继续查找。主报告通过 Summary.md 汇总。

5. 必须处理的版本差异#

容易沿用的旧说法当前证据
全游戏只有一个 GLOBALS 块scrProgram 定义 64 块,24 位全局地址分成块号与偏移
VM word 永远四字节scrValue 在 64 位目标通常为八字节;.sco 初始化数据仍以四字节元素保存
每帧固定运行 1,000 条指令旧手册有此说法;当前默认常量是 13,000,000,快速内核的限制机制又不同
AND/OR 永远不短路编译器可由 -shortcircuit 改变语义,当前 SP 工程启用了该选项
预处理只支持不可嵌套的 IFDEF当前 lexer 要求 #IF,支持嵌套计数及 DEFINED、NOT
有 HSM 示例就说明当前语言支持 STATE/EVENT目录有历史 HSM 示例和编辑器开关;当前 scr.y token/产生式不能证明这些语法仍可编译
有 threadrun.cpp 就应以它为准当前 thread.cpp 末尾已合入快速内核,应优先分析这个实现

旧手册适合解释设计意图,当前文法、生成器、运行时和工程选项共同决定真实行为。源码来自跨平台、跨年代的集合,不能据此确认某一零售版本的全部构建宏。[S2–S6]

6. 对新语言研究的启发#

研究一门游戏脚本语言,需要同时回答“程序表达了什么”“帧调度何时执行它”“它可以造成哪些引擎副作用”。只模仿关键词会错过最有价值的部分:资源归属、可恢复执行、Native 契约、调试观测和内容规模下的工程组织。

后续设计应维护一个可版本化的语言规范,明确编译选项、目标 ABI、调试模式和资源格式。避免让旧手册、编辑器语法与编译器悄悄成为三套规范。

源码证据#

  • S1 — GTA5_SP.scproj:Language 与工具路径。
  • S2 — script.dtx:历史语言手册。
  • S3 — program.h:EXECUTABLE_SCRIPTS、分页及全局块。
  • S4 — value.h:scrValue。
  • S5 — scr.y:预处理器。
  • S6 — thread.cpp:合入的快速解释内核。