CD Code Digest Hub /GTA V · v2

Framework 基础设施:fwsys / fwtl / fwutil / fwmaths 及其余子目录

65 分钟阅读 12 个章节

本页覆盖 rage/framework/src 中“不是实体、场景或流式”的基础设施:配置(fwConfigManager/gameconfig)、计时(fwTimer)、有限状态机(fwFsm)、元数据存储(fwMetaDataStore)、对象池(fwPool 内部实现)与引用安全指针(fwRegdRef),以及一组工具/数学/调试/本地化/商城/纹理转换库。最后给出 framework/src 全部子目录的归属索引,指向负责它们的 Wiki 页面。

背景与相关页面#

相关源码文件#

文件内容
fwsys/config.h/.cpp/.pscfwConfigManager、fwConfig、按构建/平台过滤的配置合并
fwsys/timer.h/.cppfwTimer、fwTimeSet(多时间域)
fwsys/fsm.h/.cpp、app.h/.cppfwFsm 状态机基类、fwApp
fwsys/game.h/.cpp、glue.h、metadatastore.h/.cpp、fileExts.h、syschannel.*流式模块注册入口、纹理载荷胶水、元数据存储、文件类型
fwsys/gameskeleton.h/.cpp见 01-runtime(本页只链接)
fwtl/Pool.h/.cpp、Pagedpool.h、DefragPool.h/.cpp、poolcriticalsection.h对象池族
fwtl/regdrefs.h/.cpp、ExtRefAwareBase.*、DebugOwnerHistory.*引用安全指针与调试历史
fwtl/assetstore.*、nameregistrar.*、LinkList.h、StepAllocator.h、customvertexpushbuffer.h资产存储(见流式页)与杂项容器
fwutil/*、fwmaths/*、memory/*、fwdebug/*、fwgeovis/*、fwlocalisation/*、fwcommerce/*、fwtextureconversion/*、fwcontrol/*工具库

1. framework/src 子目录归属索引#

rage/framework/src 共 34 个子目录。下表给出每个目录在本 Wiki 中的权威页面(本页负责的条目在后续章节展开)。

子目录内容(一句话)权威页面
entity、fwdecoratorfwEntity、fwArchetype、扩展、装饰器entity-and-archetype.md
fwscene世界表示、可见性扫描、搜索、地图数据、资产存储scene-graph-and-visibility.md
streaming流式引擎streaming-engine.md
fwsys(除 gameskeleton)、fwtl、fwutil、fwmaths、memory、fwdebug、fwgeovis、fwlocalisation、fwcommerce、fwtextureconversion基础设施本页
fwsys/gameskeleton.*初始化/关闭/更新函数注册骨架../01-runtime/game-skeleton-and-main-loop.md
ai、fweventaiTask 框架、事件../07-ai-tasks/task-system.md、../07-ai-tasks/events-and-responses.md
fwanimation、fwactuator动画导演、执行器../10-animation/game-animation-and-ik.md
fwnet网络对象框架../17-network-sync/network-object-model.md
fwscript脚本框架层../14-script-runtime/script-handlers-and-threads.md
fwaudio音频框架层../13-audio/music-radio-speech.md
fwrenderer、fwdrawlist、fwlight、timecycle、video渲染阶段基类、绘制列表、灯光、timecycle、视频../11-rendering/render-pipeline-and-phases.md、../11-rendering/drawlists-and-render-thread-handoff.md、../11-rendering/deferred-lighting-and-shadows.md、../11-rendering/environment-rendering.md
vfx、fwpheffects特效框架、物理效果../12-vfx/decals-and-vfx-systems.md
phframework物理框架层../09-physics/rage-physics-engine.md
fwvehicleai车辆 AI 框架../08-vehicles/vehicle-ai-and-road-network.md
fwuiUI 框架层../18-frontend-ui/text-and-localisation.md
fwcontrol见下方说明../22-input-platform/input-and-control-mapping.md(按简报指派;内容实为录制数据,见 §8.6)
framework_lib_psc、vcprojparser 代码生成工程与 VS 工程/unity 文件../00-overview/build-and-config.md

2. fwConfigManager:gameconfig 与池尺寸#

2.1 目的与数据模型#

头注释:fwConfigManager 处理指定池尺寸及类似设置/上限的游戏配置文件;所有 fwBasePool 派生池都可被配置覆盖;应尽早初始化(parser 之后),池对象可以先构造但在配置加载后才能使用 src/dev_ng/rage/framework/src/fwsys/config.h:26-37。

类型作用证据
fwPoolSizeEntry / fwPoolSizeEntryArray{池名, 尺寸} 数组(parser 可解析)src/dev_ng/rage/framework/src/fwsys/config.h:43-63
fwConfig合并后的配置:m_PoolSizes 与 m_ArchMaxModelInfos(默认 32200);游戏派生 CGameConfig 增加大量子配置src/dev_ng/rage/framework/src/fwsys/config.h:211-244、src/dev_ng/rage/framework/src/fwsys/config.cpp:270-283、src/dev_ng/game/game/config.h:536-580
fwConfigWithFilter(Base)m_Build、m_Platforms 过滤串 + 一个 fwConfig;非 FINAL 额外有 m_Param(命令行参数名)src/dev_ng/rage/framework/src/fwsys/config.h:255-312
fwAllConfigs文件根:fwConfigWithFilter 数组src/dev_ng/rage/framework/src/fwsys/config.h:322-328
fwConfigManagerImpl<_CfgData>模板:InitClass(file) 创建单例并 Load,CreateConfigData 返回游戏的配置子类src/dev_ng/rage/framework/src/fwsys/config.h:163-187

parser 模式定义在 config.psc(注意 fwConfig 的 psc 只声明了 m_PoolSizes;m_ArchMaxModelInfos 由 C++ 中 PAR_PARSABLE 的游戏子类或其他 psc 负责,本页未追踪)src/dev_ng/rage/framework/src/fwsys/config.psc:1-37。头文件里的 XML 示例展示了覆盖 FragmentStore 池尺寸的写法 src/dev_ng/rage/framework/src/fwsys/config.h:199-209。

简报中提到的 fwPoolSizes 在源码中不存在;对应的类型是 fwConfigManager::fwPoolSizeEntryArray(字段名 fwConfig::m_PoolSizes)。

2.2 加载与合并#

Load(file):创建空配置 → PARSER.LoadObjectPtr 读取 fwAllConfigs(文件存在但解析为空时 Quitf(ERR_GAMECONFIG_1))→ 依次遍历每个 fwConfigWithFilter,MatchFilter 通过的才合并:非池数据调用虚函数 MergeNonPoolData,池尺寸按 atStringHash(池名) 写入 m_PoolSizeMap,后出现的条目覆盖先前的 src/dev_ng/rage/framework/src/fwsys/config.cpp:75-130。

MatchFilter 的取值表 src/dev_ng/rage/framework/src/fwsys/config.cpp:222-266:

维度关键字 → 条件
构建any、bank=__BANK、bankrelease=!__DEV&&__BANK、beta=__DEV&&__OPTIMIZED、debug=__DEV&&!__OPTIMIZED、dev=__DEV、final、profile、release=!__DEV&&!__BANK&&!__FINAL、nonfinal
平台any、ps3/psn、psp2、x64=__WIN32PC、xbox360/xenon、xboxone=RSG_DURANGO、ps4=RSG_ORBIS
参数(非 FINAL)若设置了 m_Param,该命令行参数必须存在

构建、平台、参数三者都匹配才算命中。

2.3 查询与锁定#

GetSizeOfPool(hash, default):映射中有值且未锁定时,若 sm_UseLargerPoolFromCodeOrData 则取 max(default, 配置值),否则断言“配置值 ≥ 默认值”并返回配置值;无覆盖则返回默认值 src/dev_ng/rage/framework/src/fwsys/config.cpp:33-53。LockPoolSize(name) 把条目置为 kLockedPoolSize(-1);若配置文件里列了被锁定的池则 assert/报错 src/dev_ng/rage/framework/src/fwsys/config.cpp:56-72、src/dev_ng/rage/framework/src/fwsys/config.h:131-135。CONFIGURED_FROM_FILE(=1) 用作“必须由配置覆盖”的占位默认值 src/dev_ng/rage/framework/src/fwsys/config.h:332-336。

游戏装配:CSystem 初始化时 fwConfigManagerImpl<CGameConfig>::InitClass("common:/data/gameconfig.xml");非 FINAL 可用 -altGameConfig 指定替代文件(不存在则回退)src/dev_ng/game/system/system.cpp:156、src/dev_ng/game/system/system.cpp:494-507。gameconfig.xml 属于数据资产,不在本源码树中(全树搜索 gameconfig*.xml 无结果),因此各池的实际尺寸无法从源码确认。

谁在查询:FW_INSTANTIATE_CLASS_POOL* 宏生成的 InitPool(§5.2)、fwAssetStore::FinalizeSize(streaming-engine.md)、strStreamingInfoManager::Init 的若干表(MaxLoadedInfo 等)、fwArchetypeManager 的原型上限(m_ArchMaxModelInfos,见 entity-and-archetype.md)。


3. fwTimer:多时间域计时#

3.1 时间域#

fwTimeSet 记录一个时间域:毫秒时间、帧计数、上一帧时间、秒/毫秒步长、倒数步长、毫秒小数余量;Init 默认步长 0.05s src/dev_ng/rage/framework/src/fwsys/timer.h:46-78。fwTimer 维护多个时间域,注释说明“缩放(慢动作)先于裁剪(避免过快/过慢帧)”src/dev_ng/rage/framework/src/fwsys/timer.h:360-391:

时间域缩放裁剪暂停时推进证据
sm_systemTime否否是src/dev_ng/rage/framework/src/fwsys/timer.cpp:620-635
sm_gameTime是是否(单步时推进)src/dev_ng/rage/framework/src/fwsys/timer.cpp:542-563
sm_nonPausedGameTime是是是src/dev_ng/rage/framework/src/fwsys/timer.cpp:528-540
sm_scaledNonClippedTime是否否src/dev_ng/rage/framework/src/fwsys/timer.cpp:568-580
sm_nonScaledClippedTime否见下文差异否src/dev_ng/rage/framework/src/fwsys/timer.cpp:582-594
sm_camTime仅当 sm_bShouldApplyGameTimeScaleToCameras是否(步长仍更新)src/dev_ng/rage/framework/src/fwsys/timer.cpp:638-663
sm_nonPausableCamTime同上是是src/dev_ng/rage/framework/src/fwsys/timer.cpp:666-679
sm_nonPausedNonScaledClippedTime否是是src/dev_ng/rage/framework/src/fwsys/timer.cpp:681-693
sm_replayTimeScaledNonClippedPausable(GTA_REPLAY_RAGE)是新路径为是否src/dev_ng/rage/framework/src/fwsys/timer.cpp:596-609

GetNonPausableCamFrameCount() 的注释表明它被反篡改代码使用、不供一般使用 src/dev_ng/rage/framework/src/fwsys/timer.h:183;PC 旧路径还把系统帧计数同步为该值 src/dev_ng/rage/framework/src/fwsys/timer.cpp:632-634。本页不展开相关安全逻辑(见 ../23-debug-security/security-overview.md)。

3.2 时间缩放#

有效缩放 = GetTimeWarpActive():四类缩放(eTST_Camera/Script/UI/SpecialAbility)中最小值若 < 1 则取之,否则取 sm_fTimeScale;非 FINAL 再乘调试缩放 sm_fDebugTimeScale src/dev_ng/rage/framework/src/fwsys/timer.h:396-405、src/dev_ng/rage/framework/src/fwsys/timer.h:511-520、src/dev_ng/rage/framework/src/fwsys/timer.cpp:504-508。assert 构建中,联网游戏缩放不为 1 且非脚本修改时 CHECKOUT() 断言“MP 中时间缩放应为 1”src/dev_ng/rage/framework/src/fwsys/timer.h:18-32。

3.3 帧更新#

fwTimer::Update()(每帧)src/dev_ng/rage/framework/src/fwsys/timer.cpp:417-710:

  1. 把延迟的脚本暂停/恢复请求生效;非 FINAL 处理调试暂停键(Orbis 额外用 NumLock)、单步、缩放快捷键。
  2. 读 sysTimer 得到真实帧时间并重置;调用 netInterface::StartOfFrame()(注释:让网络位置更新获得准确时间戳)src/dev_ng/rage/framework/src/fwsys/timer.cpp:509-517。
  3. 按 s_newUpdate 选择更新路径:新路径对每个时间域调用 fwTimeSet::Update(step, scale, clip),它累积毫秒小数余量(s_retainMsRemainder 默认 true)并按需把步长钳到 [min, max] src/dev_ng/rage/framework/src/fwsys/timer.cpp:158-183;旧路径用预先钳好的步长直接累加。s_newUpdate 默认值是 __WIN32PC,即只有 PC 默认走新路径(BANK 可切换)src/dev_ng/rage/framework/src/fwsys/timer.cpp:51-52、src/dev_ng/rage/framework/src/fwsys/timer.cpp:239-240。
  4. 最后把结果同步到 RAGE 的全局 TIME(注释:待 RAGE 移除对 TIME 的引用后可删)src/dev_ng/rage/framework/src/fwsys/timer.cpp:695-704。

帧时间范围:静态初值 min = 1/30、max = 1/15 src/dev_ng/rage/framework/src/fwsys/timer.cpp:98-99;Init() 把 min 改为 1/3000(注释:允许 100 倍慢动作),max 为 1/15(或 -maxframetime);非 FINAL 支持 -forcedfps、-fixedframetime、-maxframetime、-minframetime、-maxfps、-timescale src/dev_ng/rage/framework/src/fwsys/timer.cpp:252-305、src/dev_ng/rage/framework/src/fwsys/timer.cpp:323-327。FRAME_LIMITER_MIN_FRAME_TIME = 1/30,注释称游戏不会跑得比这更快(CSystem::EndRender 等待)src/dev_ng/rage/framework/src/fwsys/timer.h:16。

注释与行为差异:sm_nonScaledClippedTime 的注释写“non scaled and clipped”,旧路径确实钳制步长,但新路径调用的是 Update(TimeStepInSeconds, 1.0f, false)——clip=false,即 PC 默认路径下该时间域不裁剪 src/dev_ng/rage/framework/src/fwsys/timer.cpp:582-594。依赖它“已裁剪”的代码在 PC 上可能得到超过 1/15s 的步长(推断,未检查调用方)。


4. fwFsm、fwApp、fwGame、fwMetaDataStore#

4.1 fwFsm#

fwFsm 是基于宏的极简状态机:派生类实现 UpdateState(state, message, event),用 fwFsmBegin / fwFsmState(s) / fwFsmOnEnter / fwFsmOnUpdate / fwFsmOnExit / fwFsmOnMsg(m) / fwFsmEnd 宏写成嵌套 if 链 src/dev_ng/rage/framework/src/fwsys/fsm.h:14-32、src/dev_ng/rage/framework/src/fwsys/fsm.h:34-100。返回值 Unhandled/Continue/Quit,事件 OnEnter/OnUpdate/OnExit/OnMessage src/dev_ng/rage/framework/src/fwsys/fsm.h:42-57。

Update() 语义 src/dev_ng/rage/framework/src/fwsys/fsm.cpp:41-84:累加运行时间与状态内时间;循环直到某次调用返回非 Unhandled——若有挂起的状态切换,先对旧状态发 OnExit、标记“新状态未进入”、清零状态内时间;否则若有挂起消息,先交给当前状态,未处理再交给全局处理器(state = -1);否则对新状态发一次 OnEnter,之后每帧 OnUpdate。SetMessage 断言上一条消息已处理 src/dev_ng/rage/framework/src/fwsys/fsm.cpp:35-39。因为 Update 在返回 Unhandled 时会继续循环,所以一帧内可以连续完成 Exit → Enter → … 多步。

使用者:fwApp : fwFsm(空壳)→ 游戏 CApp : fwApp src/dev_ng/rage/framework/src/fwsys/app.h:15-21、src/dev_ng/game/Core/app.h:20;以及若干音频指挥器与场景聚类包装(如 audVehicleConductor、audGunFightConductor、CSPClusterFSMWrapper)src/dev_ng/game/audio/vehicleconductor.h:32、src/dev_ng/game/task/Scenario/ScenarioClustering.h:130。游戏 AI 任务不使用 fwFsm(任务 FSM 见 ../07-ai-tasks/task-system.md)。

4.2 fwGame / fwGameInterface / glue#

fwGame 只做一件事:Init() → RegisterStreamingModules(),依次注册框架层存储,再回调游戏接口 fwGameInterface::RegisterStreamingModules() src/dev_ng/rage/framework/src/fwsys/game.h:13-35、src/dev_ng/rage/framework/src/fwsys/game.cpp:27-58(注册顺序与 strIndex 布局见 streaming-engine.md §2.1)。fwsys/glue.h 的 fwTexturePayload 是一个持有 grcTexture* 的小包装(析构时断言纹理指针已被清空)src/dev_ng/rage/framework/src/fwsys/glue.h:15-33。

4.3 fwMetaDataStore#

fwMetaDataStore : fwAssetStore<fwMetaDataFile> 管理 .#mt(PSO/XML 元数据)文件:模块名 "MetaDataStore"、META_FILE_ID、槽数来自配置;PSO 加载器允许加载 XML、原位加载、布局不匹配告警,根类型不限(SetRootType(NULL))src/dev_ng/rage/framework/src/fwsys/metadatastore.h:18-85、src/dev_ng/rage/framework/src/fwsys/metadatastore.cpp:25-41。它自带一个 fwBoxStreamer(优先半径 30,ASSET_METADATA 预流距离 50),但默认所有槽都标记为 ignored,只有调用 MakeSlotStreamable(name, aabb) 的槽才参与按位置流送 src/dev_ng/rage/framework/src/fwsys/metadatastore.cpp:19、src/dev_ng/rage/framework/src/fwsys/metadatastore.cpp:43-59。行人模型的元数据依赖即来自此存储(见 streaming-engine.md §3.4)。

4.4 fileExts.h#

文件类型 ID 与平台扩展名表见 streaming-engine.md §2.4。


5. fwtl:对象池与引用安全指针#

5.1 fwBasePool / fwPool<T> 内部实现#

fwPool 是固定容量、带每槽标志字节的对象池;注释说明它比 atl/pool.h 支持更多标志并可遍历所有元素 src/dev_ng/rage/framework/src/fwtl/Pool.h:27-28。

内存布局:m_aStorage(容量 × 元素大小)+ m_aFlags(每槽 1 字节)+ 头部若干 s32 src/dev_ng/rage/framework/src/fwtl/Pool.h:364-371。标志字节高位 POOL_FLAG_ISFREE=0x80,低 7 位是“引用(世代)号” src/dev_ng/rage/framework/src/fwtl/Pool.h:31-32。注释提醒不要随意调整成员顺序,因为 SPU 代码依赖 src/dev_ng/rage/framework/src/fwtl/Pool.h:361-363。存储分配顺序:360 用专用池分配器、PS3 用 residual 分配器,PS3 上若启用 flex 堆则用 flex 分配器,否则 rage_new src/dev_ng/rage/framework/src/fwtl/Pool.cpp:458-526。

空闲链表:侵入式——空闲槽的前 4 字节存“下一个空闲下标”,因此 fwPool<T> 编译期要求 sizeof(T) ≥ sizeof(s32) src/dev_ng/rage/framework/src/fwtl/Pool.cpp:141-159、src/dev_ng/rage/framework/src/fwtl/Pool.h:402。

操作实现要点证据
New()从链表头取槽,清 free 位,世代号 +1(SetReference 保证 ≥1),计数与峰值更新;红区告警。链表空时:有 spillover 则从游戏虚拟堆单独分配;否则 BANK 调 PoolFullCallback,再 Quitf("… Pool Full … raise PoolSize in common/data/gameconfig.xml")(若尺寸不来自配置则提示“See a programmer”)src/dev_ng/rage/framework/src/fwtl/Pool.cpp:540-665、src/dev_ng/rage/framework/src/fwtl/Pool.h:356-359
Delete(p)非 __NO_OUTPUT 构建用 0xDD 填充;把槽追加到链表尾(FIFO 复用,降低立即复用同槽的概率);置 free 位src/dev_ng/rage/framework/src/fwtl/Pool.cpp:753-836
GetIndex(p) / GetAt(h)句柄 = (下标 << 8) + 标志字节;GetAt 比较句柄低 8 位与当前标志字节,不等(已释放或世代号变化)返回 NULL——这是脚本实体句柄的防悬空机制src/dev_ng/rage/framework/src/fwtl/Pool.cpp:885-922、src/dev_ng/rage/framework/src/fwtl/Pool.h:235-243
GetSlot(i)无分支:free 位为 1 时用掩码把返回地址清零src/dev_ng/rage/framework/src/fwtl/Pool.h:255-297

spillover:RAGE_POOL_SPILLOVER = (__XENON || __PPU) && !ATL_POOL_SPARSE src/dev_ng/rage/base/src/atl/pool.h:40。仅在旧主机上,池的后 spillover × 容量 个槽不预分配,而是在主体用尽后逐个从游戏虚拟堆分配 src/dev_ng/rage/framework/src/fwtl/Pool.cpp:255-296。因此 FW_INSTANTIATE_CLASS_POOL_SPILLOVER(T, n, 0.62f, …) 里的比例在 PC/新主机上没有效果。ATL_POOL_SPARSE(= USE_SPARSE_MEMORY)时每个元素单独分配 src/dev_ng/rage/base/src/atl/pool.h:25、src/dev_ng/rage/framework/src/fwtl/Pool.cpp:542-577。

5.2 池注册宏#

宏作用证据
FW_REGISTER_CLASS_POOL(T)(类内)声明 static Pool* _ms_pPool、重载 operator new/delete 走池、声明 InitPool/ShutdownPool/GetPoolsrc/dev_ng/rage/framework/src/fwtl/Pool.h:48-73、src/dev_ng/rage/framework/src/fwtl/Pool.h:105
FW_REGISTER_LOCKING_CLASS_POOL(T, CS)同上,但 new/delete 期间构造临界区对象src/dev_ng/rage/framework/src/fwtl/Pool.h:75-110
FW_INSTANTIATE_CLASS_POOL(T, n, hash)(cpp)InitPool 用 fwConfigManager::GetSizeOfPool(hash, n) 决定容量并注册到池追踪器src/dev_ng/rage/framework/src/fwtl/Pool.h:118-123
…_SPILLOVER / …_BASECLASS_…(存储大小不同于类大小)/ …_LOCKED_SIZE(锁定配置覆盖)/ …_NO_FLEX(COMMERCE_CONTAINER)变体src/dev_ng/rage/framework/src/fwtl/Pool.h:125-188
rage_checked_pool_new(T)池满时返回 NULL 而非调用构造函数src/dev_ng/rage/framework/src/fwtl/Pool.h:191

注意 FW_INSTANTIATE_BASECLASS_POOL_LOCKED_SIZE 的 InitPool 签名没有 redZone 参数,但函数体使用了 redZone src/dev_ng/rage/framework/src/fwtl/Pool.h:153-158——推断该宏在当前代码中从未被实例化(否则无法编译)。

其他池类型:

  • fwRscMemPagedPool / FW_REGISTER_CLASS_PAGEDPOOL:基于 atPagedPool,页从流式分配器的资源虚拟内存分配,失败则回退游戏虚拟堆并报错 src/dev_ng/rage/framework/src/fwtl/Pagedpool.h:32-82、src/dev_ng/rage/framework/src/fwtl/Pagedpool.h:144-195。
  • fwDescPool:支持增量/完全碎片整理的数组分配池,专门用于场景图的 fwEntityDesc(见 scene-graph-and-visibility.md §2.6)src/dev_ng/rage/framework/src/fwtl/DefragPool.h:41-102。
  • fwPoolCriticalSection<T>:默认不加锁而是断言在更新线程;SetUseLock(true) 后才真正上锁 src/dev_ng/rage/framework/src/fwtl/poolcriticalsection.h:16-53。

5.3 fwRegdRef / fwRefAwareBase#

头注释说明:被引用对象派生自 fwRefAwareBase,持有方用 fwRegdRef<T> 代替裸指针;对象被删除时所有登记的 fwRegdRef 自动置 NULL;“粗糙地”线程安全,已知引用存放在可调试的池中 src/dev_ng/rage/framework/src/fwtl/regdrefs.h:7-35。

  • 每个 fwRefAwareBaseImpl 只多一个指针 m_pKnownRefHolderHead(fwRefAwareBase 含 vtable 共 8/16 字节)src/dev_ng/rage/framework/src/fwtl/regdrefs.h:614-621。
  • AddKnownRef(ppRef) 从 "Known Refs" 池(尺寸来自配置)分配一个 fwKnownRefHolder{ppRef, next} 插到链表头;析构时 ClearAllKnownRefs 遍历链表把每个 *ppRef 置空 src/dev_ng/rage/framework/src/fwtl/regdrefs.h:119-145、src/dev_ng/rage/framework/src/fwtl/regdrefs.h:315-357、src/dev_ng/rage/framework/src/fwtl/regdrefs.cpp:13。
  • 并发保护是 fwPoolCriticalSection<fwKnownRefHolder>(默认只断言主线程)src/dev_ng/rage/framework/src/fwtl/regdrefs.h:107-108。
  • fwRegdRef<T> 的赋值先 RemoveKnownRef 旧对象再 AddKnownRef 新对象,析构 RemoveKnownRef src/dev_ng/rage/framework/src/fwtl/regdrefs.h:625-680。
  • fwExtRefAwareBase(非 FINAL)在此基础上加数值引用计数与 fwDebugOwnerHistory 调用栈历史,用于排查泄漏/孤儿 src/dev_ng/rage/framework/src/fwtl/ExtRefAwareBase.h:7-52、src/dev_ng/rage/framework/src/fwtl/DebugOwnerHistory.h:16-43。

代价:每次设置/清空一个 fwRegdRef 都是一次池分配/释放与链表操作;对象删除是 O(引用数)。fwEntity 即通过 fwExtensibleBase : fwRefAwareBase 获得此能力(见 entity-and-archetype.md)。

5.4 其余 fwtl#

类型作用证据
fwNameRegistrarDef<K> / fwNameRegistrar专用哈希表(桶数组 + 链),注释说明最初为 16 位上限后扩为 32 位,建议改用 atHashMapsrc/dev_ng/rage/framework/src/fwtl/nameregistrar.h:15-49
fwLink<T> / fwLinkList<T>固定容量的双向链表(预分配存储 + 首尾哨兵)src/dev_ng/rage/framework/src/fwtl/LinkList.h:14-60
fwStepAllocator线性步进分配器(扫描作业的暂存分配即用它)src/dev_ng/rage/framework/src/fwtl/StepAllocator.h:26-40
VtxPushBuffer<T>直接向命令缓冲写顶点的 grcVertexBuffer 包装(360/PS3 专用路径 + 默认实现;SPU 不可用)src/dev_ng/rage/framework/src/fwtl/customvertexpushbuffer.h:1-35、src/dev_ng/rage/framework/src/fwtl/customvertexpushbuffer.h:942
fwAssetStore见 streaming-engine.md §2.3—

6. fwutil#

文件/类型作用游戏侧使用(抽样)证据
fwFlags<T>位标志模板(fwFlags8/16/32 等),__FLAG_DEBUGGING 时改为外联实现广泛src/dev_ng/rage/framework/src/fwutil/Flags.h:18-50
fwIdKeyGenerator / 唯一 ID 生成器由指针 + 偏移生成唯一 ID—src/dev_ng/rage/framework/src/fwutil/idgen.h:28-60
rtti.hDECLARE_RTTI_BASE_CLASS / DERIVED_CLASS 宏:基于类名哈希的轻量 RTTI(GetIsClass<T>()、AsClass<T>())广泛src/dev_ng/rage/framework/src/fwutil/rtti.h:19-50
Gen9Settings.hRSG_GEN9、IS_GEN9_PLATFORM、GEN9_STANDALONE_* 开关(默认 RSG_GEN9=0)—src/dev_ng/rage/framework/src/fwutil/Gen9Settings.h:1-36
xmacro.hGTA_ONLY/RDR_ONLY/GAMETOOL_ONLY、X-macro FOREACH 等—src/dev_ng/rage/framework/src/fwutil/xmacro.h:13-40
fwQuadTreeNode通用二维四叉树(池分配),支持按矩形/点查询与回调拾取物管理、环境音频、game.cpp、scene.cppsrc/dev_ng/rage/framework/src/fwutil/QuadTree.h:18-70
fwPtrList*单/双向指针链表;节点池的 FW_INSTANTIATE_CLASS_POOL 已被注释掉广泛src/dev_ng/rage/framework/src/fwutil/PtrList.cpp:9-10
fwKeyGenCRC 键生成(数据块/字符串)—src/dev_ng/rage/framework/src/fwutil/KeyGen.h:11-56
fwOrientator点集最小包围矩形朝向求解(按面积/周长/最大边)调试资产分析src/dev_ng/rage/framework/src/fwutil/orientator.h:28-50
fwProfanityFilter文本校验:脏话、保留词、文件系统非法字符(注释承认名不副实);词表由 ProfanityFilter.psc 描述视频编辑器、多人聊天、回放蒙太奇文本src/dev_ng/rage/framework/src/fwutil/ProfanityFilter.h:17-50
ForceNoPopups*非 FINAL 下临时禁止弹窗的 RAII—src/dev_ng/rage/framework/src/fwutil/popups.h:9-29

7. fwmaths、memory、fwdebug、fwgeovis#

7.1 fwmaths#

文件/类型作用证据
angle.h / fwAngle角度常量与工具(角度差、限幅到 ±π、插值)src/dev_ng/rage/framework/src/fwmaths/angle.h:10-40
geomutil.h / fwGeom::fwLine线段(注释:射线-三角形测试“仅供 PortalCorners 使用”)src/dev_ng/rage/framework/src/fwmaths/geomutil.h:21-40
kDOP18.h18-DOP 包围体(面/96 顶点表示)src/dev_ng/rage/framework/src/fwmaths/kDOP18.h:20-40
KeyholeTests.h人口控制“钥匙孔”形状测试(环带、楔形)src/dev_ng/rage/framework/src/fwmaths/KeyholeTests.h:1-40
PortalCorners.h / fwPortalCorners门户四角点,w 分量额外存标志/不透明度(场景图门户节点使用)src/dev_ng/rage/framework/src/fwmaths/PortalCorners.h:20-40
random.hfwRandom:非 SPU 直接用 C rand()/srand(),SPU 用 mthRandom(USE_RAGE_RAND = __SPU);SemiShuffledSequence;脚本专用 CRandomScripts(注释:脚本需独立且线程安全的随机数)与 CRandomMWCScripts(注释:为赌场游戏增加的独立 MWC 生成器)src/dev_ng/rage/framework/src/fwmaths/random.h:7、src/dev_ng/rage/framework/src/fwmaths/random.h:31-89、src/dev_ng/rage/framework/src/fwmaths/random.h:171-209
RandomSPU.hSPU 版 fwRandom(MT)src/dev_ng/rage/framework/src/fwmaths/RandomSPU.h:1-30
Range.h / Rect.hfwRange<T>;fwBox2D 与 fwRect(注释吐槽 fwRect 的 top/bottom 令人困惑)src/dev_ng/rage/framework/src/fwmaths/Range.h:13-30、src/dev_ng/rage/framework/src/fwmaths/Rect.h:14-60
Vector.h / vectorutil.h旧式向量辅助;包围盒最近点、fwBestFitPlane、重心坐标、切线空间、视锥包围盒等src/dev_ng/rage/framework/src/fwmaths/vectorutil.h:305-330

fwRandom 在非 SPU 平台使用 CRT 全局 rand(),不是线程安全的、也不可按实例复现;这也是脚本使用独立生成器的原因(后半句为注释所述意图)。

7.2 memory#

memory/memdebug.h 仅在 RAGE_MEMORY_DEBUG 下提供 sysMemDebug 单例:打印所有分配器、小块分配器、追踪器、池(RAGE_POOL_TRACKING)与存储(ENABLE_STORETRACKING)src/dev_ng/rage/framework/src/memory/memdebug.h:7-69。内存体系本身见 ../01-runtime/memory-and-pools.md。

7.3 fwdebug#

类型作用证据
fwDebugBank惰性 RAG bank:先只放一个“Toggle xxx bank”按钮,激活时才创建主控件src/dev_ng/rage/framework/src/fwdebug/debugbank.h:26-80
fwPickerManager 等实体拾取器框架:渲染拾取、世界探针拾取、相交实体拾取三种 picker,结果为 fwRegdRef<fwEntity> 数组,支持隔离/隐藏显示模式与“控制权”交接src/dev_ng/rage/framework/src/fwdebug/picker.h:31-70、src/dev_ng/rage/framework/src/fwdebug/picker.h:380-420
fwVectorMapBANK 下叠加在游戏上的 2D 调试地图(非 BANK 为空实现)src/dev_ng/rage/framework/src/fwdebug/vectormap.h:1-30、src/dev_ng/rage/framework/src/fwdebug/vectormap.h:121-128
fwDebugDrawDEBUG_DRAW = __IM_BATCHER 开关src/dev_ng/rage/framework/src/fwdebug/debugdraw.h:19-36

7.4 fwgeovis#

gv 命名空间定义 GTAV 的世界网格常量:单元 50m、每瓦片 3×3 单元(瓦片 150m)、世界范围 X −4050..5100、Y −4050..8400、Z 0..816,另有 “ISLANDHEIST” 扩展边界(Y 下限 −7000、X 上限 6000)与导航网格边界 ±6000..9000;HEIGHTMAP_GENERATOR_TOOL = __GAMETOOL src/dev_ng/rage/framework/src/fwgeovis/geovis.h:4-58。gvTile 存放高度图、密度图、哈希 ID 图等离线生成数据 src/dev_ng/rage/framework/src/fwgeovis/geovistile.h:7-40。游戏侧的高度图(GameWorldHeightMap)、水、路径服务器、物理、调试抓图等引用这些常量(rg "geovis.h|gv::WORLD" 结果)。这些常量与 WorldLimits.h 的 ±16000 引擎硬上限是两套不同用途的边界(见 scene-graph-and-visibility.md)。


8. fwlocalisation、fwcommerce、fwtextureconversion、fwcontrol#

8.1 fwlocalisation#

类型作用证据
fwLanguagePack语言包元信息:日期格式(DMY/MDY/YMD)与分隔符、BANK 下的公制/英制覆盖、语言名等src/dev_ng/rage/framework/src/fwlocalisation/languagePack.h:25-70
fwTextDatabaseStreamingWrapper把文本数据库注册为流式模块、按语言重载、加载“额外文本”元文件src/dev_ng/rage/framework/src/fwlocalisation/textDatabaseStreamingWrapper.h:28-82
fwLocalisedString、templateString.h、fwTextUtil、unit_conversion.h、fwTextFileConversion、fwDebugLanguageStrings、textTypes.h、.psc×2本地化字符串、模板串、文本工具、单位换算、文本文件转换、调试语言串文件列表

游戏代码中搜索不到 fwTextDatabaseStreamingWrapper/fwTextAsset 的使用(仅框架工程文件与 ragebuilder 工具引用),而 fwLanguagePack 被 9 个游戏文件使用。这表明 GTAV 的运行时文本系统没有采用框架层的文本数据库流式包装(推断;游戏文本系统见 ../18-frontend-ui/text-and-localisation.md)。

8.2 fwcommerce#

cCommerceUtil 是平台商城的抽象基类(初始化、更新、内容/分类数据是否就绪、数据拉取/错误状态、订阅依赖/排斥/追加销售查询、排序标签、分配器)src/dev_ng/rage/framework/src/fwcommerce/CommerceUtil.h:16-60。CommerceUtilInstance(forceBase) 按平台返回实现:360 → cXboxCommerceManager,PS3 → cPS3CommerceManager,Orbis → cOrbisCommerceManager,Durango → cDurangoCommerceManager;PC 分支被注释掉(注释称待 RoS 权益与 rgsc 代码并入后启用),因此 PC 返回基类实例 src/dev_ng/rage/framework/src/fwcommerce/CommerceUtil.cpp:562-570、src/dev_ng/rage/framework/src/fwcommerce/CommerceUtil.cpp:630-657。PC/ 子目录下的 Arvato/Steam/PC 实现因此不在运行路径上(推断)。游戏使用者:商城主界面、CommerceManager、网络遥测(rg CommerceUtilInstance|cCommerceUtil)。商城业务与在线服务见 ../16-network-online/live-cloud-commerce-social.md。

8.3 fwtextureconversion#

整个模块只在 (__BANK || __GAMETOOL) && !__RESOURCECOMPILER 下编译 src/dev_ng/rage/framework/src/fwtextureconversion/textureconversion.h:9;定义纹理转换参数/图像描述(parser 可解析)src/dev_ng/rage/framework/src/fwtextureconversion/textureconversion.h:25-40。游戏侧唯一使用者是调试纹理查看器 game/debug/TextureViewer/TextureViewer.cpp(rg textureconversion 结果)。资产管线中的纹理转换见 ../24-toolchain/asset-pipeline.md。

8.4 fwcontrol(归属说明)#

简报把 fwcontrol 归入 22 输入页,但其实际内容是录制数据格式而非输入控制:fwWaypointRecordingRoute : pgBase(路点录制:位置 + 打包的标志/朝向/移动混合比/两侧空间)src/dev_ng/rage/framework/src/fwcontrol/WaypointRecordingRoute.h:12-50、CVehicleStateEachFrame(车辆录制的逐帧状态,速度按 32767/120 定点编码,即最大 120 m/s)src/dev_ng/rage/framework/src/fwcontrol/record.h:4-30、CPedRecordingRsc(行人录制原始数据资源,缓冲 300000 字节,注释:每角色每秒约 2K)src/dev_ng/rage/framework/src/fwcontrol/pedrecording.h:6-30。游戏侧由 CWaypointRecordingRoute : fwWaypointRecordingRoute 与 game/control/record.h 使用 src/dev_ng/game/control/WaypointRecordingRoute.h:9。这些录制在流式层分别是 WAYPOINTRECORDING_FILE_ID/VEHICLERECORDING_FILE_ID 资源(src/dev_ng/rage/framework/src/fwsys/fileExts.h:71-72),内容上更接近 AI 路径/车辆录制(07/08 页)。


9. 约束与边界行为#

主题约束证据
池满非 spillover 平台直接 Quitf,提示改 gameconfig.xmlsrc/dev_ng/rage/framework/src/fwtl/Pool.cpp:621-634
池尺寸配置值小于代码默认值时 assert(除非 UseLargerPoolFromCodeOrData);锁定池不可在配置中出现src/dev_ng/rage/framework/src/fwsys/config.cpp:40-48、src/dev_ng/rage/framework/src/fwsys/config.cpp:56-72
句柄GetAt 依赖 7 位世代号,同一槽复用 127 次后可能误判有效(推断:世代号回绕,SetReference 保证非零)src/dev_ng/rage/framework/src/fwtl/Pool.h:356-359、src/dev_ng/rage/framework/src/fwtl/Pool.cpp:899-922
线程fwPoolCriticalSection 默认只断言更新线程;fwTimer::StartUserPause 断言更新线程src/dev_ng/rage/framework/src/fwtl/poolcriticalsection.h:21-31、src/dev_ng/rage/framework/src/fwsys/timer.cpp:712-714
FSM 消息一次只能挂一条消息src/dev_ng/rage/framework/src/fwsys/fsm.cpp:35-39
计时帧步长默认钳在 [1/3000, 1/15];nonScaledClippedTime 在新路径不裁剪src/dev_ng/rage/framework/src/fwsys/timer.cpp:252-258、src/dev_ng/rage/framework/src/fwsys/timer.cpp:583-586

10. 未决问题 / 证据不足#

  • gameconfig.xml 不在源码树中,所有 CONFIGURED_FROM_FILE 池/存储的实际尺寸无法确认。
  • CGameConfig 的完整字段(人口、2dEffect、模型信息、扩展、流式引擎、在线服务、脚本栈等子配置)属于游戏层,本页只列出访问器。
  • fwDescPool 的 DefragPartialNew 算法、atPagedPool 实现、fwNameRegistrar 的冲突处理未逐行核对。
  • fwsys/timer.cpp 中暂停/单步/网络时间同步的完整交互(与 netInterface 的关系)只看了入口。
  • fwlocalisation 的 .psc(extraTextFile.psc、textDatabaseSource.psc)与 fwTextFileConversion 的工具链用途未展开。