Last active
September 20, 2022 17:52
-
-
Save SuperFlue/dfecd60d2fa173ccdd2b5cdc46ad972e to your computer and use it in GitHub Desktop.
Unity package extractor in PowerShell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This script can unpack Unitypackages that are based on tar.gz | |
# Regires an updated version of Windows 10 that has tar.exe buildt in (any currently in-support version of W10 should have this). | |
# MIT License <SuperFlue@GitHub> | |
[CmdletBinding()] | |
param ( | |
# The path to the unitypackage | |
[Parameter(ValueFromRemainingArguments=$true,Position=0)] | |
[String]$UnityPackage = (Read-Host "Enter package path"), | |
# Optional temp folder | |
# If no folder is specified we create a temporary folder in the same folder as the unitypackage | |
[Parameter()] | |
[string]$TempPath, | |
# Optional out folder | |
# If no one is specified we output the result in a folder in the same folder as the unitypackage | |
[Parameter()] | |
[string]$OutPath, | |
# Switch to prepare the output to be placed directly in a Unity Project | |
# Point -OutPath to your Unity Project root folder | |
# NOTE! You should only do this if you know what you are doing, and preferably only on fresh projects | |
# This is meant to be able to deploy a set of UnityPackages directly so you don't have to import them one by one | |
# But doing it this way might cause collisions between assets | |
[Parameter()] | |
[Switch]$DeployToProject, | |
# Switch that decides if we want to include .meta files or not in the extracted result | |
# If these are included you can just copy and paste the output directly into a Unity folder and things should link up properly | |
# Though prefered way in that case is to simply import the package properly into Unity in the first place... | |
[switch]$IncludeMetaFile = $true | |
) | |
# For easier handling we create a class to represent each upacked item | |
# This makes things a bit more predictable when we process the files | |
class UnityPackageItem { | |
[System.IO.DirectoryInfo]$CurrentDir | |
[string]$FullPath | |
[string]$Type | |
[int]$AssetLevel | |
UnityPackageItem(){} | |
UnityPackageItem([System.IO.DirectoryInfo]$ItemDirectory){ | |
$this.CurrentDir = $ItemDirectory | |
# Read the full item path from the "pathname" file | |
$File = [System.IO.StreamReader]::new($ItemDirectory.FullName+"\pathname",[System.Text.Encoding]::UTF8) | |
$this.FullPath = $File.ReadToEnd() | |
$File.Dispose() | |
# To make it easier to create folders in order we figure out which "level" the asset is on | |
$this.AssetLevel = @($this.FullPath -split "/").Count | |
# Check if this is a file or directory based on wether the "asset" file exists | |
if([System.IO.File]::Exists($ItemDirectory.FullName+"\asset")){ | |
$this.Type = "File" | |
} | |
else { | |
$this.Type = "Directory" | |
} | |
} | |
} | |
# Bit of sanity checking to make sure that tar.exe exist in path. | |
$TarExe = where.exe tar.exe | |
if([string]::IsNullOrWhiteSpace($TarExe)){ | |
Throw "No tar.exe found in path, halting script..." | |
} | |
# Get the file info of the package | |
# Also since PowerShell is weird with pasting " and ' in a Mandatory parameter, we make sure to strip those out of the input | |
try { | |
$UnityPkg = Get-Item ($UnityPackage.Replace('"','').Replace("'",'')) | |
} | |
catch { | |
Throw "Unable to get item ""$UnityPackage"", halting...." | |
} | |
# Handling temp and output folders | |
if([string]::IsNullOrWhiteSpace($TempPath)){ | |
$TempFolder = (Join-Path $UnityPkg.Directory.FullName ("TEMP_"+$UnityPkg.BaseName)) | |
} | |
else { | |
$TempFolder = (Join-Path $TempPath ("TEMP_"+$UnityPkg.BaseName)) | |
} | |
if([string]::IsNullOrWhiteSpace($OutPath)){ | |
$OutPath = $UnityPkg.Directory.FullName | |
} | |
if($DeployToProject){ | |
$OutFolder = $OutPath | |
} | |
else { | |
$OutFolder = (Join-Path $OutPath $UnityPkg.BaseName) | |
} | |
if(-not (Test-Path -Path $TempFolder)){ | |
$null = New-Item $TempFolder -ItemType Directory -Force | |
} | |
if(-not (Test-Path -Path $OutFolder )){ | |
$null = New-Item $OutFolder -ItemType Directory -Force | |
} | |
# Untar the files into the temp folder | |
$TarUnpackString = " -xzf ""{0}"" -C ""{1}""" | |
Start-Process tar.exe -ArgumentList "$($TarUnpackString -f $UnityPkg.FullName, $TempFolder)" -NoNewWindow -Wait | |
# Get all directories and process them as UnityPackageItems | |
$AllUnityItems = Get-ChildItem $TempFolder -Directory | |
$ProcessedList = [System.Collections.Generic.List[UnityPackageItem]]::new($AllUnityItems.Count) | |
foreach($UItem in $AllUnityItems){ | |
$ProcessedList.Add( [UnityPackageItem]::new($UItem) ) | |
} | |
# Pick out all the folders and sort by level | |
$LevelSortedList = $ProcessedList.FindAll({($args[0]).Type -eq "Directory"}) | Sort-Object AssetLevel | |
# To handle certain scenarios we just create the Assets folder directly | |
$null = New-Item (Join-Path $OutFolder "Assets") -ItemType Directory -Force | |
# Create folders | |
$LevelSortedList | ForEach-Object -Process { | |
$null = New-Item (Join-Path $OutFolder $psitem.FullPath) -ItemType Directory -Force | |
} | |
# Pick out all the files | |
$AllFiles = $ProcessedList.FindAll({($args[0]).Type -eq "File"}) | |
# Move the "asset" files into the right folder and rename them with the name as described in the "pathname" files | |
$AllFiles | ForEach-Object -Process { | |
Move-Item -Path (Join-Path $psitem.CurrentDir.FullName "asset") -Destination (Join-Path $OutFolder $psitem.FullPath) | |
} | |
# If we want the meta files we move them into the right place here | |
if ($IncludeMetaFile) { | |
$ProcessedList | ForEach-Object -Process { | |
Move-Item -Path (Join-Path $psitem.CurrentDir.FullName "asset.meta") -Destination "$(Join-Path $OutFolder $psitem.FullPath).meta" | |
} | |
} | |
# Remove the temp folder afterwards | |
Remove-Item $TempFolder -Recurse |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment