はじめに
GTA5ネイティブに存在する車両の改造を行います。
クライアント側を変更しただけでは他のプレイヤーには反映されないので、プラグイン化してサーバーにリソースとして読み込ませます。
今回はPolice Maverickというヘリコプターを防弾ガラスへ改造してみます。
必要なもの
- Blender
- Sollumz
- CodeWalker (最新版は公式Discordにあります)
それぞれ導入が完了しているものとします。
CodeWalkerでファイルをエクスポートする
CodeWalkerフォルダにあるCodeWalker RPF Explorerでモデルやオーディオファイルなど様々なファイルをインポート・エクスポートすることができます。
まずRPF Explorerでファイルを検索します。
Tools -> Binary Searchでファイルを検索できます。
Police Maverickはゲーム内IDでpolmavという名前で扱われます。
他の車両もゲーム内IDやハッシュで管理されているので都度調べると良いと思います。
検索設定を適当に合わせてやると良いでしょう。
検索は割愛します。
update\x64\dlcpacks\patchday3ng\dlc.rpf\x64\levels\gta5\vehicles.rpfにあるpolmavファイルを使います。

この2つをExtract Rawで抽出します。
polmav.yftはXMLでもエクスポートします。
保存先は管理しやすければどこでも大丈夫です。
次にpolmav.yftを右クリック -> View または ダブルクリックで開きます。
左上の >>をクリックしてメニューを開き、Materialタブに移動します。
Save all textures...でテクスチャを保存します。
こちらも保存先はどこでも大丈夫です。
BlenderでSollumzを使い編集する
Sollumzのパイメニューショートカットキーは Vです。
ここからでもいけます。
エクスポートしたxmlファイルをインポートします。
インポートされました。
ですが、このままだと四角い箱みたいなのが邪魔で肝心の本体が見えません。
Shift + Vで描画設定のパイメニューが開けます。
Hide ShattermapsとHide Collisonsの2つをクリックします。
表示されました。
右上のココを選択するとビューポートの表示設定を変更できます。
ピンク色の部分はテクスチャエラーを起こしています。
テクスチャが見つからないときによく起きます。
VでFind Missing Texturesを選択します。
先ほど抽出したテクスチャのフォルダに行きボタンを押します。
特定のファイルを選択しないで大丈夫です。
テクスチャが適用されました。まだピンクの部分がありますが、LODによるものなので今はあまり気にしなくて大丈夫です。
Shift + VでHighに設定するとちゃんと設定されます。
きちんと3Dモデルが表示されましたね。
あとは好きに加工したり、色を変えたりするのも自由です。
今回は防弾ガラスへ変更したいと思います。
見切れてますが今回の場合だとこれらがガラスのコリジョンです。
目のアイコンをクリックするとコリジョンを表示できます。
こんな感じになりました。
次にコリジョンマテリアルを設定します。

変更したいコリジョンを全て洗濯した後、
3DビューポートのツールバーからSollumz Toolsを選択し、コリジョン -> Create Collison Materialを選択します。
ここの小さな▶をクリックして検索バーを表示します。
Car Glassと入力します。
様々なコリジョンマテリアルがあるのですが、今回は防弾ガラスへ変えるのでCar Glass Bulletproofを選択します。
Convert To Selectedを選択します。
プロパティのマテリアルがCAR_GLASS_BULLETPROOFに変更されます。

Ctrl + L でデータのリンク/転送を開いたらマテリアルをリンクを選びます。
アウトライナーでモデルを選択します。
Vキーを押し、Export CodeWalker XMLを選び、任意の場所に保存します。
今回はexportフォルダに保存しておきました。
これでBlenderの操作は終了です。
RPF ExplorerでXMLをインポートする
Edit Modeに切り替えておきます。
編集モードでは上書きが可能になります。本体のデータを上書きしないようにしましょう。
File -> Open Folderでyftファイルの保存先を開きます。
あらかじめ保存しておいたpolmav.yftファイルを右クリックします。
Import XML... を選択します。
先ほどBlenderでExportしたxmlファイルを選択します。
これでインポートができました。
必ず抽出したyftファイルへ上書きしてください。
本体のデータを上書きしないよう注意しましょう。
vehicles.metaファイルを用意する
update\update.rpf\common\data\levels\gta5にvehicles.metaというファイルがあります。
これは車両の定義ファイルであり、車両がどういう特性を持つかなどがxml形式で記述されたファイルです。
これを先ほどと同じ要領で保存しておきます。
基本的にここから必要なものを取り出して使うので、そのまま使いません。
VSCodeなどテキストエディタでpolmavが定義された行を探します。
<modelName>で囲われた物を見つけたら<Item>の行からコピペします。
探すのがめんどい方用に用意しておきました。
XML
<Item>
<modelName>polmav</modelName>
<txdName>polmav</txdName>
<handlingId>POLMAV</handlingId>
<gameName>POLMAV</gameName>
<vehicleMakeName />
<expressionDictName>null</expressionDictName>
<expressionName>null</expressionName>
<animConvRoofDictName>null</animConvRoofDictName>
<animConvRoofName>null</animConvRoofName>
<animConvRoofWindowsAffected />
<ptfxAssetName>null</ptfxAssetName>
<audioNameHash />
<layout>LAYOUT_HELI</layout>
<coverBoundOffsets>POLMAV_COVER_OFFSET_INFO</coverBoundOffsets>
<explosionInfo>EXPLOSION_INFO_DEFAULT</explosionInfo>
<scenarioLayout />
<cameraName>FOLLOW_MAVERICK_CAMERA</cameraName>
<aimCameraName>MAVERICK_AIM_CAMERA</aimCameraName>
<bonnetCameraName>HELI_BONNET_CAMERA</bonnetCameraName>
<povCameraName>HELI_POV_CAMERA</povCameraName>
<FirstPersonDriveByIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByRearLeftIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByRearRightIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByLeftPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByRightPassengerIKOffset x="0.000000" y="-0.063000" z="-0.033000" />
<FirstPersonDriveByRightRearPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByLeftPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByRightPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonMobilePhoneOffset x="0.121000" y="0.350000" z="0.508000" />
<FirstPersonPassengerMobilePhoneOffset x="0.136000" y="0.296000" z="0.410000" />
<FirstPersonMobilePhoneSeatIKOffset>
<Item>
<Offset x="-0.519000" y="-0.133000" z="0.558000" />
<SeatIndex value="2" />
</Item>
<Item>
<Offset x="0.547000" y="-0.359000" z="0.468000" />
<SeatIndex value="3" />
</Item>
</FirstPersonMobilePhoneSeatIKOffset>
<PovCameraOffset x="0.000000" y="0.005000" z="0.650000" />
<PovCameraVerticalAdjustmentForRollCage value="0.000000" />
<PovPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
<PovRearPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
<vfxInfoName>VFXVEHICLEINFO_HELI_GENERIC</vfxInfoName>
<shouldUseCinematicViewMode value="true" />
<shouldCameraTransitionOnClimbUpDown value="false" />
<shouldCameraIgnoreExiting value="false" />
<AllowPretendOccupants value="false" />
<AllowJoyriding value="true" />
<AllowSundayDriving value="true" />
<AllowBodyColorMapping value="true" />
<wheelScale value="0.170000" />
<wheelScaleRear value="0.075000" />
<dirtLevelMin value="0.000000" />
<dirtLevelMax value="0.450000" />
<envEffScaleMin value="0.000000" />
<envEffScaleMax value="1.000000" />
<envEffScaleMin2 value="0.000000" />
<envEffScaleMax2 value="1.000000" />
<damageMapScale value="0.600000" />
<damageOffsetScale value="1.000000" />
<diffuseTint value="0x00FFFFFF" />
<steerWheelMult value="1.000000" />
<HDTextureDist value="5.000000" />
<lodDistances content="float_array">
20.000000
35.000000
100.000000
200.000000
1000.000000
1000.000000
</lodDistances>
<minSeatHeight value="1.057" />
<identicalModelSpawnDistance value="20" />
<maxNumOfSameColor value="10" />
<defaultBodyHealth value="1000.000000" />
<pretendOccupantsScale value="1.000000" />
<visibleSpawnDistScale value="1.350000" />
<trackerPathWidth value="2.000000" />
<weaponForceMult value="1.000000" />
<frequency value="100" />
<swankness>SWANKNESS_4</swankness>
<maxNum value="999" />
<flags>FLAG_NO_BOOT FLAG_HAS_LIVERY FLAG_LAW_ENFORCEMENT FLAG_DRIVER_NO_DRIVE_BY FLAG_NO_RESPRAY
FLAG_ALLOWS_RAPPEL FLAG_DONT_SPAWN_IN_CARGEN FLAG_HEADLIGHTS_USE_ACTUAL_BONE_POS
FLAG_DONT_SPAWN_AS_AMBIENT FLAG_BLOCK_FROM_ATTRACTOR_SCENARIO FLAG_DONT_TIMESLICE_WHEELS</flags>
<type>VEHICLE_TYPE_HELI</type>
<plateType>VPT_NONE</plateType>
<dashboardType>VDT_MAVERICK</dashboardType>
<vehicleClass>VC_HELICOPTER</vehicleClass>
<wheelType>VWT_SPORT</wheelType>
<trailers />
<additionalTrailers />
<drivers>
<Item>
<driverName>S_M_Y_SWAT_01</driverName>
<npcName />
</Item>
</drivers>
<extraIncludes />
<doorsWithCollisionWhenClosed />
<driveableDoors />
<bumpersNeedToCollideWithMap value="false" />
<needsRopeTexture value="true" />
<requiredExtras />
<rewards>
<Item>REWARD_WEAPON_SNIPERRIFLE</Item>
<Item>REWARD_AMMO_SNIPERRIFLE</Item>
<Item>REWARD_STAT_WEAPON</Item>
</rewards>
<cinematicPartCamera>
<Item>HELI_REAR_ROTOR_CAMERA</Item>
</cinematicPartCamera>
<NmBraceOverrideSet />
<buoyancySphereOffset x="0.000000" y="0.000000" z="0.000000" />
<buoyancySphereSizeScale value="1.000000" />
<pOverrideRagdollThreshold type="NULL" />
<firstPersonDrivebyData>
<Item>STD_FRONT_LEFT</Item>
<Item>HELI_FRONT_RIGHT</Item>
<Item>HELI_LEFT_SIDE_PASSENGER</Item>
<Item>HELI_RIGHT_SIDE_PASSENGER</Item>
</firstPersonDrivebyData>
<lockOnPositionOffset x="0.000000" y="0.600000" z="-0.100000" />
</Item>
ここからvehicles.metaの元ファイルに準拠した形に整えます。
vehicles.meta
<?xml version="1.0" encoding="utf-8"?>
<CVehicleModelInfo__InitDataList>
<residentTxd>vehshare</residentTxd>
<residentAnims />
<InitDatas>
<Item>
<modelName>polmav</modelName>
<txdName>polmav</txdName>
<handlingId>POLMAV</handlingId>
<gameName>POLMAV</gameName>
<vehicleMakeName />
<expressionDictName>null</expressionDictName>
<expressionName>null</expressionName>
<animConvRoofDictName>null</animConvRoofDictName>
<animConvRoofName>null</animConvRoofName>
<animConvRoofWindowsAffected />
<ptfxAssetName>null</ptfxAssetName>
<audioNameHash />
<layout>LAYOUT_HELI</layout>
<coverBoundOffsets>POLMAV_COVER_OFFSET_INFO</coverBoundOffsets>
<explosionInfo>EXPLOSION_INFO_DEFAULT</explosionInfo>
<scenarioLayout />
<cameraName>FOLLOW_MAVERICK_CAMERA</cameraName>
<aimCameraName>MAVERICK_AIM_CAMERA</aimCameraName>
<bonnetCameraName>HELI_BONNET_CAMERA</bonnetCameraName>
<povCameraName>HELI_POV_CAMERA</povCameraName>
<FirstPersonDriveByIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByRearLeftIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonProjectileDriveByRearRightIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByLeftPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByRightPassengerIKOffset x="0.000000" y="-0.063000" z="-0.033000" />
<FirstPersonDriveByRightRearPassengerIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByLeftPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonDriveByRightPassengerUnarmedIKOffset x="0.000000" y="0.000000" z="0.000000" />
<FirstPersonMobilePhoneOffset x="0.121000" y="0.350000" z="0.508000" />
<FirstPersonPassengerMobilePhoneOffset x="0.136000" y="0.296000" z="0.410000" />
<FirstPersonMobilePhoneSeatIKOffset>
<Item>
<Offset x="-0.519000" y="-0.133000" z="0.558000" />
<SeatIndex value="2" />
</Item>
<Item>
<Offset x="0.547000" y="-0.359000" z="0.468000" />
<SeatIndex value="3" />
</Item>
</FirstPersonMobilePhoneSeatIKOffset>
<PovCameraOffset x="0.000000" y="0.005000" z="0.650000" />
<PovCameraVerticalAdjustmentForRollCage value="0.000000" />
<PovPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
<PovRearPassengerCameraOffset x="0.000000" y="0.000000" z="0.000000" />
<vfxInfoName>VFXVEHICLEINFO_HELI_GENERIC</vfxInfoName>
<shouldUseCinematicViewMode value="true" />
<shouldCameraTransitionOnClimbUpDown value="false" />
<shouldCameraIgnoreExiting value="false" />
<AllowPretendOccupants value="false" />
<AllowJoyriding value="true" />
<AllowSundayDriving value="true" />
<AllowBodyColorMapping value="true" />
<wheelScale value="0.170000" />
<wheelScaleRear value="0.075000" />
<dirtLevelMin value="0.000000" />
<dirtLevelMax value="0.450000" />
<envEffScaleMin value="0.000000" />
<envEffScaleMax value="1.000000" />
<envEffScaleMin2 value="0.000000" />
<envEffScaleMax2 value="1.000000" />
<damageMapScale value="0.600000" />
<damageOffsetScale value="1.000000" />
<diffuseTint value="0x00FFFFFF" />
<steerWheelMult value="1.000000" />
<HDTextureDist value="5.000000" />
<lodDistances content="float_array">
20.000000
35.000000
100.000000
200.000000
1000.000000
1000.000000
</lodDistances>
<minSeatHeight value="1.057" />
<identicalModelSpawnDistance value="20" />
<maxNumOfSameColor value="10" />
<defaultBodyHealth value="1000.000000" />
<pretendOccupantsScale value="1.000000" />
<visibleSpawnDistScale value="1.350000" />
<trackerPathWidth value="2.000000" />
<weaponForceMult value="1.000000" />
<frequency value="100" />
<swankness>SWANKNESS_4</swankness>
<maxNum value="999" />
<flags>FLAG_NO_BOOT FLAG_HAS_LIVERY FLAG_LAW_ENFORCEMENT FLAG_DRIVER_NO_DRIVE_BY
FLAG_NO_RESPRAY FLAG_ALLOWS_RAPPEL FLAG_DONT_SPAWN_IN_CARGEN
FLAG_HEADLIGHTS_USE_ACTUAL_BONE_POS FLAG_DONT_SPAWN_AS_AMBIENT
FLAG_BLOCK_FROM_ATTRACTOR_SCENARIO FLAG_DONT_TIMESLICE_WHEELS
FLAG_HAS_BULLET_RESISTANT_GLASS</flags>
<type>VEHICLE_TYPE_HELI</type>
<plateType>VPT_NONE</plateType>
<dashboardType>VDT_MAVERICK</dashboardType>
<vehicleClass>VC_HELICOPTER</vehicleClass>
<wheelType>VWT_SPORT</wheelType>
<trailers />
<additionalTrailers />
<drivers>
<Item>
<driverName>S_M_Y_SWAT_01</driverName>
<npcName />
</Item>
</drivers>
<extraIncludes />
<doorsWithCollisionWhenClosed />
<driveableDoors />
<bumpersNeedToCollideWithMap value="false" />
<needsRopeTexture value="true" />
<requiredExtras />
<rewards>
<Item>REWARD_WEAPON_SNIPERRIFLE</Item>
<Item>REWARD_AMMO_SNIPERRIFLE</Item>
<Item>REWARD_STAT_WEAPON</Item>
</rewards>
<cinematicPartCamera>
<Item>HELI_REAR_ROTOR_CAMERA</Item>
</cinematicPartCamera>
<NmBraceOverrideSet />
<buoyancySphereOffset x="0.000000" y="0.000000" z="0.000000" />
<buoyancySphereSizeScale value="1.000000" />
<pOverrideRagdollThreshold type="NULL" />
<firstPersonDrivebyData>
<Item>STD_FRONT_LEFT</Item>
<Item>HELI_FRONT_RIGHT</Item>
<Item>HELI_LEFT_SIDE_PASSENGER</Item>
<Item>HELI_RIGHT_SIDE_PASSENGER</Item>
</firstPersonDrivebyData>
<lockOnPositionOffset x="0.000000" y="0.600000" z="-0.100000" />
</Item>
</InitDatas>
</CVehicleModelInfo__InitDataList>
<flags>要素にFLAG_HAS_BULLET_RESISTANT_GLASSフラグを追加します。
他のフラグは消さないようにしましょう。
...
<trackerPathWidth value="2.000000" />
<weaponForceMult value="1.000000" />
<frequency value="100" />
<swankness>SWANKNESS_4</swankness>
<maxNum value="999" />
<flags>FLAG_NO_BOOT FLAG_HAS_LIVERY ... FLAG_HAS_BULLET_RESISTANT_GLASS</flags>
<type>VEHICLE_TYPE_HELI</type>
<plateType>VPT_NONE</plateType>
<dashboardType>VDT_MAVERICK</dashboardType>
<vehicleClass>VC_HELICOPTER</vehicleClass>
<wheelType>VWT_SPORT</wheelType>
<trailers />
...
flagのリスト
他にも適用させたいフラグはこちらから調べると良いと思います。
プラグイン化する
fxmanifest.luaを用意します。
fx_version 'cerulean'
game 'gta5'
files {
'data/vehicles.meta',
'stream/*.yft',
'stream/*.ytd'
}
data_file 'VEHICLE_METADATA_FILE' 'data/vehicles.meta'
ディレクトリ構造
[plugin_folder]
├─ fxmanifest.lua
│
├─ data/
│ └─ vehicles.meta
│
└─ stream/
├─ polmav.yft
└─ polmav.ytd
data_file 'VEHICLE_METADATA_FILE' 'data/vehicles.meta'の記述を忘れないでください。
あとはサーバーを起動するだけです。肌感覚ではリソースの再起動だけだと正常に読み込まれないのでサーバーの再起動が必須です。
結果
・変更前
ガラスが割れています。奥のガラスに弾が当たっている様子が見えます。
・変更後
いくら撃っても割れません。多分先に車両が壊れます。
終わりに
基本的なことしかしていないのでもっと難しいこともできます。
新しい車両を作って追加したり、派手に装飾を施したりもできると思います。
































