AssetStudio/AssetStudio/StudioClasses/Studio.cs

749 lines
34 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2018-04-09 20:45:09 +00:00
using System.Diagnostics;
using System.Globalization;
using System.IO;
2018-03-01 12:01:25 +00:00
using System.Linq;
2018-04-09 20:45:09 +00:00
using System.Threading;
using System.Windows.Forms;
using static AssetStudio.Exporter;
2018-04-02 22:51:22 +00:00
namespace AssetStudio
{
internal static class Studio
{
2017-02-11 20:57:24 +00:00
public static List<AssetsFile> assetsfileList = new List<AssetsFile>(); //loaded files
public static Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>();
2018-02-28 19:42:43 +00:00
public static Dictionary<string, EndianBinaryReader> resourceFileReaders = new Dictionary<string, EndianBinaryReader>(); //use for read res files
2018-11-07 21:00:53 +00:00
public static List<AssetItem> exportableAssets = new List<AssetItem>(); //used to hold all assets while the ListView is filtered
2018-07-26 02:00:32 +00:00
private static HashSet<string> assetsNameHash = new HashSet<string>(); //avoid the same name asset
2018-11-07 21:00:53 +00:00
public static List<AssetItem> visibleAssets = new List<AssetItem>(); //used to build the ListView from all or filtered assets
2018-10-16 16:43:34 +00:00
public static Dictionary<string, SortedDictionary<int, TypeTreeItem>> AllTypeMap = new Dictionary<string, SortedDictionary<int, TypeTreeItem>>();
2018-09-26 17:15:37 +00:00
public static List<GameObjectTreeNode> treeNodeCollection = new List<GameObjectTreeNode>();
public static Dictionary<GameObject, GameObjectTreeNode> treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
2018-11-07 22:45:33 +00:00
public static string mainPath;
public static string productName = string.Empty;
2017-02-11 20:57:24 +00:00
//UI
public static Action<int> SetProgressBarValue;
public static Action<int> SetProgressBarMaximum;
public static Action ProgressBarPerformStep;
public static Action<string> StatusStripUpdate;
public static Action<int> ProgressBarMaximumAdd;
2018-04-18 04:04:46 +00:00
public enum FileType
{
AssetsFile,
BundleFile,
WebFile
}
2018-07-14 15:46:32 +00:00
public static FileType CheckFileType(Stream stream, out EndianBinaryReader reader)
2018-04-18 04:04:46 +00:00
{
reader = new EndianBinaryReader(stream);
return CheckFileType(reader);
}
2018-04-09 20:45:09 +00:00
2018-04-18 04:04:46 +00:00
public static FileType CheckFileType(string fileName, out EndianBinaryReader reader)
{
reader = new EndianBinaryReader(File.OpenRead(fileName));
return CheckFileType(reader);
}
private static FileType CheckFileType(EndianBinaryReader reader)
{
var signature = reader.ReadStringToNull();
reader.Position = 0;
switch (signature)
{
case "UnityWeb":
case "UnityRaw":
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
case "UnityFS":
return FileType.BundleFile;
case "UnityWebData1.0":
return FileType.WebFile;
default:
{
var magic = reader.ReadBytes(2);
reader.Position = 0;
if (WebFile.gzipMagic.SequenceEqual(magic))
{
return FileType.WebFile;
}
reader.Position = 0x20;
magic = reader.ReadBytes(6);
reader.Position = 0;
if (WebFile.brotliMagic.SequenceEqual(magic))
{
return FileType.WebFile;
}
return FileType.AssetsFile;
}
}
}
public static void ExtractFile(string[] fileNames)
2018-03-04 18:35:53 +00:00
{
2018-04-09 20:45:09 +00:00
ThreadPool.QueueUserWorkItem(state =>
{
int extractedCount = 0;
2018-04-18 04:04:46 +00:00
foreach (var fileName in fileNames)
2018-04-09 20:45:09 +00:00
{
2018-04-18 04:04:46 +00:00
var type = CheckFileType(fileName, out var reader);
if (type == FileType.BundleFile)
extractedCount += ExtractBundleFile(fileName, reader);
else if (type == FileType.WebFile)
extractedCount += ExtractWebDataFile(fileName, reader);
else
reader.Dispose();
2018-04-09 20:45:09 +00:00
ProgressBarPerformStep();
}
StatusStripUpdate($"Finished extracting {extractedCount} files.");
});
2018-03-04 18:35:53 +00:00
}
2018-04-18 04:04:46 +00:00
private static int ExtractBundleFile(string bundleFileName, EndianBinaryReader reader)
{
2018-07-14 15:46:32 +00:00
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
var bundleFile = new BundleFile(reader, bundleFileName);
2018-04-09 20:45:09 +00:00
reader.Dispose();
if (bundleFile.fileList.Count > 0)
{
2018-04-18 04:04:46 +00:00
var extractPath = bundleFileName + "_unpacked\\";
Directory.CreateDirectory(extractPath);
2018-07-14 15:46:32 +00:00
return ExtractStreamFile(extractPath, bundleFile.fileList);
2018-04-18 04:04:46 +00:00
}
return 0;
}
private static int ExtractWebDataFile(string webFileName, EndianBinaryReader reader)
{
2018-07-14 15:46:32 +00:00
StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
2018-04-18 04:04:46 +00:00
var webFile = new WebFile(reader);
reader.Dispose();
if (webFile.fileList.Count > 0)
{
var extractPath = webFileName + "_unpacked\\";
Directory.CreateDirectory(extractPath);
2018-07-14 15:46:32 +00:00
return ExtractStreamFile(extractPath, webFile.fileList);
2018-04-18 04:04:46 +00:00
}
return 0;
}
2018-07-14 15:46:32 +00:00
private static int ExtractStreamFile(string extractPath, List<StreamFile> fileList)
2018-04-18 04:04:46 +00:00
{
int extractedCount = 0;
2018-07-14 15:46:32 +00:00
foreach (var file in fileList)
2018-04-18 04:04:46 +00:00
{
2018-07-14 15:46:32 +00:00
var filePath = extractPath + file.fileName;
2018-04-18 04:04:46 +00:00
if (!Directory.Exists(extractPath))
{
2018-04-18 04:04:46 +00:00
Directory.CreateDirectory(extractPath);
}
2018-07-14 15:46:32 +00:00
if (!File.Exists(filePath) && file.stream is MemoryStream stream)
2018-04-18 04:04:46 +00:00
{
2018-07-14 15:46:32 +00:00
File.WriteAllBytes(filePath, stream.ToArray());
2018-04-18 04:04:46 +00:00
extractedCount += 1;
}
2018-07-14 15:46:32 +00:00
file.stream.Dispose();
}
return extractedCount;
}
2018-09-26 17:15:37 +00:00
public static void BuildAssetStructures(bool loadAssets, bool displayAll, bool buildHierarchy, bool buildClassStructures, bool displayOriginalName)
{
2018-11-07 21:00:53 +00:00
var tempDic = new Dictionary<ObjectReader, AssetItem>();
// first loop - read asset data & create list
2018-04-21 13:52:15 +00:00
if (loadAssets)
{
2017-02-11 20:57:24 +00:00
SetProgressBarValue(0);
2018-11-07 21:00:53 +00:00
SetProgressBarMaximum(assetsfileList.Sum(x => x.ObjectReaders.Count));
2018-04-18 00:19:30 +00:00
StatusStripUpdate("Building asset list...");
2018-11-07 21:00:53 +00:00
var fileIDfmt = "D" + assetsfileList.Count.ToString().Length;
2017-02-11 20:57:24 +00:00
for (var i = 0; i < assetsfileList.Count; i++)
{
2017-02-11 20:57:24 +00:00
var assetsFile = assetsfileList[i];
2018-11-07 21:00:53 +00:00
var tempExportableAssets = new List<AssetItem>();
var fileID = i.ToString(fileIDfmt);
AssetBundle ab = null;
2018-11-07 21:00:53 +00:00
var j = 0;
var assetIDfmt = "D" + assetsFile.m_Objects.Count.ToString().Length;
foreach (var objectReader in assetsFile.ObjectReaders.Values)
{
2018-11-07 21:00:53 +00:00
var assetItem = new AssetItem(objectReader);
tempDic.Add(objectReader, assetItem);
assetItem.UniqueID = fileID + j.ToString(assetIDfmt);
var exportable = false;
2018-11-07 21:00:53 +00:00
switch (assetItem.Type)
{
2018-10-16 16:43:34 +00:00
case ClassIDType.GameObject:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var m_GameObject = new GameObject(objectReader);
assetItem.Text = m_GameObject.m_Name;
assetsFile.GameObjects.Add(objectReader.m_PathID, m_GameObject);
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.Transform:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var m_Transform = new Transform(objectReader);
assetsFile.Transforms.Add(objectReader.m_PathID, m_Transform);
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.RectTransform:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var m_Rect = new RectTransform(objectReader);
assetsFile.Transforms.Add(objectReader.m_PathID, m_Rect);
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.Texture2D:
2018-09-26 17:28:03 +00:00
{
2018-11-07 21:00:53 +00:00
var m_Texture2D = new Texture2D(objectReader, false);
2018-09-26 17:28:03 +00:00
if (!string.IsNullOrEmpty(m_Texture2D.path))
2018-11-07 21:00:53 +00:00
assetItem.FullSize = objectReader.byteSize + m_Texture2D.size;
2018-10-16 16:43:34 +00:00
goto case ClassIDType.NamedObject;
2018-09-26 17:28:03 +00:00
}
2018-10-16 16:43:34 +00:00
case ClassIDType.AudioClip:
2018-09-26 17:28:03 +00:00
{
2018-11-07 21:00:53 +00:00
var m_AudioClip = new AudioClip(objectReader, false);
2018-09-26 17:28:03 +00:00
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
2018-11-07 21:00:53 +00:00
assetItem.FullSize = objectReader.byteSize + m_AudioClip.m_Size;
2018-10-16 16:43:34 +00:00
goto case ClassIDType.NamedObject;
2018-09-26 17:28:03 +00:00
}
2018-10-16 16:43:34 +00:00
case ClassIDType.VideoClip:
2018-09-26 17:28:03 +00:00
{
2018-11-07 21:00:53 +00:00
var m_VideoClip = new VideoClip(objectReader, false);
2018-09-26 17:28:03 +00:00
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
2018-11-07 21:00:53 +00:00
assetItem.FullSize = objectReader.byteSize + (long)m_VideoClip.m_Size;
2018-10-16 16:43:34 +00:00
goto case ClassIDType.NamedObject;
2018-09-26 17:28:03 +00:00
}
2018-10-16 16:43:34 +00:00
case ClassIDType.NamedObject:
case ClassIDType.Mesh:
case ClassIDType.Shader:
case ClassIDType.TextAsset:
case ClassIDType.AnimationClip:
case ClassIDType.Font:
case ClassIDType.MovieTexture:
case ClassIDType.Sprite:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var obj = new NamedObject(objectReader);
assetItem.Text = obj.m_Name;
2017-02-16 07:30:11 +00:00
exportable = true;
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.Avatar:
case ClassIDType.AnimatorController:
case ClassIDType.AnimatorOverrideController:
case ClassIDType.Material:
case ClassIDType.MonoScript:
case ClassIDType.SpriteAtlas:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var obj = new NamedObject(objectReader);
assetItem.Text = obj.m_Name;
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.Animator:
2017-02-16 07:30:11 +00:00
{
exportable = true;
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.MonoBehaviour:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var m_MonoBehaviour = new MonoBehaviour(objectReader);
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var script))
2018-08-04 20:46:27 +00:00
{
var m_Script = new MonoScript(script);
2018-11-07 21:00:53 +00:00
assetItem.Text = m_Script.m_ClassName;
2018-08-04 20:46:27 +00:00
}
else
{
2018-11-07 21:00:53 +00:00
assetItem.Text = m_MonoBehaviour.m_Name;
2018-08-04 20:46:27 +00:00
}
exportable = true;
2017-02-16 07:30:11 +00:00
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.PlayerSettings:
2017-02-16 07:30:11 +00:00
{
2018-11-07 21:00:53 +00:00
var plSet = new PlayerSettings(objectReader);
2017-02-16 07:30:11 +00:00
productName = plSet.productName;
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.AssetBundle:
{
2018-11-07 21:00:53 +00:00
ab = new AssetBundle(objectReader);
assetItem.Text = ab.m_Name;
2018-04-06 23:51:33 +00:00
break;
}
}
2018-11-07 21:00:53 +00:00
if (assetItem.Text == "")
2018-07-26 02:00:32 +00:00
{
2018-11-07 21:00:53 +00:00
assetItem.Text = assetItem.TypeString + " #" + assetItem.UniqueID;
2018-07-26 02:00:32 +00:00
}
2018-11-07 21:00:53 +00:00
assetItem.SubItems.AddRange(new[] { assetItem.TypeString, assetItem.FullSize.ToString() });
2018-07-26 02:00:32 +00:00
//处理同名文件
2018-11-07 21:00:53 +00:00
if (!assetsNameHash.Add((assetItem.TypeString + assetItem.Text).ToUpper()))
2018-07-26 02:00:32 +00:00
{
2018-11-07 21:00:53 +00:00
assetItem.Text += " #" + assetItem.UniqueID;
2018-07-26 02:00:32 +00:00
}
//处理非法文件名
2018-11-07 21:00:53 +00:00
assetItem.Text = FixFileName(assetItem.Text);
2018-04-17 23:11:10 +00:00
if (displayAll)
{
exportable = true;
}
if (exportable)
{
2018-11-07 21:00:53 +00:00
tempExportableAssets.Add(assetItem);
}
2018-11-07 21:00:53 +00:00
objectReader.exportName = assetItem.Text;
2017-02-11 20:57:24 +00:00
ProgressBarPerformStep();
2018-11-07 21:00:53 +00:00
j++;
}
if (displayOriginalName)
{
2018-11-07 21:00:53 +00:00
foreach (var x in tempExportableAssets)
{
2018-11-07 21:00:53 +00:00
var replacename = ab?.m_Container.Find(y => y.second.asset.m_PathID == x.reader.m_PathID)?.first;
if (!string.IsNullOrEmpty(replacename))
2017-06-22 00:51:20 +00:00
{
var ex = Path.GetExtension(replacename);
x.Text = !string.IsNullOrEmpty(ex) ? replacename.Replace(ex, "") : replacename;
2018-11-07 21:00:53 +00:00
x.reader.exportName = x.Text;
2017-06-22 00:51:20 +00:00
}
2018-11-07 21:00:53 +00:00
}
}
2018-11-07 21:00:53 +00:00
exportableAssets.AddRange(tempExportableAssets);
tempExportableAssets.Clear();
}
2018-05-02 18:41:47 +00:00
visibleAssets = exportableAssets;
2018-07-26 02:00:32 +00:00
assetsNameHash.Clear();
}
2018-11-07 21:00:53 +00:00
// second loop - build tree structure
2018-04-21 13:52:15 +00:00
if (buildHierarchy)
{
2018-11-07 21:00:53 +00:00
var gameObjectCount = assetsfileList.Sum(x => x.GameObjects.Count);
2018-04-21 13:52:15 +00:00
if (gameObjectCount > 0)
{
2018-04-21 13:52:15 +00:00
SetProgressBarValue(0);
SetProgressBarMaximum(gameObjectCount);
StatusStripUpdate("Building tree structure...");
2018-04-21 13:52:15 +00:00
foreach (var assetsFile in assetsfileList)
{
2018-09-26 17:15:37 +00:00
var fileNode = new GameObjectTreeNode(null); //RootNode
fileNode.Text = assetsFile.fileName;
2018-04-21 13:52:15 +00:00
2018-11-07 21:00:53 +00:00
foreach (var m_GameObject in assetsFile.GameObjects.Values)
2018-03-01 12:01:25 +00:00
{
2018-04-21 13:52:15 +00:00
foreach (var m_Component in m_GameObject.m_Components)
2018-03-01 12:01:25 +00:00
{
2018-11-07 21:00:53 +00:00
if (m_Component.TryGet(out var asset))
2018-03-01 12:01:25 +00:00
{
2018-11-07 21:00:53 +00:00
switch (asset.type)
2018-03-01 12:01:25 +00:00
{
2018-10-16 16:43:34 +00:00
case ClassIDType.Transform:
{
m_GameObject.m_Transform = m_Component;
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.MeshRenderer:
{
m_GameObject.m_MeshRenderer = m_Component;
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.MeshFilter:
{
m_GameObject.m_MeshFilter = m_Component;
2018-11-07 21:00:53 +00:00
if (m_Component.TryGet(out var objectReader))
2018-04-21 13:52:15 +00:00
{
2018-11-07 21:00:53 +00:00
var m_MeshFilter = new MeshFilter(objectReader);
if (m_MeshFilter.m_Mesh.TryGet(out objectReader))
{
2018-11-07 21:00:53 +00:00
var item = tempDic[objectReader];
item.gameObject = m_GameObject;
}
}
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.SkinnedMeshRenderer:
{
m_GameObject.m_SkinnedMeshRenderer = m_Component;
2018-11-07 21:00:53 +00:00
if (m_Component.TryGet(out var objectReader))
{
2018-11-07 21:00:53 +00:00
var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(objectReader);
if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out objectReader))
{
2018-11-07 21:00:53 +00:00
var item = tempDic[objectReader];
item.gameObject = m_GameObject;
}
2018-04-21 13:52:15 +00:00
}
break;
}
2018-10-16 16:43:34 +00:00
case ClassIDType.Animator:
{
m_GameObject.m_Animator = m_Component;
2018-11-07 21:00:53 +00:00
var item = tempDic[asset];
item.Text = m_GameObject.reader.exportName;
asset.exportName = m_GameObject.reader.exportName;
break;
}
2018-03-01 12:01:25 +00:00
}
}
}
2018-04-21 13:52:15 +00:00
var parentNode = fileNode;
if (m_GameObject.m_Transform != null && m_GameObject.m_Transform.TryGetTransform(out var m_Transform))
{
if (m_Transform.m_Father.TryGetTransform(out var m_Father))
{
if (m_Father.m_GameObject.TryGetGameObject(out var parentGameObject))
2018-04-21 13:52:15 +00:00
{
2018-09-26 17:15:37 +00:00
if (!treeNodeDictionary.TryGetValue(parentGameObject, out parentNode))
{
parentNode = new GameObjectTreeNode(parentGameObject);
treeNodeDictionary.Add(parentGameObject, parentNode);
}
2018-04-21 13:52:15 +00:00
}
}
}
2018-09-26 17:15:37 +00:00
if (!treeNodeDictionary.TryGetValue(m_GameObject, out var currentNode))
{
currentNode = new GameObjectTreeNode(m_GameObject);
treeNodeDictionary.Add(m_GameObject, currentNode);
}
parentNode.Nodes.Add(currentNode);
2018-11-07 21:00:53 +00:00
2018-04-21 13:52:15 +00:00
ProgressBarPerformStep();
}
2018-04-21 13:52:15 +00:00
if (fileNode.Nodes.Count > 0)
{
2018-09-26 17:15:37 +00:00
treeNodeCollection.Add(fileNode);
2018-04-21 13:52:15 +00:00
}
}
}
}
2018-11-07 21:00:53 +00:00
tempDic.Clear();
2018-11-07 21:00:53 +00:00
// build list of class strucutres
2018-04-21 13:52:15 +00:00
if (buildClassStructures)
{
foreach (var assetsFile in assetsfileList)
{
2018-09-26 21:23:10 +00:00
if (AllTypeMap.TryGetValue(assetsFile.unityVersion, out var curVer))
{
2018-10-16 16:43:34 +00:00
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null))
{
2018-10-16 16:43:34 +00:00
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
curVer[key] = new TypeTreeItem(key, type.m_Nodes);
}
}
else
{
2018-10-16 16:43:34 +00:00
var items = new SortedDictionary<int, TypeTreeItem>();
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null))
{
var key = type.classID;
if (type.m_ScriptTypeIndex >= 0)
{
key = -1 - type.m_ScriptTypeIndex;
}
items.Add(key, new TypeTreeItem(key, type.m_Nodes));
}
AllTypeMap.Add(assetsFile.unityVersion, items);
}
}
}
}
2018-03-01 12:01:25 +00:00
public static string FixFileName(string str)
{
2018-03-01 12:01:25 +00:00
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
2018-03-01 12:01:25 +00:00
public static string[] ProcessingSplitFiles(List<string> selectFile)
{
var splitFiles = selectFile.Where(x => x.Contains(".split"))
.Select(x => Path.GetDirectoryName(x) + "\\" + Path.GetFileNameWithoutExtension(x))
.Distinct()
.ToList();
selectFile.RemoveAll(x => x.Contains(".split"));
foreach (var file in splitFiles)
{
if (File.Exists(file))
{
2018-03-01 12:01:25 +00:00
selectFile.Add(file);
}
}
return selectFile.Distinct().ToArray();
}
2018-04-09 20:45:09 +00:00
2018-11-07 21:00:53 +00:00
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, int assetGroupSelectedIndex, bool openAfterExport)
2018-04-09 20:45:09 +00:00
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
int toExport = toExportAssets.Count;
int exportedCount = 0;
SetProgressBarValue(0);
SetProgressBarMaximum(toExport);
foreach (var asset in toExportAssets)
{
var exportpath = savePath + "\\";
if (assetGroupSelectedIndex == 1)
{
exportpath += Path.GetFileNameWithoutExtension(asset.sourceFile.filePath) + "_export\\";
}
else if (assetGroupSelectedIndex == 0)
{
exportpath = savePath + "\\" + asset.TypeString + "\\";
}
StatusStripUpdate($"Exporting {asset.TypeString}: {asset.Text}");
2018-11-07 21:00:53 +00:00
var reader = asset.reader;
2018-07-26 02:00:32 +00:00
try
2018-04-09 20:45:09 +00:00
{
2018-07-26 02:00:32 +00:00
switch (asset.Type)
{
2018-10-16 16:43:34 +00:00
case ClassIDType.Texture2D:
2018-11-07 21:00:53 +00:00
if (ExportTexture2D(reader, exportpath, true))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.AudioClip:
2018-11-07 21:00:53 +00:00
if (ExportAudioClip(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.Shader:
2018-11-07 21:00:53 +00:00
if (ExportShader(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.TextAsset:
2018-11-07 21:00:53 +00:00
if (ExportTextAsset(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.MonoBehaviour:
2018-11-07 21:00:53 +00:00
if (ExportMonoBehaviour(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.Font:
2018-11-07 21:00:53 +00:00
if (ExportFont(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.Mesh:
2018-11-07 21:00:53 +00:00
if (ExportMesh(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.VideoClip:
2018-11-07 21:00:53 +00:00
if (ExportVideoClip(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.MovieTexture:
2018-11-07 21:00:53 +00:00
if (ExportMovieTexture(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.Sprite:
2018-11-07 21:00:53 +00:00
if (ExportSprite(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.Animator:
2018-11-07 21:00:53 +00:00
if (ExportAnimator(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-10-16 16:43:34 +00:00
case ClassIDType.AnimationClip:
2018-07-26 02:00:32 +00:00
break;
default:
2018-11-07 21:00:53 +00:00
if (ExportRawFile(reader, exportpath))
2018-07-26 02:00:32 +00:00
{
exportedCount++;
}
break;
2018-04-09 20:45:09 +00:00
2018-07-26 02:00:32 +00:00
}
}
catch (Exception ex)
{
MessageBox.Show($"Export {asset.Type}:{asset.Text} error\r\n{ex.Message}\r\n{ex.StackTrace}");
2018-04-09 20:45:09 +00:00
}
ProgressBarPerformStep();
}
var statusText = exportedCount == 0 ? "Nothing exported." : $"Finished exporting {exportedCount} assets.";
if (toExport > exportedCount)
{
statusText += $" {toExport - exportedCount} assets skipped (not extractable or files already exist)";
}
StatusStripUpdate(statusText);
if (openAfterExport && exportedCount > 0)
{
Process.Start(savePath);
}
});
}
2018-10-27 01:39:45 +00:00
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes)
2018-04-17 17:29:18 +00:00
{
ThreadPool.QueueUserWorkItem(state =>
2018-04-17 17:29:18 +00:00
{
2018-09-26 17:15:37 +00:00
foreach (GameObjectTreeNode node in nodes)
2018-04-17 17:29:18 +00:00
{
//遍历一级子节点
2018-09-26 17:15:37 +00:00
foreach (GameObjectTreeNode j in node.Nodes)
2018-04-18 00:19:30 +00:00
{
2018-07-14 21:15:05 +00:00
ProgressBarPerformStep();
//收集所有子节点
var gameObjects = new List<GameObject>();
CollectNode(j, gameObjects);
//跳过一些不需要导出的object
if (gameObjects.All(x => x.m_SkinnedMeshRenderer == null && x.m_MeshFilter == null))
continue;
//处理非法文件名
var filename = FixFileName(j.Text);
//每个文件存放在单独的文件夹
var targetPath = $"{savePath}{filename}\\";
//重名文件处理
for (int i = 1; ; i++)
2018-04-18 00:19:30 +00:00
{
if (Directory.Exists(targetPath))
{
targetPath = $"{savePath}{filename} ({i})\\";
}
else
{
break;
}
2018-04-18 00:19:30 +00:00
}
Directory.CreateDirectory(targetPath);
//导出FBX
StatusStripUpdate($"Exporting {filename}.fbx");
2018-10-27 01:39:45 +00:00
try
2018-05-02 18:41:47 +00:00
{
2018-10-27 01:39:45 +00:00
ExportGameObject(j.gameObject, targetPath);
}
catch (Exception ex)
{
MessageBox.Show($"{ex.Message}\r\n{ex.StackTrace}");
2018-05-02 18:41:47 +00:00
}
StatusStripUpdate($"Finished exporting {filename}.fbx");
2018-04-18 00:19:30 +00:00
}
}
2018-10-22 17:18:19 +00:00
StatusStripUpdate("Finished");
});
2018-04-18 00:19:30 +00:00
}
2018-09-26 17:15:37 +00:00
private static void CollectNode(GameObjectTreeNode node, List<GameObject> gameObjects)
2018-04-17 17:29:18 +00:00
{
2018-09-26 17:15:37 +00:00
gameObjects.Add(node.gameObject);
foreach (GameObjectTreeNode i in node.Nodes)
2018-04-17 17:29:18 +00:00
{
CollectNode(i, gameObjects);
}
}
2018-11-07 21:00:53 +00:00
public static void ExportAnimatorWithAnimationClip(AssetItem animator, List<AssetItem> animationList, string exportPath)
2018-04-09 20:45:09 +00:00
{
ThreadPool.QueueUserWorkItem(state =>
{
2018-04-17 23:11:10 +00:00
StatusStripUpdate($"Exporting {animator.Text}");
2018-04-09 20:45:09 +00:00
try
{
2018-11-07 21:00:53 +00:00
ExportAnimator(animator.reader, exportPath, animationList);
2018-04-17 23:11:10 +00:00
StatusStripUpdate($"Finished exporting {animator.Text}");
2018-04-09 20:45:09 +00:00
}
catch (Exception ex)
{
MessageBox.Show($"{ex.Message}\r\n{ex.StackTrace}");
2018-04-17 23:11:10 +00:00
StatusStripUpdate("Error in export");
2018-04-09 20:45:09 +00:00
}
ProgressBarPerformStep();
});
}
2018-04-11 07:52:37 +00:00
2018-11-07 21:00:53 +00:00
public static void ExportObjectsWithAnimationClip(string exportPath, TreeNodeCollection nodes, List<AssetItem> animationList = null)
2018-04-11 07:52:37 +00:00
{
ThreadPool.QueueUserWorkItem(state =>
2018-04-12 19:16:09 +00:00
{
var gameObjects = new List<GameObject>();
GetSelectedParentNode(nodes, gameObjects);
2018-07-24 05:02:08 +00:00
if (gameObjects.Count > 0)
{
2018-07-24 05:02:08 +00:00
SetProgressBarValue(0);
SetProgressBarMaximum(gameObjects.Count);
foreach (var gameObject in gameObjects)
{
2018-09-26 17:15:37 +00:00
StatusStripUpdate($"Exporting {gameObject.m_Name}");
2018-07-24 05:02:08 +00:00
try
{
ExportGameObject(gameObject, exportPath, animationList);
2018-09-26 17:15:37 +00:00
StatusStripUpdate($"Finished exporting {gameObject.m_Name}");
2018-07-24 05:02:08 +00:00
}
catch (Exception ex)
{
MessageBox.Show($"{ex.Message}\r\n{ex.StackTrace}");
StatusStripUpdate("Error in export");
}
ProgressBarPerformStep();
}
2018-07-24 05:02:08 +00:00
}
else
{
StatusStripUpdate("No Object can be exported.");
}
});
2018-04-17 23:11:10 +00:00
}
private static void GetSelectedParentNode(TreeNodeCollection nodes, List<GameObject> gameObjects)
2018-04-17 23:11:10 +00:00
{
2018-09-26 17:15:37 +00:00
foreach (GameObjectTreeNode i in nodes)
2018-04-17 23:11:10 +00:00
{
if (i.Checked)
{
2018-09-26 17:15:37 +00:00
gameObjects.Add(i.gameObject);
2018-04-17 23:11:10 +00:00
}
else
{
GetSelectedParentNode(i.Nodes, gameObjects);
2018-04-17 23:11:10 +00:00
}
2018-04-12 19:16:09 +00:00
}
2018-04-11 07:52:37 +00:00
}
}
}