CD Code Digest Hub /GTA V · v2

车辆架构:CVehicle 类层次、工厂、模型元数据、人口与帧内时序

98 分钟阅读 17 个章节 2 张图

本页是 08-vehicles/ 的父页面,解释 GTAV 里“车辆”这一实体在 C++ 层如何组织:VehicleType 枚举如何驱动类层次与类型判断、CVehicleFactory 如何创建/销毁车辆并挂接音频实体与 gadget、SetModelId 如何把模型信息(CVehicleModelInfo)、操控数据(CHandlingData)、物理实例与座位/门/轮子组装起来、vehiclelayouts/carcols/vehicles.meta 等数据驱动配置分别落在哪些类上、车辆人口(CVehiclePopulation)如何以“生成链接 + 异步作业 + 单周期限额”生成与回收车辆,以及一辆车在一帧内被哪些系统按什么顺序处理。

车辆代码规模很大:Vehicle.cpp 约 38,600 行、vehicle.h 约 3,470 行(主类声明从第 401 行开始)src/dev_ng/game/Vehicles/vehicle.h:401-411。物理/操控/损坏与 LOD 细节见子页 vehicle-physics-handling-damage.md;车辆 AI、路网、交通灯、录像与 GPS 见 vehicle-ai-and-road-network.md。

背景与相关页面#

相关源码文件#

