Skip to content

Instantly share code, notes, and snippets.

@majimboo
Last active August 2, 2021 12:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save majimboo/deba49add81da6b591da408280df0846 to your computer and use it in GitHub Desktop.
Save majimboo/deba49add81da6b591da408280df0846 to your computer and use it in GitHub Desktop.
a script that can list all the packages you have imported in your Unity project.
package main
import (
"archive/tar"
"compress/gzip"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
)
type Asset struct {
UnityVersion string
Pubdate string
Version string
Description string
UploadID string
VersionID string
ID string
Title string
ActualAssetPath string
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage:")
fmt.Println("unity-pkg-lister.exe <UNITY_PROJECT_NAME>")
return
}
PROJECT_NAME := os.Args[1]
OUTPUT_FILENAME := "unity_asset_packages.txt"
userDataPath, _ := os.UserConfigDir()
unityPath := filepath.Join(userDataPath, "Unity")
folders, _ := filepath.Glob(filepath.Join(unityPath, "Asset Store*"))
var installedAssets []Asset
fmt.Println("==========================================")
fmt.Println("# project " + PROJECT_NAME)
fmt.Println("==========================================")
fmt.Println("\nchecking all downloaded packages")
for _, assetFolder := range folders {
assets, _ := filepath.Glob(filepath.Join(assetFolder, "*/*/*.unitypackage"))
for _, assetPath := range assets {
fileName := filepath.Base(assetPath)
title := strings.TrimSuffix(fileName, filepath.Ext(fileName))
fmt.Printf("> %s\n", title)
f, err := os.Open(assetPath)
if err != nil {
log.Fatalln(err)
}
f.Seek(14, io.SeekStart)
var stringLength uint16
err = binary.Read(f, binary.LittleEndian, &stringLength)
if err != nil {
log.Fatalln(err)
}
byteSlice := make([]byte, stringLength)
_, err = f.Read(byteSlice)
if err != nil {
log.Fatalln(err)
}
f.Close()
var asset Asset
json.Unmarshal(byteSlice, &asset)
m, e := readUnityPackage(assetPath)
if e != nil {
panic(e)
}
asset.ActualAssetPath = m
installedAssets = append(installedAssets, asset)
}
}
output, err := os.Create(OUTPUT_FILENAME)
if err != nil {
log.Fatal(err)
}
defer output.Close()
userPath, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
fmt.Println("\nchecking for actual imported packages")
projectAssetFolders, _ := filepath.Glob(filepath.Join(userPath, PROJECT_NAME, "Assets", "**", "*"))
for _, projectAssetFolder := range projectAssetFolders {
assetFolderName := filepath.Base(projectAssetFolder)
for _, installedAsset := range installedAssets {
if strings.Contains(installedAsset.ActualAssetPath, assetFolderName) {
fmt.Printf("found = %s\n", installedAsset.Title)
output.WriteString(installedAsset.Title + "," + assetFolderName + "," + installedAsset.Version + "\n")
}
}
}
fmt.Printf("\n%s has been populated\n", OUTPUT_FILENAME)
}
func readUnityPackage(source string) (string, error) {
file, err := os.Open(source)
if err != nil {
return "", err
}
defer file.Close()
gzRead, err := gzip.NewReader(file)
if err != nil {
return "", err
}
tarRead := tar.NewReader(gzRead)
var pathName string
for {
cur, err := tarRead.Next()
if err == io.EOF {
break
} else if err != nil {
return "", err
}
if cur.Typeflag != tar.TypeReg {
continue
}
if strings.Contains(strings.ToLower(cur.Name), "pathname") {
data, err := io.ReadAll(tarRead)
if err != nil {
return "", err
}
txtData := string(data)
if strings.Contains(strings.ToLower(txtData), "assets/") {
pathName = strings.Split(strings.ReplaceAll(txtData, "\r\n", "\n"), "\n")[0]
break
}
}
}
return pathName, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment