FiveM / GTA V → Roblox(車両)
「この車両を変換して」+ZIP = ユーザーのクリック不要で全フロー:前提条件→変換→アップロード→Studioへの到着→セットアップ→検証→修正→短いレポート(日本語)。StudioのステップはMCP Roblox Studioが接続されている場合のみ適用されます。接続がない場合は、フォルダと手動ステップを提供します(ページ下部)。
測定、選択、注意点:docs/studio-import-tests.md。
ガードレール
- ZIP内のコードは決して実行しないでください。内容はデータのみです。
- シークレットは表示、ファイルへの書き込み、コミットを行わないでください(Open Cloudキーは環境変数のみ)。
- 既存のプレイスは、作業ディレクトリ
Workspace.F2R_ImportTest(またはユーザーが指定したフォルダ)以外は変更しないでください。プレイスの保存や公開は絶対に行わないでください。ランタイムは ReplicatedStorage / ServerScriptService / StarterPlayerScripts にインストールされます。レポートにその旨を記載してください。 - Robloxに公開するのは、車両のプライベートアセット(GLB、サウンド)のみとし、それ以外は許可なく公開しないでください。
- 結果を捏造しないでください。スクリプトやVerifyのメッセージをそのまま引用してください。
- ゲームを公開する前に、Modのライセンスと実際の商標を確認するよう、一度リマインドしてください。
0. 前提条件(並行して、最初に)
| 前提条件 | 確認方法 | ない場合 |
|---|---|---|
| Python 3.10+、numpy、Pillow | python3 -c "import numpy, PIL" | python3 -m pip install --user numpy pillow(pipがない場合:get-pip.py --user) |
| .NET 8(バイナリファイル .yft/.ytd/.awc 用) | dotnet --version または ~/.dotnet/dotnet | dotnet-install.sh --channel 8.0 --install-dir ~/.dotnet;コンバーターは ~/.dotnet を自動で見つけます |
| GTA Vアセットサーバー(実際のテクスチャとサウンド) | MCPツール gta_status(ready: true) | PC上で tools/gta-asset-server/start-server.bat を起動し、My MCP servers に登録するよう提案;それ以外の場合は、キャッシュ(~/.cache/fivem2roblox)内のものを使用し、キャッシュにもなければ単色/合成音を使用 |
| Studio接続 | studio_connection_status(プラグイン接続)、list_roblox_studios | フォルダと手動ステップを提供 |
| Robloxアップロード | VibeStarter:ツール upload_file + asset_publish;それ以外:環境変数 ROBLOX_API_KEY が存在すること(絶対に表示しない) | 最終手段:手動アクション1回のみ、「3Dインポート」(§ 4c) |
1. 変換
cd skills/fivem-vehicle-to-roblox
python scripts/convert_vehicle.py "<zip>" -o "<出力先>" [--plate "テキスト"] [--texture-overrides <フォルダ>]
オプション:--vehicle <名前>(マルチビークルパック)、--lod med(30万トライアングル超)、--no-collision(当たり判定=単純なボックス)、--wheel-collision(ホイールのソリッドシリンダー)、--studs-per-meter、--texture-overrides <フォルダ>(パック内のテクスチャを置き換える同名のPNG/DDS:リブランド、修正)、--sound-ids <json>、--retry-gamefiles、--no-game-server。
コード2=抽出機能なしのバイナリ:.NET 8をインストール(上記)して再実行;それ以外の場合はユーザーがCodeWalker XML出力を提供;暗号化された dlc.rpf → OpenIV。
<出力先>/<名前>/report.md を読む:「当たり判定:車両の公式衝突判定」(それ以外は境界ボックス:.yft に Physics/Bounds がない場合はその旨を報告)、「基本ゲームから再利用されたテクスチャ」、「実際のゲームサウンド」、「アセットサーバーからの転送」(ファイル、MB、秒)の各行。vehshare/vehicle_generic_* テクスチャの欠落、または合成音の使用=アセットサーバーに接続できない。
2. モデルとサウンドのアップロード(プライベートアセット)
並行して:
- GLB
<名前>.glb→upload_fileのちasset_publish→ Modelタイプのrbxassetid。 - サウンド:各
sounds/*.wav|ogg→upload_file+asset_publish→sounds/sound_ids.jsonに書き込み ={ "engine_on_1.wav": "rbxassetid://…", … }。 VibeStarter以外の場合:python scripts/roblox_upload.py <出力先>/<名前>/sounds --user-id <id>(キーは環境変数)。 --sound-ids <出力先>/<名前>/sounds/sound_ids.jsonを指定して変換を再実行(キャッシュ:約15秒)し、SoundIdをセットアップに統合します。GLBは変換間で同一(決定論的)です:新しいアップロードは不要。
忠実な当たり判定(自動)
.yft には車両の公式衝突判定(Physics/LOD1、複合 Bound)が含まれています:ボディ、ボンネット、トランク、ドア、窓が低ポリゴンメッシュ(約240トライアングル)、ホイールがディスク。コンバーターはこれをGLB(col__<os>__<n>、*_lowlod / *_dummy は除外)にエクスポートします。セットアップでは、これらを不可視でソリッド、かつ照会可能なパーツとして Collision/<os>/ に配置し、それぞれのボーンに溶接(ドアを開けても衝突判定は保持)、精度を設定(凸の場合は Hull、そうでない場合は PreciseConvexDecomposition、CreateMeshPartAsync + ApplyMesh を使用:スクリプトで CollisionFidelity を設定してもエラーなしで無視される)、ホイールをシリンダー(半径と接触点;--wheel-collision でソリッド)として追加し、Hitbox ボックスを無効化(境界ボリュームとして保持、属性 BoundsOnly)。m422での測定:可視ボディからの距離が15cm未満のレイを86%が達成(ボックスのみでは34%)。プレイヤーはボンネットの上に +1.55 stud で立つ(+3.17 stud ではなく)。当たり判定を表示するには:Collision を一時的に可視化(Transparency 0.5)。
3. Studio用スクリプトの準備(100KBのコードをコピーしない)
変換によって <出力先>/<名前>/studio/ が作成されます:FiveMRuntime.lua(ランタイム、プレイスに1回)、<名前>_Setup.studio.lua(コンパクトなセットアップ)、Verify.lua、ApplySoundIds.lua、chunks/ + manifest.json。
- 開いているプレイスと同期したRojoプロジェクト(VibeStarter):ファイルをマウントされたフォルダに配置 —
→python scripts/studio_stage.py <出力先>/<名前> --project <プロジェクトのフォルダ>ReplicatedStorage.rbxts_include.F2R_Transfer(StringValueFiveMRuntime、<名前>_Setup、ApplySoundIds、<名前>_sound_ids;ModuleScriptVerify)が約2秒でStudioに表示されます。 - それ以外の場合:
studio/chunks/*.luaをmanifest.jsonの順序で、execute_luauをファイルごとに1回ずつ、そのまま送信します。各ステップの最後のチャンクがスクリプトを実行し、結果を返します。
4. Studioにモデルを配置する
a. EditableMesh:却下(保存時にジオメトリが失われる、車両1台で約12MBのテキストになる)。
b. 採用:insert_asset でGLBのIDを使用、parent = "Workspace.F2R_ImportTest"(フォルダがなければ execute_luau で作成)、position は自由(セットアップが車両を地面に配置)。MeshPartsはglTFノードの名前を保持(Model <名前>_Node 内、セットアップで削除)。
c. 最終手段、アップロードが不可能な場合:ユーザーに1回だけアクションを依頼 — 「Studioで:ホーム › 3Dインポート › <出力先>/<名前>/<名前>.glb、デフォルトオプション。完了したら教えてください。」 セットアップはその後、モデルを自動的に見つけます(パーツ ProbePart)。
5. ランタイム + セットアップ(execute_luau、編集)
local T = game.ReplicatedStorage.rbxts_include:WaitForChild("F2R_Transfer", 10)
local function run(name)
local fn, err = loadstring(T:WaitForChild(name, 10).Value, "=" .. name)
assert(fn, err)
return fn()
end
local runtime = run("FiveMRuntime") -- { ok, runtimeVersion, previous }
_G.F2R_TARGET = workspace.F2R_ImportTest.<名前> -- 挿入されたModel
local setup = run("<名前>_Setup") -- { parts, joints, missingParts, missingSounds, groundedBy, warnings }
return { runtime = runtime, setup = setup }
セットアップの前に _G.F2R_NO_GROUND = true とすると、インポート時の高さを維持します。SoundIdの忘れ:_G.F2R_TARGET = モデル;_G.F2R_SOUND_IDS = T.<名前>_sound_ids.Value;run("ApplySoundIds")。
6. 検証(roblox/Verify.lua)
Verify.lua は関数 verify(opts) -> JSON を返します:{ pass, fail, warn, skip, results = { {group, name, status, detail} } }。
編集 — require(T.Verify:Clone())({ model = <モデル> }):ランタイムがインストールされていること;パーツが存在し、正しく命名されていること(F2RExpectedParts);車両がまっすぐで、前方が−Z方向であること;スケール(ホイールベースが1%以内);ヘッドライトがテールライトより前にあること;パーツがフットプリント内にあること;地面に設置されていること;ホイールが正しい位置と向きにあること;当たり判定(パーツとホイールが存在し、不可視かつソリッドでボーンに溶接され、精度が設定され、ボックスが無効化されていること、6方向から400本のレイを使用した忠実度が可視ボディおよびボックスと比較して15cm未満が80%以上);SoundIdが入力されていること;SetColor / SetMod / SetLivery / SetExtra / SetNeon / SetPlate および Serialize → Apply で状態が復元されること。
プレイ、サーバー(execute_luau Server、1プレイヤー)— require(…Verify)({ model = …, checks = {…} }):seats_play(各シートで乗車、降車;seat = "<名前>" で1つのみ)、lock_play、park_play、flip_play、void_play(虚空への落下から回復)。ボディ適応(クライアント、着座プレイヤー):checks = {"fit_play"} — ボディのどの点もキャビンの外に出ていない、シートに座っている、スケールが読み取れる。seats_play を車両を軽い傾斜(作業フォルダ内の一時的な傾斜プラットフォーム)に置いて再実行。
プレイ、クライアント(レンダリングランタイムはクライアント側でのみ動作;loadstring はクライアントでは禁止):
start_stop_play(is_start = true)。execute_luauクライアント:require(game.ReplicatedStorage.rbxts_include.F2R_Transfer.Verify)({ model = workspace.F2R_ImportTest:WaitForChild("<名前>"), checks = {"joints","lights","sounds","audio"} })→ レンダリングはFiveMVehiclesClientによって自動的にアタッチされる(それ以外の場合はゲーム内で車両が無反応);ドア/ボンネット/トランクがHingesからDoor_*経由で角度を持って動作、ホイールとステアリングはテレメトリ経由で動作、キャリパー(hub_*)は回転せずに操舵、サスペンションアーム(suspension_*)は回転固定、各LightRoleはHeadlights 1/2、Brake、Reverse、Indicator Left/Right/Hazard、Engine、Sirenに対してNeon(または照明点灯)として機能;サウンドが読み込まれる;エンジン音が聞こえる。- 運転:
execute_luauサーバー — プレイヤーを座らせる(seat:Sit(humanoid)をSeats.DriverSeatに対して)そして属性Hornを監視;player_inputH 次いで E(700ms間押し続ける);execute_luauサーバー —Engine = true、Headlights = 1、Hornがtrueになった後falseに戻るのを待つ。 - 運転エンジン:プレイヤーがステアリングを握る(サーバー側で
VehicleAccess.Enter)、次いでexecute_luauクライアントrequire(…Verify)({ model = …, checks = {"drive_play"} })(加速、一貫した回転数、停止、直進を維持)。完全な測定(0-100、制動、旋回、縁石、坂道、後退):マップから離れた場所にTestTrack.luaを作成、DriveBench.luaベンチマーク、詳細はreferences/roblox-integration.md(「運転テスト」)を参照;長時間テストはtask.spawnで。 start_stop_play(is_start = false)。制御を返す前に必ずPlayを停止してください。3分間Studio呼び出しなしのPlayはVibeStarterによって停止されます。
Verifyの結果を読み取ってください。コンソールのエラー数ではありません:他の車両を含むプレイスでは、私たちのものではない「Failed to load sound …」が数百件表示されることがあります。warn ステータス「レンダリング停止」=Studioにフォーカスがない(RenderStepped停止):グループを再実行してください。
7. 各エラーの修正
| Verifyエラー | 一般的な原因 | 修正 |
|---|---|---|
| パーツ欠落/名前変更 | 異なるインポーター | 名前を確認(F2RMissingParts);GLBを再インポート(§ 4b) |
| ホイールベース / 前方が−Z方向でない / ホイールの向き | モデルが反転、基準点が不適切 | セットアップのメッセージ「位置合わせが不正確」;pick_ref_parts または軸変換を修正 |
| ドアが0°(「レンダリング停止」ではない) | Motor6Dがない、パーツがルートに溶接されている | Joints/ とドアパーツの Owner を確認 |
| ライトの役割がオフのまま | パーツに LightRole がない、不明なライトID | references/gta-format.md(ライトID);f2r/vehicle.py を修正 |
| SoundIdが空/サウンドが読み込まれない | アップロード未完了または拒否 | § 2;ApplySoundIds |
| Serialize / Apply | 状態が復元されない | roblox/runtime/VehicleCustomization.lua |
当たり判定:精度 Default | ApplyMesh が拒否された(メッシュ未ロード、権限不足) | セットアップを再実行;GLBがプレイス所有者のアセットであることを確認 |
| 当たり判定の忠実度 < 80% | Modの衝突判定が粗い、または存在しない | 「大きすぎる/小さすぎる」と報告;Physics がないMod → ボックス(報告) |
| レンダリングがFiveMVehiclesClientによってアタッチされない | 2026-11-10の修正前のランタイム | FiveMRuntime(新しいバージョン)を再インストール |
| ホイール操舵時にキャリパーが固定 | 2026-11-11より前の変換(hub_* ボーンが無視) | 再変換して再インストール(§ 4bから6) |
| プロンプト/サウンドが「車外」 | 2026-11-11より前のセットアップ(親設定前にWorldPositionが設定) | 車両を再インストール(§ 4bから6) |
| 降車:屋根の上に着地 | 両側に空きスペースがない(壁、他の車両) | 正常;それ以外の場合は傾斜と隣接パーツを確認 |
| 頭が天井に(警告) | アバターがスケールに対して大きすぎる | seats_play が推奨するスケールで再変換 |
スキルの修正後:再変換、再インストール(モデルを削除し、§ 4bから6を実行)、再検証。ランタイムの変更は FiveMRuntime(バージョン=ソースのハッシュ)によって伝播します。
…
[翻訳のために省略]