Framework 基础设施:fwsys / fwtl / fwutil / fwmaths 及其余子目录
本页覆盖 rage/framework/src 中“不是实体、场景或流式”的基础设施:配置(fwConfigManager/gameconfig)、计时(fwTimer)、有限状态机(fwFsm)、元数据存储(fwMetaDataStore)、对象池(fwPool 内部实现)与引用安全指针(fwRegdRef),以及一组工具/数学/调试/本地化/商城/纹理转换库。最后给出 framework/src 全部子目录的归属索引,指向负责它们的 Wiki 页面。
背景与相关页面#
- 游戏如何用这些池(
CPools、各类实体池、内存堆)与内存预算:见 ../01-runtime/memory-and-pools.md。 gameSkeleton(fwsys/gameskeleton.*)与CGame的 init/shutdown/update 注册:见 ../01-runtime/game-skeleton-and-main-loop.md。CApp(派生自fwApp)的应用状态机:见 ../01-runtime/startup-and-app-fsm.md。- parser/PSO(
fwPsoStoreLoader背后的格式)与.psc代码生成:见 ../02-rage-core/parser-and-metadata.md、../00-overview/build-and-config.md。 - 使用这些基础设施的框架模块:entity-and-archetype.md、scene-graph-and-visibility.md、streaming-engine.md。
相关源码文件#
| 文件 | 内容 |
|---|---|
fwsys/config.h/.cpp/.psc | fwConfigManager、fwConfig、按构建/平台过滤的配置合并 |
fwsys/timer.h/.cpp | fwTimer、fwTimeSet(多时间域) |
fwsys/fsm.h/.cpp、app.h/.cpp | fwFsm 状态机基类、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、fwdecorator | fwEntity、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、fwevent | aiTask 框架、事件 | ../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 |
fwui | UI 框架层 | ../18-frontend-ui/text-and-localisation.md |
fwcontrol | 见下方说明 | ../22-input-platform/input-and-control-mapping.md(按简报指派;内容实为录制数据,见 §8.6) |
framework_lib_psc、vcproj | parser 代码生成工程与 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:
- 把延迟的脚本暂停/恢复请求生效;非 FINAL 处理调试暂停键(Orbis 额外用 NumLock)、单步、缩放快捷键。
- 读
sysTimer得到真实帧时间并重置;调用netInterface::StartOfFrame()(注释:让网络位置更新获得准确时间戳)src/dev_ng/rage/framework/src/fwsys/timer.cpp:509-517。 - 按
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。 - 最后把结果同步到 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/GetPool | src/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新对象,析构RemoveKnownRefsrc/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 位,建议改用 atHashMap | src/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.h | DECLARE_RTTI_BASE_CLASS / DERIVED_CLASS 宏:基于类名哈希的轻量 RTTI(GetIsClass<T>()、AsClass<T>()) | 广泛 | src/dev_ng/rage/framework/src/fwutil/rtti.h:19-50 |
Gen9Settings.h | RSG_GEN9、IS_GEN9_PLATFORM、GEN9_STANDALONE_* 开关(默认 RSG_GEN9=0) | — | src/dev_ng/rage/framework/src/fwutil/Gen9Settings.h:1-36 |
xmacro.h | GTA_ONLY/RDR_ONLY/GAMETOOL_ONLY、X-macro FOREACH 等 | — | src/dev_ng/rage/framework/src/fwutil/xmacro.h:13-40 |
fwQuadTreeNode | 通用二维四叉树(池分配),支持按矩形/点查询与回调 | 拾取物管理、环境音频、game.cpp、scene.cpp | src/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 |
fwKeyGen | CRC 键生成(数据块/字符串) | — | 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.h | 18-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.h | fwRandom:非 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.h | SPU 版 fwRandom(MT) | src/dev_ng/rage/framework/src/fwmaths/RandomSPU.h:1-30 |
Range.h / Rect.h | fwRange<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 |
fwVectorMap | BANK 下叠加在游戏上的 2D 调试地图(非 BANK 为空实现) | src/dev_ng/rage/framework/src/fwdebug/vectormap.h:1-30、src/dev_ng/rage/framework/src/fwdebug/vectormap.h:121-128 |
fwDebugDraw | DEBUG_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.xml | src/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的工具链用途未展开。