文件作用
game/Vehicles/vehicle.h、Vehicle.cppCVehicle 基类:控制输入、物理入口、LOD/dummy 转换、AI 挂接、每帧静态更新函数、池大小助手
game/Vehicles/VehicleDefines.h池/数组上限、健康值常量、eVehicleDummyMode、锁状态、任务树枚举
game/Vehicles/VehicleFactory.h、VehicleFactory.cppCVehicleFactory:池初始化、创建/销毁、拖车/货物、gadget 装配、调试 bank
game/Vehicles/Automobile.*、Bike.*、Bmx.*、boat.cpp/Boat.h、Heli.*、Planes.*、Submarine.*、Trailer.*、train.*、AmphibiousAutomobile.*、DraftVehicle.*各具体车辆类
game/Vehicles/door.h、door.cppCCarDoor、CBouncingPanel
game/Vehicles/VehicleGadgets.h、VehicleGadgets.cppCVehicleGadget 族、炮塔/武器/CVehicleWeaponMgr
game/Vehicles/componentReserve.*座位/门组件预留(ped 进出车协调)
game/Vehicles/vehiclepopulation.*、VehiclePopulationJob.cpp、VehPopUpdateDensities*.cpp、vehiclepopulation_shared.cpp车辆人口:生成链接、异步作业、生成/回收、复用池
game/Vehicles/cargen.*、cargens.psc车辆生成点(CTheCarGenerators)
game/Vehicles/Metadata/*vehiclelayouts 元数据(布局、座位、入口点、驾驶射击、爆炸信息等)与 AI 操控曲线
game/modelinfo/VehicleModelInfo*.h/.cpp/.psc、ModelSeatInfo.*车辆模型信息、颜色/改装/车牌/警笛/灯光、座位与入口点运行时表、CSeatManager
game/vehicleAi/VehicleAILod*.*、vehicleAi/task/DeferredTasks.*车辆 AI/物理 LOD 与延迟(多线程)任务
game/core/game.cpp、game/scene/world/GameWorld.cpp、game/scene/scene.cpp、game/physics/physics.cpp注册点与帧内调用顺序

1. 组件地图#

概念代码实体职责证据
车辆实体CVehicle : CPhysical所有车辆的公共状态与虚接口;构造函数 protected,只允许 CVehicleFactory 创建src/dev_ng/game/Vehicles/vehicle.h:401-411
类型标签VehicleType决定具体类、音频实体、玩家驾驶任务;枚举顺序被用来做区间判断src/dev_ng/game/modelinfo/VehicleModelInfo.h:169-199
工厂CVehicleFactory池初始化、Create/Destroy、拖车与货物、gadget 装配src/dev_ng/game/Vehicles/VehicleFactory.h:27-71
模型信息CVehicleModelInfo每个车型的静态数据(操控 ID、布局、改装套件、LOD、标志…)src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:196-353
操控数据CHandlingData + 子 handling物理/操控参数,按名字由模型引用src/dev_ng/game/Vehicles/Vehicle.cpp:4015-4017
座位/入口CModelSeatInfo、CEntryExitPoint、CSeatManager布局 → 骨骼索引映射;运行时乘员表src/dev_ng/game/modelinfo/ModelSeatInfo.h:157-346
门CCarDoor铰链/滑动门的驱动、闩锁、断裂、导航交互src/dev_ng/game/Vehicles/door.h:54-96
轮子CWheel(池化)悬挂、轮胎力、接触;数组指针在子类中src/dev_ng/game/Vehicles/Automobile.h:377
变速箱CTransmission档位、引擎扭矩、引擎健康src/dev_ng/game/Vehicles/vehicle.h:2580-2584
损坏CVehicleDamage / CVehicleDeformation各部位健康、形变纹理、爆炸src/dev_ng/game/Vehicles/vehicle.h:2580
AICVehicleIntelligence + CVehicleTaskManager车辆自身的任务树(与 ped 任务树独立)src/dev_ng/game/Vehicles/vehicle.h:2850-2852
LODCVehicleAILodAL_LodDummy/AL_LodSuperDummy/AL_LodTimeslicing 标志src/dev_ng/game/vehicleAi/VehicleAILod.h:31-71
gadget/武器CVehicleGadget、CVehicleWeaponMgr拖钩、叉车、挖掘臂、炮塔、探照灯…src/dev_ng/game/Vehicles/vehicle.h:2869-2870
人口CVehiclePopulation环境车辆生成/移除、复用池、警车/急救车生成src/dev_ng/game/Vehicles/vehiclepopulation.h:68

2. 类层次与 VehicleType#

2.1 枚举即类层次#

VehicleType 的排列刻意与继承关系对齐:VEHICLE_TYPE_CAR…VEHICLE_TYPE_AUTOGYRO 全部派生自 CAutomobile(含飞机、拖车、四轮摩托、两栖车、潜水车,以及经 CRotaryWingAircraft 派生的直升机/飞艇/旋翼机),BIKE/BICYCLE 派生自 CBike,BOAT/TRAIN/SUBMARINE 直接派生自 CVehicle src/dev_ng/game/modelinfo/VehicleModelInfo.h:169-199。CVehicle 的所有 InheritsFromXxx() 都是对 m_vehicleType 的区间或等值比较,注释提醒“飞机也继承自 CAutomobile” src/dev_ng/game/Vehicles/vehicle.h:543-576。因此改动该枚举顺序会悄然破坏全部类型判断——枚举头部注释也明确要求检查 CVehicle 的类型函数 src/dev_ng/game/modelinfo/VehicleModelInfo.h:171。

证据:CVehicle : CPhysical src/dev_ng/game/Vehicles/vehicle.h:401;CAutomobile/CQuadBike src/dev_ng/game/Vehicles/Automobile.h:38、src/dev_ng/game/Vehicles/Automobile.h:499;CBike src/dev_ng/game/Vehicles/Bike.h:38、CBmx src/dev_ng/game/Vehicles/Bmx.h:25;CBoat src/dev_ng/game/Vehicles/Boat.h:174;CRotaryWingAircraft/CHeli/CAutogyro/CBlimp src/dev_ng/game/Vehicles/Heli.h:72、src/dev_ng/game/Vehicles/Heli.h:391、src/dev_ng/game/Vehicles/Heli.h:643、src/dev_ng/game/Vehicles/Heli.h:681;CPlane src/dev_ng/game/Vehicles/Planes.h:296;CSubmarine/CSubmarineCar src/dev_ng/game/Vehicles/Submarine.h:166、src/dev_ng/game/Vehicles/Submarine.h:220;CTrailer src/dev_ng/game/Vehicles/Trailer.h:48;CTrain src/dev_ng/game/Vehicles/train.h:193;CAmphibiousAutomobile/CAmphibiousQuadBike src/dev_ng/game/Vehicles/AmphibiousAutomobile.h:14、src/dev_ng/game/Vehicles/AmphibiousAutomobile.h:103;CDraftVeh src/dev_ng/game/Vehicles/DraftVehicle.h:25。

说明:源码中没有 CBicycle 类——VEHICLE_TYPE_BICYCLE 由 CBmx 实现 src/dev_ng/game/Vehicles/VehicleFactory.cpp:2816-2818;CDraftVeh 只有在 ENABLE_DRAFT_VEHICLE 打开时才会被工厂创建 src/dev_ng/game/Vehicles/VehicleFactory.cpp:2840-2844。

2.2 各具体类要点#

类关键特征(摘要)证据
CAutomobile4 轮+通用路面车辆;持有 WheelIntegrationState m_WheelIntegrator、门数组 m_aCarDoors[NUM_VEH_DOORS_MAX]、轮子指针数组 m_pCarWheels[NUM_VEH_CWHEELS_MAX];三段式 ProcessPhysics/2/3src/dev_ng/game/Vehicles/Automobile.h:251、src/dev_ng/game/Vehicles/Automobile.h:373-377、src/dev_ng/game/Vehicles/Automobile.cpp:3187
CBike / CBmx自带一扇“门”与独立轮子数组、独立积分器状态src/dev_ng/game/Vehicles/Bike.h:173、src/dev_ng/game/Vehicles/Bike.h:274-278
CBoat通过组合 CBoatHandling m_BoatHandling 实现水上逻辑(两栖车复用同一组件)src/dev_ng/game/Vehicles/Boat.h:259、src/dev_ng/game/Vehicles/AmphibiousAutomobile.h:89
CSubmarine / CSubmarineCar物理、控制、预渲染全部转发给组合的 CSubmarineHandlingsrc/dev_ng/game/Vehicles/Submarine.h:174-211
CRotaryWingAircraft 族旋翼速度/健康、飞行模型;CBlimp 派生自 CHelisrc/dev_ng/game/Vehicles/Heli.cpp:2051-2073
CPlane普通/垂直起降双飞行模型按比例混合、CAircraftDamagesrc/dev_ng/game/Vehicles/Planes.cpp:2555-2597
CTrain沿 CTrainTrack 节点运动,车站状态机 TrainStatesrc/dev_ng/game/Vehicles/train.h:198-207
CTrailerCTrailerLegs gadget、挂接约束src/dev_ng/game/Vehicles/Trailer.h:11、src/dev_ng/game/Vehicles/Trailer.h:48

物理与操控差异详见 vehicle-physics-handling-damage.md。

3. CVehicle 的组成#

CVehicle 以值成员持有 CVehicleDamage m_VehicleDamage、CTransmission m_Transmission、CHandlingData* pHandling(指向共享的只读操控数据)、CVehicleFlags m_nVehicleFlags,以及音频实体指针、主物理实例 fragInstGta* m_pVehicleFragInst 与可选的 dummy 实例 phInstGta* m_pDummyInst src/dev_ng/game/Vehicles/vehicle.h:2580-2595。AI、LOD、轮/门数组、武器管理器与 gadget 列表、座位管理器、组件预留管理器在类尾部 src/dev_ng/game/Vehicles/vehicle.h:2850-2878。

成员说明证据
m_vehControls(CVehControls)转向/副转向/油门/刹车/手刹/氮气/KERS 输入;默认手刹为 truesrc/dev_ng/game/Vehicles/vehicle.h:97-130
m_ppWheels / m_nNumWheels / m_WheelIndexById指向子类轮子数组;NUM_VEH_CWHEELS_MAX = 10src/dev_ng/game/Vehicles/vehicle.h:2856-2859、src/dev_ng/game/Vehicles/VehicleDefines.h:19
m_pDoors / m_nNumDoors指向子类门数组;NUM_VEH_DOORS_MAX = 9src/dev_ng/game/Vehicles/vehicle.h:2861-2864、src/dev_ng/game/Vehicles/VehicleDefines.h:20
m_pIntelligence / m_vehicleAiLod车辆 AI 与 LOD 状态src/dev_ng/game/Vehicles/vehicle.h:2851-2852
m_SeatManager / m_ComponentReservationMgr乘员表与座位/门预留src/dev_ng/game/Vehicles/vehicle.h:2876-2878
m_fTimeSinceLastAiUpdate时间片 LOD 下累积的 AI 步长src/dev_ng/game/Vehicles/vehicle.h:2586-2589

IsDummy()/IsSuperDummy() 直接读取 LOD 标志 src/dev_ng/game/Vehicles/vehicle.h:992-993;dummy 相关虚函数(TryToMakeIntoDummy、SwitchToDummyPhysics 等)在基类声明 src/dev_ng/game/Vehicles/vehicle.h:996-1029,机制见物理子页第 8 节。

4. 内存与池#

资源容量 / 规则证据
CVehicle 池VEHICLE_POOL_SIZE 不再是常量 200,而是从 gameconfig.xml 的 "Vehicles" 池读取(CPoolHelpers::SetVehiclePoolSize),未设置即 TrapZsrc/dev_ng/game/Vehicles/VehicleDefines.h:11-17、src/dev_ng/game/Vehicles/Vehicle.cpp:32152-32174、src/dev_ng/game/system/system.cpp:966
CVehicle 分配方式REGISTER_POOL_ALLOCATOR + 带堆的池:堆大小 VEHICLE_HEAP_SIZE 在 360/PS3 为 464KB,其它平台 ×10;子类大小不同,所以是“变长池”src/dev_ng/game/Vehicles/vehicle.h:426、src/dev_ng/game/Vehicles/VehicleFactory.cpp:1443-1453
音频实体池同样按 VEHICLE_POOL_SIZE 个、488KB(×10)堆src/dev_ng/game/Vehicles/VehicleFactory.cpp:1461-1467
CWheel 池WHEEL_POOL_SIZE = VEHICLE_POOL_SIZE * 5,spillover 0.33src/dev_ng/game/Vehicles/VehicleDefines.h:28、src/dev_ng/game/Vehicles/wheel.cpp:208
CVehicleIntelligence 池VEHICLE_POOL_SIZE 个、元素大小取 sizeof(CHeliIntelligence)src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:81
座位 / 入口点MAX_VEHICLE_SEATS = 16、MAX_ENTRY_EXIT_POINTS = 16src/dev_ng/game/Vehicles/VehicleDefines.h:22-24
武器 / 炮塔主武器 6、炮台电池 38、炮塔 3 槽 × 4 = 12src/dev_ng/game/Vehicles/VehicleDefines.h:69-73
新车健康CREATED_VEHICLE_HEALTH = 1000;起火健康 250;残骸 60 s 后移除src/dev_ng/game/Vehicles/VehicleDefines.h:38-40
空间索引CVehicle::InitSystem 用池大小分配 CSpatialArray 存储,并初始化 AI LOD 优先级数组src/dev_ng/game/Vehicles/Vehicle.cpp:1105-1123

池满时(__BANK)工厂会在 MP 下打印全池清单并断言“请提高 gameconfig.xml 的 PoolSize” src/dev_ng/game/Vehicles/VehicleFactory.cpp:2777-2802。

5. 创建与销毁:CVehicleFactory#

工厂单例在 CGame::CreateFactories/DestroyFactories 中与 ped 工厂、CVehicleIntelligenceFactory 一起创建/销毁 src/dev_ng/game/core/game.cpp:588-605;车辆录像与路网的流式模块也在同一文件的流式模块注册函数中登记 src/dev_ng/game/core/game.cpp:578-581。

5.1 Create 流程#

CVehicleFactory::Create(modelId, ownedBy, popType, pMat, bClone, bCreateAsInactive) 的顺序 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1564-1769:

  1. 校验模型信息存在且为 MI_TYPE_VEHICLE;若 fragment 缓存无法再分配条目(FRAGCACHEMGR->CanGetNewCacheEntries(1) 失败)直接返回 NULL src/dev_ng/game/Vehicles/VehicleFactory.cpp:1568-1590。
  2. 原本的“销毁车辆缓存”复用路径被 #if 0 关闭 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1592-1596,于是总是走 CreateVehicle(type);计数 CVehiclePopulation::IncrementNumVehiclesCreatedThisCycle()(这会占用本人口周期的生成额度,见第 10 节) src/dev_ng/game/Vehicles/VehicleFactory.cpp:1598-1613。
  3. 先设置矩阵、再设置 bCreatingAsInactive,最后 SetModelId(modelId)——注释强调必须在矩阵之后调用以便正确初始化物理 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1615-1635。
  4. 船拖车计数(FLAG_SPAWN_BOAT_ON_TRAILER),上限常量为“无船拖车 1 / 有船拖车 2” src/dev_ng/game/Vehicles/VehicleFactory.cpp:1645-1659、src/dev_ng/game/Vehicles/VehicleFactory.h:130-133。
  5. 网络注册必须在任何其他状态改变之前:bClone && NetworkInterface::IsGameInProgress() 时调用 RegisterVehicleToNetwork,失败则立即 Destroy 返回 NULL src/dev_ng/game/Vehicles/VehicleFactory.cpp:1668-1685。
  6. AssignVehicleGadgets(5.4);按 PopZone 的脏度范围与颜色、天气修正设置车身脏度,XMAS 天气在联机/回放时把脏色设为雪白 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1689-1724。
  7. 插入 CVehicle::GetSpatialArray(),记录初始生成位置,更新车身颜色重映射 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1726-1736。

注意:Create 不会把车辆加入世界;调用方(人口、脚本、cargen)随后自行 CGameWorld::Add,例如环境车生成路径 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5805-5808。

5.2 CreateVehicle:类型分派与音频实体#

CreateVehicle 用 switch(nVehicleType) rage_new 出具体类,然后按类型挂接音频实体:直升机/旋翼机/飞艇 → audHeliAudioEntity,火车 → audTrainAudioEntity,飞机 → audPlaneAudioEntity,船/潜艇 → audBoatAudioEntity,汽车类 → audCarAudioEntity,自行车 → audBicycleAudioEntity,拖车 → audTrailerAudioEntity,未知类型回退到基类并告警 src/dev_ng/game/Vehicles/VehicleFactory.cpp:2805-2912。导出导航网格碰撞(NAVMESH_EXPORT)时跳过音频初始化 src/dev_ng/game/Vehicles/VehicleFactory.cpp:2862-2866。

5.3 SetModelId → InitPhys → 组件初始化#

CVehicle::SetModelId 是车辆真正“成形”的地方 src/dev_ng/game/Vehicles/Vehicle.cpp:3996-4224:

顺序动作证据
1CEntity::SetModelId;按 popType 增加模型引用(停放车单独计数)src/dev_ng/game/Vehicles/Vehicle.cpp:4008-4013
2pHandling = CHandlingDataMgr::GetHandlingData(modelInfo->GetHandlingId());初始化阻力系数与 m_Transmission.SetupTransmission(...)(及可选第二变速箱)src/dev_ng/game/Vehicles/Vehicle.cpp:4015-4029
3由 handling mFlags 推导 van/big/bus/low、不爆胎/不断轮、MF_INDESTRUCTIBLE(全部免伤标志)以及 ABS 标准/可选(50% 随机)src/dev_ng/game/Vehicles/Vehicle.cpp:4035-4068
4模型标志 FLAG_DISABLE_DEFORMATION 关闭可见损坏;坦克默认免疫火焰src/dev_ng/game/Vehicles/Vehicle.cpp:4076-4087
5随机初始脏度;补建动态组件;InitPhys()src/dev_ng/game/Vehicles/Vehicle.cpp:4092-4100
6m_SeatManager.Init(numSeats, driverSeat);CreateDrawable、骨架与动画导演src/dev_ng/game/Vehicles/Vehicle.cpp:4108-4127
7组件预留、损坏、灯光开关初始化;警车/执法车辆/警笛标志src/dev_ng/game/Vehicles/Vehicle.cpp:4131-4152
8InitWheels();(frag 已缓存时)InitDoors()、InitCompositeBound()src/dev_ng/game/Vehicles/Vehicle.cpp:4154-4160
9坦克或带炮塔标志的车型在生成时就创建 CVehicleWeaponMgrsrc/dev_ng/game/Vehicles/Vehicle.cpp:4162-4169
10HD 资源状态、请求动态对象导航网格、AddVehicleInstance;低底盘车型默认装上液压改装src/dev_ng/game/Vehicles/Vehicle.cpp:4180-4216

CVehicle::InitPhys src/dev_ng/game/Vehicles/Vehicle.cpp:4940-5070:

  • ENABLE_FRAG_OPTIMIZATION 下,无环境布料的汽车/拖车在插入时不分配 fragment 缓存条目(bDisableCacheOnInsertion),之后按需 GiveFragCacheEntry src/dev_ng/game/Vehicles/Vehicle.cpp:4952-4956、src/dev_ng/game/Vehicles/Vehicle.cpp:1768-1778。
  • 用 fragInstGta(PH_INST_FRAG_VEH, ...) 建主实例,设高优先级、手动骨架更新,插入物理层;除非“以非激活状态创建”否则立刻 PHSIM->ActivateObject src/dev_ng/game/Vehicles/Vehicle.cpp:4958-4978。
  • 若 frag 含 VEH_CHASSIS_DUMMY 组则标记 bHasDummyBound;否则 CAutomobile::InitDummyInst 另建一个 GTA_BOX_VEHICLE_TYPE 的 phInstGta 作为 dummy 实例 src/dev_ng/game/Vehicles/Vehicle.cpp:4995-5004、src/dev_ng/game/Vehicles/Automobile.cpp:4946-4966。

AI 部分由 CVehicle::InitAi 完成:经 CVehicleIntelligenceFactory 创建 CVehicleIntelligence(直升机 → CHeliIntelligence,飞机 → CPlaneIntelligence),并总是压入一个 CTaskVehicleNoDriver(NO_DRIVER_TYPE_INITIALLY_CREATED) 到主任务树 src/dev_ng/game/Vehicles/Vehicle.cpp:29508-29517、src/dev_ng/game/vehicleAi/VehicleIntelligenceFactory.cpp:20-32。

5.4 AssignVehicleGadgets:按骨骼/标志装配#

gadget 不是数据表驱动,而是工厂按 handling 标志与骨骼存在与否硬编码装配 src/dev_ng/game/Vehicles/VehicleFactory.cpp:3030-3252:

条件gadget证据
MF_HAS_TRACKSCVehicleTrackssrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3039-3044
HF_ENABLE_LEANCVehicleLeanHelpersrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3045-3049
FLAG_PARKING_SENSORSCVehicleGadgetParkingSensor(半径 0.4)src/dev_ng/game/Vehicles/VehicleFactory.cpp:3051-3056
骨骼 VEH_ATTACHCVehicleTrailerAttachPoint,并禁止成为停放 superdummysrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3058-3065
VEH_DIGGER_ARMCVehicleGadgetDiggerArm(找到后直接 return)src/dev_ng/game/Vehicles/VehicleFactory.cpp:3067-3082
拖车 + VEH_MISC_ECVehicleGadgetBoatBoomsrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3084-3099
VEH_TOW_ARMCVehicleGadgetTowArmsrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3102-3119
VEH_FORKS+VEH_CARRIAGE / VEH_HANDLER_FRAME_1/2叉车 / Handler 吊架src/dev_ng/game/Vehicles/VehicleFactory.cpp:3121-3147
VEH_DOOR_HATCH_R/LCVehicleGadgetBombBaysrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3149-3160
收割机骨骼 / 关节挖掘臂 / EOD 臂对应 gadgetsrc/dev_ng/game/Vehicles/VehicleFactory.cpp:3162-3219
扰流板骨骼或下压力修正 >1CVehicleGadgetDynamicSpoiler;VEH_FLAP_L/R → 动态襟翼src/dev_ng/game/Vehicles/VehicleFactory.cpp:3236-3250

多数分支在 ENABLE_FRAG_OPTIMIZATION 下强制 GiveFragCacheEntry(true),因为关节 gadget 需要 articulated body。

5.5 Destroy、销毁缓存与复用池#

CVehicleFactory::Destroy src/dev_ng/game/Vehicles/VehicleFactory.cpp:2679-2772:计入本周期销毁数 → 若在销毁缓存中只清引用 → 网络克隆不允许销毁(断言并返回),否则 NetworkInterface::UnregisterObject → 船拖车计数 → DestroyChildrenVehicles → 从空间数组移除 → 回放通知 → CGameWorld::Remove → CTheScripts::UnregisterEntity → delete。

两套“避免重复创建”的机制状态不同:

  • 工厂销毁缓存(ms_reuseDestroyedVehs,MAX_DESTROYED_VEHS_CACHED = 50):仍保留数据结构与每帧 ProcessDestroyedVehsCache 注册,但 Create 的取用与 Destroy 的放入都被 #if 0 关闭 src/dev_ng/game/Vehicles/VehicleFactory.h:113-126、src/dev_ng/game/Vehicles/VehicleFactory.cpp:1593-1596、src/dev_ng/game/Vehicles/VehicleFactory.cpp:2767-2771、src/dev_ng/game/core/game.cpp:2854。这表明它是遗留路径(推断:缺少关闭原因的注释)。
  • 人口复用池(VEHICLE_REUSE_POOL_SIZE = 15)是实际生效的机制:被移除的环境车若 CanVehicleBeReused 则冻结、移出寻路服务器并标记 SetIsInReusePool(true),之后同型号生成时 FindVehicleToReuse/ReuseVehicleFromVehicleReusePool 取回;超时、模型被丢弃或 MP 禁用时真正移除 src/dev_ng/game/Vehicles/vehiclepopulation.h:1386-1387、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:9065-9075、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:9876-9930、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:10297-10345、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5039、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5630。复用池内的车辆不做 AI 与 LOD 更新 src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:204-208、src/dev_ng/game/Vehicles/Vehicle.cpp:29540-29544。

6. 模型信息与数据驱动元数据#

6.1 CVehicleModelInfo 的车辆字段(vehicles.meta)#

CVehicleModelInfo::InitData(VehicleModelInfoData.psc)是 vehicles.meta 每个条目的结构。车辆领域最重要的字段:

字段含义证据
m_modelName、m_txdName、m_handlingId、m_gameName模型/贴图、操控名(字符串→CHandlingDataMgr 索引)src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:196-200
m_layout(默认 LAYOUT_STANDARD)、m_POVTuningInfo、m_coverBoundOffsets、m_explosionInfo、m_scenarioLayout指向 vehiclelayouts 中的命名对象src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:211-215
m_cameraName/m_aimCameraName/m_bonnetCameraName/m_povCameraName相机元数据名(相机系统见 21 章)src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:216-220
m_AllowPretendOccupants/m_AllowJoyriding/m_AllowSundayDriving人口与 AI 行为开关src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:249-251
m_lodDistances[VLT_MAX]、m_HDTextureDist渲染 LOD 距离src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:266-267
m_damageMapScale、m_damageOffsetScale、m_defaultBodyHealth形变与车身健康src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:261-262、src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:273
m_frequency、m_swankness、m_maxNum、m_flags、m_type、m_vehicleClass、m_wheelType、m_plateType人口频率/档次、全局上限、标志位集、VehicleType、类别、轮毂类型、车牌类型src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:281-296
m_trailers、m_drivers、m_extraIncludes、m_requiredExtras可挂拖车、默认司机、extra 关联src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:298-324
m_buoyancySphereOffset/m_buoyancySphereSizeScale浮力球(见 09-physics)src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:332-333
m_numSeatsOverride覆盖布局座位数src/dev_ng/game/modelinfo/VehicleModelInfoData.psc:349

三个 DLC 可挂载的数据文件类型在 CVehicleModelInfo::InitClass(INIT_AFTER_MAP_LOADED) 注册挂载接口:VEHICLE_METADATA_FILE(vehicles.meta,加载后还会调用 CTrain::TrainConfigsPostLoad 重绑车厢模型)、VEHICLE_VARIATION_FILE(carvariations,AppendVehicleVariations)、CARCOLS_FILE(AppendVehicleColors)src/dev_ng/game/modelinfo/VehicleModelInfo.cpp:176-230、src/dev_ng/game/modelinfo/VehicleModelInfo.cpp:255-262。人口上限与 140 辆基线的比值还会放大各车型的 maxNum 乘数 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:821-825。

6.2 carcols、改装套件与 CVehicleVariationInstance#

全局颜色/改装表 CVehicleModelInfoVarGlobal 以 PSO store 方式从 platform:/data/carcols.<meta> 加载,并注册为 REST 单例 Vehicles/carcols 以便网页工具浏览 src/dev_ng/game/modelinfo/VehicleModelInfo.cpp:541-551。其结构包括车牌、颜色、金属漆、车窗颜色、灯光设置、警笛设置、改装套件 m_Kits、按 VWT_MAX 分类的轮毂、全局变体数据与氙灯颜色 src/dev_ng/game/modelinfo/VehicleModelInfoColors.psc:785-815。

  • 改装套件 CVehicleKit:名字(需与 dwd/txd 同名)、ID、类型,可见改装 m_visibleMods、仅能被链接带出的 m_linkMods、属性改装 m_statMods、槽位名覆盖与涂装名 src/dev_ng/game/modelinfo/VehicleModelInfoColors.psc:670-692。
  • 改装槽位 eVehicleModType 分三段:可渲染(VMT_SPOILER…VMT_LIGHTBAR)、属性(VMT_ENGINE/BRAKES/GEARBOX/HORN/SUSPENSION/ARMOUR)、开关(VMT_NITROUS/TURBO/SUBWOOFER/TYRE_SMOKE/HYDRAULICS/XENON_LIGHTS),最后是轮子等杂项 src/dev_ng/game/modelinfo/VehicleModelInfoEnums.h:30-114。
  • 实例侧:变体实例存放在车辆的绘制处理器中(GetVehicleDrawHandler().GetVariationInstance()),IsModded() 即改装数 > 0 src/dev_ng/game/Vehicles/vehicle.h:460-463;SetModIndex 触发改装模型流送,流送请求在“Ped and Vehicle assets”更新组中统一处理 src/dev_ng/game/modelinfo/VehicleModelInfoVariation.cpp:645、src/dev_ng/game/core/game.cpp:2769-2775。
  • 改装对操控的影响:例如“扩展改装”车型用 CCarHandlingData::m_AdvancedData(槽位/索引/值)覆盖涡轮功率,RSG_GEN9 下非扩展车型另有分支 src/dev_ng/game/Vehicles/Transmission.cpp:143-176。

6.3 vehiclelayouts:CVehicleMetadataMgr#

CVehicleMetadataMgr 是一个包含 20 类命名对象数组的单例:动画速率集、clip set 映射、掩体边界、自行车信息、POV 调校、入口动画变体、额外点、驾驶射击武器组/动画/信息、座位信息与座位动画、入口点信息与入口点动画、爆炸信息、布局信息、场景布局、座位覆盖、车内覆盖、第一人称驾驶射击环视数据 src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.psc:4-66。

  • 基础文件 commoncrc:/data/ai/vehiclelayouts.meta 在 Init 时 PARSER.LoadObject 载入;加载后修复座位“换座链接”指针并做数据校验,同时注册 REST 单例 Vehicles/Layouts src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.cpp:34-35、src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.cpp:1284-1300。
  • DLC 的 VEHICLE_LAYOUTS_FILE 通过挂载接口(eDFMI_UnloadLast)调用 AppendExtra/RemoveExtra:解析到临时实例后逐数组追加或按名移除 src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.cpp:1088-1095、src/dev_ng/game/Vehicles/Metadata/VehicleMetadataManager.cpp:1312-1390。
  • 布局中的座位/入口点以 external_named 指针引用座位信息与动画信息(按名字解析)src/dev_ng/game/Vehicles/Metadata/VehicleLayoutInfo.psc:39-47;布局标志(如 NoDriver、StreamAnims、WarpIntoAndOut、MustCloseDoor…)src/dev_ng/game/Vehicles/Metadata/VehicleLayoutInfo.psc:4-37。这些数据主要服务于 ped 进出车/驾驶射击动画(07-ai-tasks 负责)。

6.4 座位、入口点与预留#

  • CModelSeatInfo::InitFromLayoutInfo(layout, skelData, numSeatsOverride) 把布局中的座位/入口点映射到本车型实际存在的骨骼(“非 1:1,以支持缺失的座位/门”),存 m_iLayoutSeatIndicies/m_iSeatBoneIndicies 与 CEntryExitPoint m_aEntryExitPoints[MAX_ENTRY_EXIT_POINTS] src/dev_ng/game/modelinfo/ModelSeatInfo.h:193-288。
  • CEntryExitPoint:一个入口有一个直接可达座位和经换座的间接座位,保存门骨骼与门把手骨骼 src/dev_ng/game/modelinfo/ModelSeatInfo.h:150-187;入口评估函数 EvaluateSeatAccessFromAllEntryPoints 等为 ped 进车任务服务 src/dev_ng/game/modelinfo/ModelSeatInfo.h:238-248。
  • 注意命名:运行时乘员表类名是 CSeatManager(不是 CVehicleSeatManager)。它保存 m_pSeatOccupiers[MAX_VEHICLE_SEATS]、上一乘员、玩家数与“已排程但尚未创建的乘员”计数(7 位)src/dev_ng/game/modelinfo/ModelSeatInfo.h:290-346;GetDriver() 用无符号比较消除分支 src/dev_ng/game/modelinfo/ModelSeatInfo.h:352-360。
  • CComponentReservationManager 为每个座位与入口点(MAX_VEHICLE_SEATS + MAX_ENTRY_EXIT_POINTS)维护一个 CComponentReservation,让多个 ped 不会同时使用同一扇门/座位 src/dev_ng/game/Vehicles/componentReserve.h:20-55。

7. 门、窗与部件:CCarDoor#

CCarDoor 用位标志描述轴(旋转 X/Y/Z 或滑动)与驱动模式:DRIVEN_SHUT/AUTORESET/NORESET/GAS_STRUT/SWINGING/SMOOTH/SPECIAL(后门仅在被炸开或座位劫持时打开),以及闩锁、断裂、articulated、DRIVEN_BY_PHYSICS(车辆关节由动画驱动时仍由物理驱动)等 src/dev_ng/game/Vehicles/door.h:54-96。主要 API:SetTargetDoorOpenRatio、SetSwingingFree、SetShutAndLatched、BreakOff/BreakOffNextUpdate、GetIsIntact src/dev_ng/game/Vehicles/door.h:140-197。

  • 门的物理在 CAutomobile::ProcessPhysics 里逐门调用 CCarDoor::ProcessPhysics:articulated collider 时全部处理,否则只处理带驱动/强制唤醒标志或待断裂的门 src/dev_ng/game/Vehicles/Automobile.cpp:3454-3470。
  • 门开合比例变化会置 bDoorRatioHasChanged,在延迟任务完成阶段 UpdateDoorsForNavigation 把打开的门作为动态障碍加入/更新/移出寻路服务器 src/dev_ng/game/Vehicles/Vehicle.cpp:25241-25246、src/dev_ng/game/Vehicles/Vehicle.cpp:25054-25080。
  • 窗户状态 m_bWindowsRolledDown[] 在 InitDoors 中全部摇上 src/dev_ng/game/Vehicles/Vehicle.cpp:4784-4790;车窗玻璃破碎属于 12-vfx 的 vehicleglass。
  • CBouncingPanel(最多 3 个)由 CVehicleDamage 持有,模拟被撞松的保险杠/面板 src/dev_ng/game/Vehicles/vehicleDamage.h:650、src/dev_ng/game/Vehicles/vehicleDamage.h:757-758。

8. Gadget 与车辆武器#

CVehicleGadget 是一个带多个处理钩子的多态组件:ProcessPrePhysics、ProcessPhysics/2/3、ProcessPreRender、ProcessControl、ProcessPreComputeImpacts、WantsToBeAwake、ChangeLod、BlowUpCarParts,可声明为网络同步并 Serialise src/dev_ng/game/Vehicles/VehicleGadgets.h:178-268。类型枚举前半段(叉车、探照灯、吊绳、挖掘臂、Handler 吊架、电磁铁、弹仓)是网络同步类型,VGT_NUM_NETWORKED_TYPES 之后为本地类型 src/dev_ng/game/Vehicles/VehicleGadgets.h:59-86。

  • 车辆在各阶段遍历 m_pVehicleGadgets:ProcessPrePhysics src/dev_ng/game/Vehicles/Vehicle.cpp:1788-1791、DoProcessControl_OnDeferredTaskCompletion 中 ProcessControl src/dev_ng/game/Vehicles/Vehicle.cpp:25381-25389、ProcessPhysics2/ProcessPhysics3(吊钩/电磁铁需要第三遍以免与轮子积分任务冲突)src/dev_ng/game/Vehicles/Automobile.cpp:4850-4858、src/dev_ng/game/Vehicles/Automobile.cpp:4927-4930。
  • CVehicleWeaponMgr:最多 6 个 CVehicleWeapon 与 12 个 CTurret,各自绑定座位索引;Fire、AimTurretsAtWorldPos 等 src/dev_ng/game/Vehicles/VehicleGadgets.h:859-933。CreateVehicleWeaponMgr 仅当 handling 带 CVehicleWeaponHandlingData 时创建,并把骨骼 1A–1D 组装成同时开火的武器电池 src/dev_ng/game/Vehicles/VehicleGadgets.cpp:4900-4935。武器本身(CWeapon/CWeaponInfo)归 ../21-weapons-camera/weapons.md。
  • 武器处理入口:DoProcessControl 第一步 ProcessWeapons() src/dev_ng/game/Vehicles/Vehicle.cpp:25102。

9. 车辆 AI 的挂接点(概述)#

车辆拥有独立于 ped 的任务管理器 CVehicleTaskManager(主树 + 副树)src/dev_ng/game/task/System/TaskManager.h:76-92;任务树/优先级枚举为 VEHICLE_TASK_TREE_PRIMARY/SECONDARY 与 VEHICLE_TASK_PRIORITY_CRASH/PRIMARY、VEHICLE_TASK_SECONDARY_ANIM src/dev_ng/game/Vehicles/VehicleDefines.h:259-279。玩家成为司机时 SetPlayerDriveTask 按 VehicleType 选择 CTaskVehiclePlayerDrive*(拖车没有玩家驾驶任务,飞艇复用直升机任务),并禁止玩家车进入时间片 LOD src/dev_ng/game/Vehicles/Vehicle.cpp:29664-29726。路径、任务族与避障详见 vehicle-ai-and-road-network.md。

10. 车辆人口:CVehiclePopulation#

10.1 每帧 Process#

CVehiclePopulation::Process 在 gameSkeleton 的“Vehicles”人口更新组中注册,紧随其后的是 CVehicleAILodManager::Update 与飞行器避让管理器 src/dev_ng/game/core/game.cpp:2789-2794。其主体 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1245-1645:

  1. 回放接管时直接返回;玩家未定位(CStreaming::IsPlayerPositioned)时返回 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1247-1260。
  2. 计算人口范围缩放;在暂停判断前调用 CVehicle::StartAiUpdate() 缓存全部车辆 AI 速度(使新生成车辆能在本帧做一次完整 AI 更新)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1273-1281。
  3. 更新事件/调度/指令管理器(CIncidentManager、CDispatchManager、COrderManager)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1292-1299。
  4. 等待上一帧启动的“更新密度”依赖完成(自旋 + sysIpcYield)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1303-1321。
  5. 荒街、禁用节点清理、车距系数;取人口控制点(与 ped 人口共用 CPedPopulation::GetPopulationControlPointInfo)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1334-1364。
  6. 复用池维护;移除多余空警车/残骸(MP 与 SP 两套)、空置执法车、联机拥堵与挤占玩家的空车 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1381-1404。
  7. 火车与直升机各自的生成/移除逻辑 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1412-1436。
  8. 人口周期:按 PopulationFrameRate × CyclesPerFrame 把时间折算为周期数;每个周期先 RemoveDistantVehs(仅当本周期无销毁),再在三个状态(随机车辆 → 路径上的特殊车辆 → 已排程的 cargen 车辆)间轮转直到有实体被创建,然后 CTheCarGenerators::Process;创建/销毁计数每周期递减 1,多出的“溢出”到下一周期,从而限制每个人口周期最多生成一个实体 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1418-1529。
  9. 扫描“玩家所在道路”的节点;更新钥匙孔(keyhole)生成形状、近裁剪距离,并启动异步收集生成链接作业 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1582-1598。

10.2 异步作业与生成链接#

生成依赖一个“生成链接”数组 ms_aGenerationLinks[MAX_GENERATION_LINKS](360/PS3 为 1600,其余 4096)src/dev_ng/game/Vehicles/vehiclepopulation.h:900、src/dev_ng/game/game_config.h:51。每个 CVehGenLink 是一对路网节点(m_nodeA/m_nodeB)加上类别、密度(初始/修正后)、车道数、尝试次数、附近车辆数(8:8 定点)、长度/坡度/朝向(定点)、得分与期望车辆差额 src/dev_ng/game/Vehicles/vehiclepopulation.h:402-446。

两个 sysDependency 作业在初始化时绑定回调 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:895-898:

作业启动等待内容
VehiclePopulationAsyncUpdate(收集链接)Process 末尾 StartAsyncUpdateJob,参数含钥匙孔半径、最大节点距离(创建距离 + 20m)、玩家车速、相机朝向等 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4505-4574CGameWorld::Process 在物理更新后调用 UpdateLinksAfterGather 自旋等待 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1198-1230、src/dev_ng/game/scene/world/GameWorld.cpp:2082GatherPotentialVehGenLinks 在路网中找出候选链接 src/dev_ng/game/Vehicles/VehiclePopulationJob.cpp:22-50
VehiclePopAsyncUpdateDensities(更新密度)UpdateCurrentVehGenLinks 末尾 StartAsyncUpdateDensitiesJob src/dev_ng/game/Vehicles/vehiclepopulation.cpp:3892-3919、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4490-4503下一帧 Process 开头 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1303-1321计算链接得分/期望密度(VehPopUpdateDensities_shared.cpp)

这表明一个链接从被收集到被用来生成车辆至少跨越一帧(推断,基于启动/等待点)。

10.3 生成:从链接到车辆#

TryToGenerateOneRandomVeh 的主要步骤(节选)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4820-5994:GenerateVehCreationPosFromLinks 选位置 → ChooseModel(考虑警察/通缉、高速、街道关联、越野、禁大车)→ 优先 FindVehicleToReuse → PlaceOnRoadProperly(自行车/汽车各自实现)→ 复用池取回或 CVehicleFactory::Create(..., POPTYPE_RANDOM_AMBIENT, ...) → 添加司机乘客(受实时 ped 名额限制)→ 可选拖车 → CGameWorld::Add → MakeVehicleIntoDummyBasedOnDistance src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4857、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5003、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5458-5470、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5630-5642、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5681、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5731、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5805、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:5898。

MakeVehicleIntoDummyBasedOnDistance 先调用 PostCreationAiUpdate(PreGameWorldAiUpdate → StartAiUpdate → ProcessIntelligence → aiDeferredTasks::RunAll → FinishAiUpdate,让新车立刻有 follow route),再按 CalcDesiredLodForPoint 转 superdummy/dummy src/dev_ng/game/Vehicles/vehiclepopulation.cpp:8652-8692、src/dev_ng/game/Vehicles/Vehicle.cpp:29519-29526。这正是 CAutomobile::DoProcessControl 检查 bHasProcessedAIThisFrame 避免同帧二次 AI 的原因 src/dev_ng/game/Vehicles/Automobile.cpp:1859-1866。

期望的环境车数量 = 上限 × 荒街/通缉(取小)× 室内 × 战斗 × 高速 × 内存预算乘数;MP 不使用荒街与战斗乘数 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4576-4632。

10.4 回收#

RemoveDistantVehs 每个周期只检查 ceil(环境车上限 / 6) 辆车(静态游标轮转全池),跳过集群中的车(由集群负责)与延迟移除计时未到的车;ShouldRemoveVehicle 给出理由后优先进入复用池,否则 RemoveVeh;不移除时重置或设置新的延迟移除时间 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:9016-9100。ShouldRemoveVehicleInternal 综合距离(cull range 屏内/屏外)、可见性、任务与 popType 等因素 src/dev_ng/game/Vehicles/vehiclepopulation.cpp:9108。

10.5 配置来源#

参数来源证据
人口帧率/每帧周期(SP/MP)、环境/停放/低优先停放密度、环境与停放上限、钥匙孔厚度与半径、最大创建距离(屏内/屏外)、cull range、基于密度的移除速率gameconfig 的 population 配置(GET_POPULATION_VALUE),多数可被命令行 PARAM 覆盖src/dev_ng/game/Vehicles/vehiclepopulation.cpp:786-861
MP 环境车上限、本地缓冲、停放车乘数等云端 Tunables(MP_VEHICLE_UPPER_LIMIT 等键)回落到 gameconfigsrc/dev_ng/game/Vehicles/vehiclepopulation.cpp:863-874
生成标记球 CVehGenMarkUpSpheres(最多 32 个)与 MP 密度乘数VehiclePopulationTuning.pscsrc/dev_ng/game/Vehicles/Metadata/VehiclePopulationTuning.psc:5-25

10.6 车辆生成点(cargen)与特殊车辆#

CTheCarGenerators 管理地图/脚本放置的生成点(脚本最多 80 个),排程队列最多 32 辆待生成车辆;Process 每周期只处理 ceil(池大小 / (人口帧率 × 每帧周期)) 个生成点,并优先处理 CargenPriorityAreas 区域内的生成点 src/dev_ng/game/Vehicles/cargen.h:25-29、src/dev_ng/game/Vehicles/cargen.cpp:2783-2880、src/dev_ng/game/Vehicles/cargens.psc:5-15。GenerateScheduledVehiclesIfReady 每次弹出一个排程,分阶段等待碰撞探测、放置到路面后才真正生成 src/dev_ng/game/Vehicles/cargen.cpp:2916-2925。警车/急救车/罪犯车由 GenerateOneEmergencyServicesCar、GenerateCopVehicleChasingCriminal 等函数提供给 Dispatch(见 20 章)src/dev_ng/game/Vehicles/vehiclepopulation.cpp:7404、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:7903。

11. 每帧处理顺序#

下表按一帧内的先后列出车辆相关调用(主线程视角):

顺序调用车辆侧效果证据
1CVehicleVariationInstance::ProcessStreamRequests处理改装流送请求src/dev_ng/game/core/game.cpp:2771
2CVehiclePopulation::ProcessStartAiUpdate 缓存速度、移除/生成、启动链接收集作业src/dev_ng/game/core/game.cpp:2791、src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1278-1281
3CVehicleAILodManager::Update分批(3 帧一轮)决定 real/dummy/superdummy 与时间片src/dev_ng/game/core/game.cpp:2792、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:388-862
4CScene::Update → CGameWorld::Process见下 5–10src/dev_ng/game/core/game.cpp:2826、src/dev_ng/game/scene/scene.cpp:809
5CVehicle::PreGameWorldAiUpdate()全量更新帧清除“本帧禁止 dummy/superdummy”等标志src/dev_ng/game/scene/world/GameWorld.cpp:1950、src/dev_ng/game/Vehicles/Vehicle.cpp:29832-29862
6CScenarioManager::GetVehicleScenarioManager().Update();fwSceneUpdate::Update(SU_UPDATE_VEHICLE)对每辆车调用 CVehicle::ProcessControlsrc/dev_ng/game/scene/world/GameWorld.cpp:1956-1960
7aiDeferredTasks::RunAll()并行执行避障/寻路点/AI 收尾/插值四类延迟任务,再在主线程收尾src/dev_ng/game/scene/world/GameWorld.cpp:1965-1966、src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:375-392
8CVehicle::FinishAiUpdate()断言缓存速度未被改变、更新“可驾驶/停放/静止”判定、清除每帧标志src/dev_ng/game/scene/world/GameWorld.cpp:1968、src/dev_ng/game/Vehicles/Vehicle.cpp:29864-29931
9CPhysics::Update()每个物理时间片 PreSimUpdate 调用 ProcessPhysics/2/3(轮子积分在工作线程)src/dev_ng/game/scene/world/GameWorld.cpp:2061、src/dev_ng/game/physics/physics.cpp:1374-1510
10CVehiclePopulation::UpdateLinksAfterGather();CVehicleRecordingMgr::RetrieveDataForThisFrame()(非物理同步模式)等待链接作业、启动密度作业;推进车辆录像回放src/dev_ng/game/scene/world/GameWorld.cpp:2082、src/dev_ng/game/scene/world/GameWorld.cpp:2096-2105
11CVehicleModelInfo::UpdateHDRequests、ThePaths.Update()HD 资源;路网已用节点更新src/dev_ng/game/scene/scene.cpp:813-826
12Game Logic 组:CGps::Update、CJunctions::Update、CTrafficLights::UpdateGPS、路口相位、交通灯亮度src/dev_ng/game/core/game.cpp:2835-2848
13CGameWorld::ProcessAfterAllMovement车辆附着、座椅碰撞边界、寻路服务器重试src/dev_ng/game/scene/world/GameWorld.cpp:2208-2240
14Render Update:CVehicle::PreVisUpdate(车内渲染模式)→ CGameWorld::ProcessAfterCameraUpdate(CVehicle::ProcessAfterCameraUpdate → 每车 ProcessPostCamera)→ UpdateLightsOnFlagsForAllVehicles → CVehicleDeformation::TexCacheUpdate渲染准备src/dev_ng/game/core/game.cpp:2909、src/dev_ng/game/core/game.cpp:2962、src/dev_ng/game/core/game.cpp:2999、src/dev_ng/game/core/game.cpp:3039、src/dev_ng/game/Vehicles/Vehicle.cpp:29948-29960
15渲染器:CVehicleLightAsyncMgr::SetupDataForAsyncJobs / KickJobForRemainingVehicles / ProcessResults车灯与 corona 异步计算src/dev_ng/game/renderer/Renderer.cpp:975、src/dev_ng/game/renderer/Renderer.cpp:993、src/dev_ng/game/renderer/Renderer.cpp:1031

11.1 单车的 ProcessControl 链#

证据:ProcessControl 计算全量更新与时间片步长并调用 DoProcessControl src/dev_ng/game/Vehicles/Vehicle.cpp:24578-24595;CAutomobile::DoProcessControl 的全量段、AI 段与损坏段 src/dev_ng/game/Vehicles/Automobile.cpp:1799-1866、src/dev_ng/game/Vehicles/Automobile.cpp:1868-2076,末尾调用基类 src/dev_ng/game/Vehicles/Automobile.cpp:2120(摩托与船同理 src/dev_ng/game/Vehicles/Bike.cpp:1011、src/dev_ng/game/Vehicles/boat.cpp:1195);CVehicleIntelligence::Process 排队收尾 src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1109-1125;CVehicle::DoProcessControl 排队插值 src/dev_ng/game/Vehicles/Vehicle.cpp:25086-25202;插值任务与主线程收尾 src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:328-371。

ProcessControl 自身在 DoProcessControl 之后还处理跳跃车、两栖四轮收轮、火箭推进、降落伞、滑翔翼、特殊飞行模式、外伸支腿与竞技场模式等“特殊能力”输入 src/dev_ng/game/Vehicles/Vehicle.cpp:24710-25037;其中“编队领队”拾取与调参是 __BANK 调试功能,但随后的跟随加速逻辑本身不在 __BANK 内(领队指针只能由调试 picker 设置)src/dev_ng/game/Vehicles/Vehicle.cpp:24597-24708。

DoProcessControl_OnDeferredTaskCompletion 只在全量更新时执行:提交河流浮力探测、引擎温度、清除自动复位作弊位、记录最后有司机时间、门导航更新、人行道/空中计时与惊吓事件、震动反馈、溺水灭火、延迟修复、gadget 与武器 ProcessControl、CPhysical::ProcessControl src/dev_ng/game/Vehicles/Vehicle.cpp:25204-25420。

12. 线程模型:延迟任务与作业#

机制线程同步方式证据
aiDeferredTasks(4 类任务、最多 512 项、最多 4 个工作线程)sysTaskManager 工作线程 + 主线程同时消费无锁环CreateWorkersAndWait;运行期间打开 fwRegdRef/事件/空间数组等锁并禁止任务删除,切换 PHLEVEL->SetOnlyMainThreadIsUpdatingPhysicssrc/dev_ng/game/vehicleAi/task/DeferredTasks.h:13-14、src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:82-154、src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:156-197
轮子积分sysDependency(高优先级)ProcessResult 自旋 sysIpcYield 等待 jobPending 归零src/dev_ng/game/Vehicles/wheel.cpp:7893-7958
人口链接收集 / 密度更新sysDependency自旋等待src/dev_ng/game/Vehicles/vehiclepopulation.cpp:4490-4574
车灯渲染器发起的 sysDependency:60 个作业 × 每作业 5 辆车(断言容量 ≥ 车辆池)ProcessResults 等待src/dev_ng/game/Vehicles/VehicleLightAsyncMgr.cpp:18-43

只有一个任务时不创建工作线程,直接在主线程执行 src/dev_ng/game/vehicleAi/task/DeferredTasks.cpp:96-102;PS3 上 DoProcessControl 与 CVehicleIntelligence::Process 都不走延迟任务(#if !__PS3)src/dev_ng/game/Vehicles/Vehicle.cpp:25184-25201、src/dev_ng/game/vehicleAi/VehicleIntelligence.cpp:1109-1125。

13. 平台与构建差异#

条件影响证据
__XENON || __PS3(XENON_OR_PS3)车辆/音频堆 464/488KB(否则 ×10);生成链接 1600(否则 4096);路口最大车辆 64(否则 128)、交通灯信息 85(否则 512)、同时活跃路口 60(否则 128)src/dev_ng/game/Vehicles/VehicleFactory.cpp:1445-1449、src/dev_ng/game/game_config.h:51-55
!__PS3车辆插值与 AI 收尾走延迟多线程任务src/dev_ng/game/Vehicles/Vehicle.cpp:25184-25201
ENABLE_FRAG_OPTIMIZATIONfragment 缓存按需分配/释放;gadget 装配时强制分配src/dev_ng/game/Vehicles/Vehicle.cpp:1768-1778、src/dev_ng/game/Vehicles/Vehicle.cpp:4952-4956
ENABLE_DRAFT_VEHICLE是否可创建 CDraftVehsrc/dev_ng/game/Vehicles/VehicleFactory.cpp:2840-2844
__BANK车辆工厂调试 bank、池满时打印清单、编队领队调试、ms_bSpawnTrailers 过滤src/dev_ng/game/Vehicles/VehicleFactory.h:139-294、src/dev_ng/game/Vehicles/VehicleFactory.cpp:1578-1584
__ASSERT车辆存在 10 秒仍未进入物理层会断言;FinishAiUpdate 校验 AI 期间速度未变src/dev_ng/game/Vehicles/Vehicle.cpp:25090-25100、src/dev_ng/game/Vehicles/Vehicle.cpp:29753-29782
GTA_REPLAY回放编辑模式下跳过人口、LOD、AI、物理src/dev_ng/game/Vehicles/vehiclepopulation.cpp:1247-1254、src/dev_ng/game/vehicleAi/VehicleAILodManager.cpp:390-393、src/dev_ng/game/Vehicles/Automobile.cpp:3189-3195

14. 约束与边界行为#

  • 枚举顺序约束:VehicleType 的顺序是类型判断的一部分(第 2 节)。
  • 网络注册先于状态变更:Create 中网络注册失败会立即销毁;克隆车辆不可被本地 Destroy(断言后返回,不删除)src/dev_ng/game/Vehicles/VehicleFactory.cpp:1668-1685、src/dev_ng/game/Vehicles/VehicleFactory.cpp:2696-2711。
  • 玩家车不得成为 dummy:DoProcessControl 开头断言 src/dev_ng/game/Vehicles/Vehicle.cpp:25088。
  • AI 期间速度只读:StartAiUpdate 缓存速度、FinishAiUpdate 校验并失效缓存(NaN),任务若在 AI 阶段改速度会被断言捕获 src/dev_ng/game/Vehicles/Vehicle.cpp:29728-29750、src/dev_ng/game/Vehicles/Vehicle.cpp:29907-29931。
  • frag 缓存耗尽:Create 直接返回 NULL,调用方必须处理失败 src/dev_ng/game/Vehicles/VehicleFactory.cpp:1586-1590。
  • 人口周期限额:工厂每次创建都会增加“本周期创建数”,因此脚本/调度生成的车辆会挤占环境车生成机会(推断,依据第 5.1 与 10.1 的计数点)。
  • 复用池与 AI:复用池中的车辆被 ShouldDoFullUpdate、ProcessIntelligence、延迟任务校验等多处显式跳过 src/dev_ng/game/vehicleAi/task/DeferredTasks.h:44-49。

15. 未决问题与证据不足#

  • 未在源码树中找到 gameconfig.xml、handling.meta、vehicles.meta、vehiclelayouts.meta、carcols.meta 等数据文件,故车辆池实际大小与各人口参数的默认值无法给出(仅能给出读取点)。
  • CVehicle::PreRender/PreRender2(灯光、轮子渲染矩阵、扰流板等)只在本页按调用位置提及,未逐项展开;渲染侧细节归 11 章。
  • ShouldRemoveVehicleInternal 的完整判定树(约 460 行)与 ChooseModel 的模型选择权重未逐行分析。
  • 工厂销毁缓存被禁用的原因无注释说明。