Skip to content

Instantly share code, notes, and snippets.

@Cayahuanca
Last active October 16, 2023 08:13
Show Gist options
  • Save Cayahuanca/19689513318df4f56519089fc34d6077 to your computer and use it in GitHub Desktop.
Save Cayahuanca/19689513318df4f56519089fc34d6077 to your computer and use it in GitHub Desktop.
A Python script that extracts UnityPackage without using Unity.

About ExtractUnityPackage,py

ExtractUnityPackage,py is a Python script for extracting the contents of a UnityPackage.

This script can be useful in the following situations:

  • When you want to retrieve files from a UnityPackage without going through the time-consuming import process in Unity.
  • When you already have files with the same path or GUID in your Unity project, and importing the UnityPackage would overwrite them.

Note:

  • Python 3 is required to run this script. In most environments where Python 3 is installed, you should not need to install any additional libraries using tools like pip.
  • This script has been tested only on Windows and may not work correctly in Linux or macOS environments.

How to Run

Execute the script using the following command:

python ExtractUnityPackage.py [path to UnityPackage] [options]

Command Line Options

The following are the command line options for this script:

  • -m, --meta: Output .meta files.
  • -f, --force: When a folder with the same name as the UnityPackage already exists in the folder containing the UnityPackage, confirm whether to overwrite it. (You cannot decide on individual file overwrites.)

About Meta Files Option

By outputting files with .meta files attached, the exported files, when placed in Unity's Assets folder, will have the same GUID as the ones in the UnityPackage. This makes it possible to use them for shaders, scripts, or other files that might be updated by importing another UnityPackage into the project or when multiple copies of the same file might exist within the project, potentially causing bugs.

On the other hand, if there is no problem with multiple textures existing in a Unity project, if you output them without a .meta file and put them in the Unity Assets folder, a GUID different from the one in Unitypackage will be assigned to the file. This is useful if you want to create multiple variants of a Unity project, or just want specific files included in a Unitypackage.

Please note that materials, Prefab, etc. that refer to other files by using the GUID in the .meta file may not be able to be referenced properly if they are output without a .meta file and imported.

ExtractUnityPackage,py について

ExtractUnityPackage,py は、UnityPackage の中身を解凍する Python スクリプトです。

このスクリプトは、以下のような状況で便利に使用できます。

  • UnityPackage 内のファイルを、時間のかかる Unity でのインポートをせずに取得したい場合。
  • Unity のプロジェクト内に同じパスまたは GUID のファイルが既に存在し、UnityPackage をインポートすると上書きされてしまう場合。

注意事項

  • このスクリプトの実行にはPython 3が必要です。 通常、 Python 3 をインストールしている環境では、pip などで、追加のライブラリをインストールすることは不要であるはずです。
  • このスクリプトは Windows でのみテストされており、Linux や Mac の環境で正常に動作しない可能性があります。

実行方法

以下のコマンドでスクリプトを実行します。

python ExtractUnityPackage.py [Unitypackageへのパス] [オプション]

コマンドラインオプション

以下は、このスクリプトのコマンドラインオプションです。

  • -m, --meta: .meta ファイルを出力します。
  • -f, --force: Unitypackage のあるフォルダに、Unitypackage の名前と同じ名前のフォルダがすでに存在する場合に、上書きするか確認します。 (個別のファイル単位で上書きするかを決めることはできません)

Metaファイルについて

.meta ファイルを付けた状態で出力することにより、書き出したファイルを Unity の Assets フォルダに入れると、GUID が Unitypackage のものと同じになります。そのため、後から別の Unitypackage をプロジェクトにインポートして、上書き (更新)する可能性のあるファイルや、同じファイルが、プロジェクト内に複数存在するとバグが発生する可能性のある、シェーダーやスクリプトなどに使用することができます。

なお、マテリアルや Prefab など、.meta ファイルにある GUID を利用し、他のファイルを参照しているものは、.meta ファイルなしで出力し、それをインポートした場合は、うまく参照できなくなる場合があります。

import os
import argparse
import shutil
import tarfile
def extract_tar_to_folder(unitypackage_file, copy_meta, force_overwrite):
# Unitypackage ファイルの名前から拡張子を取り除いたフォルダを作成
folder_name = os.path.splitext(unitypackage_file)[0]
# 上述のフォルダがすでに存在するかチェック
if os.path.exists(folder_name):
if force_overwrite:
# -f オプションが指定されている場合、上書きを自動的に承認
print(f"フォルダ '{folder_name}' を上書きします。")
shutil.rmtree(folder_name)
else:
# それ以外の場合は、上書きの確認を求める
answer = input(f"フォルダ '{folder_name}' は既に存在します。上書きしますか? (y/n): ").strip().lower()
if answer != 'y':
print("処理を中止しました.")
return
# Unitypackageファイルを解凍
with tarfile.open(unitypackage_file, 'r') as tar:
tar.extractall(path=folder_name)
# Unitypackage の各フォルダ内にある pathname ファイルを処理
for root, _, files in os.walk(folder_name):
for file in files:
if file == "pathname":
pathname_path = os.path.join(root, "pathname")
asset_path = os.path.join(root, "asset")
# pathname ファイルから、作成するフォルダ名とファイル名を取得
with open(pathname_path, 'r', encoding='utf-8', errors='replace') as pathname_file:
new_folder_path, new_file_name = os.path.split(pathname_file.readline().strip())
# asset ファイルが、pathname ファイルと同じ階層に存在するかチェック
if os.path.exists(asset_path):
# asset ファイルも存在する場合 (書き出しがファイルになる場合)
new_file_path = os.path.join(folder_name, new_folder_path, new_file_name)
os.makedirs(os.path.join(folder_name, new_folder_path), exist_ok=True)
# assetファイルをコピー
shutil.copy(asset_path, new_file_path)
print(f"Copied {asset_path} to {new_file_path}")
if copy_meta:
# asset.meta ファイルを pathname + .meta としてコピー
asset_meta_path = os.path.join(root, "asset.meta")
new_asset_meta_path = new_file_path + ".meta"
shutil.copy(asset_meta_path, new_asset_meta_path)
print(f"Copied {asset_meta_path} to {new_asset_meta_path}")
else:
# asset ファイルが存在しない場合 (書き出しがフォルダになる場合)
new_file_path = os.path.join(folder_name, new_folder_path, new_file_name)
os.makedirs(os.path.join(folder_name, new_folder_path), exist_ok=True)
if copy_meta:
# asset.meta ファイルを pathname + .meta としてコピー
asset_meta_path = os.path.join(root, "asset.meta")
new_asset_meta_path = new_file_path + ".meta"
shutil.copy(asset_meta_path, new_asset_meta_path)
print(f"Copied {asset_meta_path} to {new_asset_meta_path}")
# Assets と Packages 以外のフォルダ (つまり、GUID と同じ名前のフォルダ) を削除
for item in os.listdir(folder_name):
item_path = os.path.join(folder_name, item)
if os.path.isdir(item_path) and item not in ["Assets", "Packages"]:
shutil.rmtree(item_path)
def main():
parser = argparse.ArgumentParser(description='Unitypackage ファイルを解凍する Python スクリプト')
parser.add_argument('unitypackage_file', type=str, help='解凍対象の Unitypackage ファイルのパス')
parser.add_argument('-m', '--meta', action='store_true', help='.meta ファイルも出力する')
parser.add_argument('-f', '--force', action='store_true', help='フォルダを上書きする場合、確認せずに上書きする')
args = parser.parse_args()
extract_tar_to_folder(args.unitypackage_file, args.meta, args.force)
print("展開が完了しました.")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment