81 Commits

Author SHA1 Message Date
VaDiM
bb7accd04d Update version to v0.18.0
- Updated dependencies
2024-04-04 22:44:20 +03:00
VaDiM
5120999026 Update readme and other text files 2024-04-04 21:55:59 +03:00
VaDiM
1fc504e587 Optimize memory consumption of swizzled textures 2024-04-02 00:40:24 +03:00
VaDiM
4e991d85fb More fixes for unity 2019.4 assets 2024-04-01 00:56:48 +03:00
VaDiM
29b4bb59a0 [GUI] Move "loading via typetree" option to a better place 2024-04-01 00:56:48 +03:00
VaDiM
9750f486d5 Fix moc3 export 2024-04-01 00:21:51 +03:00
VaDiM
97bbfe8fbb Fix type of public "offset" property in ResourceReader 2024-04-01 00:21:50 +03:00
VaDiM
684bf5a874 Show assumed unity ver in some cases for assets with stripped ver 2024-04-01 00:21:50 +03:00
VaDiM
3cc6bed844 Raplace Unity ver array with Unity ver class 2024-04-01 00:21:50 +03:00
VaDiM
c9e9bc840c Add parallel export support for some asset types 2024-04-01 00:21:50 +03:00
VaDiM
cadcf0b492 Fix displayed info for non-fmod audio clips 2024-03-28 01:52:43 +03:00
VaDiM
1e8085da2d Fix AssetBundle structure for Unity v5.4.x. Close #31 2024-03-28 01:52:43 +03:00
VaDiM
770d7e7532 [GUI] Fix compatibility with High Contrast modes 2024-03-15 18:19:05 +03:00
VaDiM
d0d8a35f67 [GUI] Fixes for Tex2DArrayImage 2024-03-14 00:42:56 +03:00
VaDiM
3f004f74d1 Add option to disable asset loading via typetree 2024-03-13 22:52:43 +03:00
VaDiM
3effd06e64 Unity 2023.2+ Texture2D fix 2024-03-13 22:52:43 +03:00
VaDiM
4f0afffeba Add AnimationClip loading via typetree 2024-03-13 22:52:43 +03:00
VaDiM
9b69b5607c Fix DisplayInfo default value in model3.json 2024-03-10 23:17:25 +03:00
VaDiM
9b16ea8d41 Fix bug with Blend type in l2d expressions 2024-03-09 22:47:11 +03:00
VaDiM
ae4548f1c3 Add support for swizzled Switch textures
Co-Authored-By: nesrak1 <12544505+nesrak1@users.noreply.github.com>
2024-03-09 02:35:23 +03:00
VaDiM
4cd246592b [CLI] Fix wrong error handler. Fix option description msgs 2024-03-07 04:38:39 +03:00
VaDiM
f54cc004bd Add support for Zstd block compression 2024-03-07 03:49:06 +03:00
VaDiM
afdc81bca8 Some minor fixes 2024-03-05 23:42:35 +03:00
VaDiM
045f6c0ff4 Add Texture2DArray loading via typetree 2024-03-05 23:42:29 +03:00
VaDiM
bc9380b8be Add Texture2D loading via typetree 2024-03-05 23:42:29 +03:00
VaDiM
46f8023756 [GUI] Improve export of Texture2DArray images
- Do not export an entire tex2darray array if both the tex2darray and some of its images were selected for exporting
2024-03-05 23:42:07 +03:00
VaDiM
0f9afa60d7 Add support for Texture2DArray 2024-03-04 19:46:28 +03:00
VaDiM
ec7f2c393d [CLI] Update readme 2024-02-13 05:43:34 +03:00
VaDiM
3ec8169b08 [GUI] Add more details to log when exporting assets 2024-02-13 04:55:25 +03:00
VaDiM
5c24183d18 Add more options to work with Scene Hierarchy (#23)
- Added option to group exported assets by node path in scene hierarchy
- Added field with node path to exported xml asset list
2024-02-13 04:52:59 +03:00
VaDiM
c68eaa5e3c Fixes for previous fixes 2024-02-13 04:51:14 +03:00
VaDiM
8460ecef8d Show/Export object dump if typetree dump is not available 2024-02-12 05:21:23 +03:00
VaDiM
f90c0ecc00 Add option to export assets with PathID in filename (#25)
https://github.com/Perfare/AssetStudio/issues/1050
https://github.com/Perfare/AssetStudio/issues/975
https://github.com/Perfare/AssetStudio/issues/762
2024-02-11 03:01:40 +03:00
VaDiM
535153be6b Add cdi3.json support for l2d export (beta) 2024-02-09 22:35:14 +03:00
VaDiM
d4162161be [GUI] Replace "Show all error msgs" option with "Show debug msgs" 2024-02-08 22:44:57 +03:00
VaDiM
6fe12d274f [CLI] Add colors to help message 2024-02-08 22:35:48 +03:00
VaDiM
70213e3012 Improve integration with Live2D assets
- Improved export method of AnimationClip motions
- [GUI] Added display of model info on the preview tab
- [GUI] Added support for partial export:
  - selected models
  - model + selected AnimationClip motions
  - model + selected Fade motions
  - model + selected Fade Motion List
2024-02-08 22:34:00 +03:00
VaDiM
2f6d9ec77f Fixes & Cleanup 2024-01-31 22:34:12 +03:00
VaDiM
0d2aebc1f4 Fix a bug where UV is exported incorrectly.
Co-Authored-By: Razmoth <32140579+razmoth@users.noreply.github.com>
2024-01-24 23:26:13 +03:00
VaDiM
115074fdc0 [GUI] Preserve selection order of AnimationClips (#24) 2023-12-30 18:51:01 +03:00
VaDiM
c2d3b8c5f9 Improve Live2D export 2023-12-30 18:13:40 +03:00
VaDiM
67a74fd395 Bugfix for unity 2022.2+ Texture2D reader 2023-12-30 17:08:07 +03:00
VaDiM
a00c857ac3 Update version to v0.17.4 2023-12-16 04:41:00 +03:00
VaDiM
5333757843 Update dependencies 2023-12-16 04:16:36 +03:00
VaDiM
4747687bec Update README.md 2023-12-15 15:11:48 +03:00
VaDiM
5c2ac1a5e8 Add .NET8 to the TargetFrameworks 2023-12-15 14:45:07 +03:00
VaDiM
e2eae53ac0 Update Live2DExtractor.cs 2023-12-15 01:24:54 +03:00
VaDiM
87347e8b60 [CLI] Update readme 2023-12-11 01:58:05 +03:00
VaDiM
0fdbddea55 [CLI] Fix asset filter for sprites 2023-12-11 01:58:00 +03:00
VaDiM
823190abb7 Improve parsing of Live2D Fade motions 2023-12-09 02:31:54 +03:00
VaDiM
60aef1b8ed [GUI] Add option to not build a tree structure 2023-12-09 02:25:59 +03:00
VaDiM
f82a73f018 [GUI] Add console logger 2023-12-06 17:28:10 +03:00
VaDiM
d42a1879ab [GUI] Add support for Drag&Drop files from a browser
Co-Authored-By: Luke <17146677+lukefz@users.noreply.github.com>
2023-12-05 00:38:24 +03:00
VaDiM
632e5f8d08 [GUI] Add support for .lnk files via Drag&Drop. Close #13 2023-12-04 04:10:49 +03:00
VaDiM
51d259464b Merge branch 'pr/16' into AssetStudioMod 2023-11-21 02:15:19 +03:00
VaDiM
efd06648ad Add support for separate PreloadData
https://github.com/Perfare/AssetStudio/issues/690

https://docs.unity.cn/550/Documentation/Manual/AssetBundleInternalStructure.html
2023-11-21 01:35:25 +03:00
VaDiM
b27482e22b Don't display SourceRevisionId in titles
https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/8.0/source-link
2023-11-21 00:31:09 +03:00
VaDiM
d572bd0e64 Add support for Live2D Fade motions 2023-11-20 19:56:41 +03:00
VaDiM
e415740373 Some fixes for Live2D export 2023-11-19 02:51:48 +03:00
VaDiM
45bf9251c9 Fix crash when SpriteAtlas is missing 2023-11-07 01:31:27 +03:00
Evaldas Ciakas
75ebe67713 Fix parsing secondary textures 2023-11-01 02:29:06 +02:00
VaDiM
ed7b0a2415 Unity 2022.2+ AnimationClip fix 2023-09-27 23:41:20 +03:00
VaDiM
22ab5c0633 Update README.md
- Added ArknightsStudio link
2023-09-24 16:19:09 +03:00
VaDiM
a2bc935850 [CLI] Improve help message 2023-09-24 16:14:26 +03:00
VaDiM
cb84c137e5 Add exception checking for gzip decompression 2023-09-24 10:41:19 +03:00
VaDiM
25c611fb9e Update README.md 2023-09-15 16:35:47 +03:00
VaDiM
6d3875cb2c Update version to v0.17.3 2023-09-13 10:55:57 +03:00
VaDiM
be4ced77ea Update readmes 2023-09-12 03:44:18 +03:00
VaDiM
2bd762e8f4 [CLI] Add names for AssetBundle and Animator assets 2023-09-12 03:33:59 +03:00
VaDiM
a926644ff6 [CLI] Add --load-all flag
- Added --load-all flag to load assets of all types
- Improved option grouping on the help screen
2023-09-12 03:33:53 +03:00
VaDiM
a4cdff5934 Fix a bit of incorrect copy-paste
in commit e216abd6be
2023-09-08 23:47:26 +03:00
VaDiM
2e10e627b0 AssemblyLoader fix (#6) 2023-09-08 06:18:41 +03:00
VaDiM
e216abd6be Unity 2022.2+ Texture2D fix 2023-09-08 06:18:34 +03:00
VaDiM
93c7e617d8 [CLI] Show names of all loaded assets in the exported asset list 2023-09-08 06:18:34 +03:00
VaDiM
000916913e [CLI] Fix a bug where the default output folder might not exist 2023-09-08 06:17:34 +03:00
VaDiM
28f9744497 Update README.md 2023-09-08 06:17:34 +03:00
VaDiM
c3f99216b6 [CLI] Add --filter-by-name support for fbx export mode 2023-09-08 01:45:25 +03:00
VaDiM
19c4835ea3 Merge branch 'pr/10' into AssetStudioMod 2023-09-05 19:38:04 +03:00
VaDiM
6b321da695 [CLI] Add FBX native libs (Linux, Mac) 2023-09-05 00:48:44 +03:00
svn
7cca301f7a Add split object fbx export to CLI 2023-08-31 21:07:02 +01:00
svn
5ac597c935 Add CMakeLists for cross platform FBXNative build 2023-08-31 21:03:07 +01:00
109 changed files with 7892 additions and 2195 deletions

View File

@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.2.0</Version>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@@ -22,26 +22,26 @@ namespace SevenZip
}
}
uint _value = 0xFFFFFFFF;
private uint _value = 0xFFFFFFFF;
public void Init() { _value = 0xFFFFFFFF; }
public void UpdateByte(byte b)
{
_value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
_value = Table[(byte)_value ^ b] ^ (_value >> 8);
}
public void Update(byte[] data, uint offset, uint size)
{
for (uint i = 0; i < size; i++)
_value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
_value = Table[(byte)_value ^ data[offset + i]] ^ (_value >> 8);
}
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
static uint CalculateDigest(byte[] data, uint offset, uint size)
public static uint CalculateDigest(byte[] data, uint offset, uint size)
{
CRC crc = new CRC();
var crc = new CRC();
// crc.Init();
crc.Update(data, offset, size);
return crc.GetDigest();
@@ -49,7 +49,7 @@ namespace SevenZip
static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
{
return (CalculateDigest(data, offset, size) == digest);
return CalculateDigest(data, offset, size) == digest;
}
}
}

View File

@@ -1,20 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023-2024</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
<PackageReference Include="ZstdSharp.Port" Version="0.7.6" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.1.11" />
<PackageReference Include="ZstdSharp.Port" Version="0.6.5" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
@@ -10,18 +11,48 @@ namespace AssetStudio
{
public class AssetsManager
{
public string SpecifyUnityVersion;
public bool ZstdEnabled = true;
public bool LoadingViaTypeTreeEnabled = true;
public List<SerializedFile> assetsFileList = new List<SerializedFile>();
private HashSet<ClassIDType> filteredAssetTypesList = new HashSet<ClassIDType>();
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
internal ConcurrentDictionary<string, BinaryReader> resourceFileReaders = new ConcurrentDictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
private UnityVersion specifiedUnityVersion;
private List<string> importFiles = new List<string>();
private HashSet<ClassIDType> filteredAssetTypesList = new HashSet<ClassIDType>();
private HashSet<string> importFilesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> noexistFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public UnityVersion SpecifyUnityVersion
{
get => specifiedUnityVersion;
set
{
if (specifiedUnityVersion == value)
{
return;
}
if (value == null)
{
specifiedUnityVersion = null;
Logger.Info("Specified Unity version: None");
return;
}
if (string.IsNullOrEmpty(value.BuildType))
{
throw new NotSupportedException("Specified Unity version is not in a correct format.\n" +
"Specify full Unity version, including letters at the end.\n" +
"Example: 2017.4.39f1");
}
specifiedUnityVersion = value;
Logger.Info($"Specified Unity version: {specifiedUnityVersion}");
}
}
public void SetAssetFilter(params ClassIDType[] classIDTypes)
{
if (filteredAssetTypesList.Count == 0)
@@ -30,6 +61,8 @@ namespace AssetStudio
{
ClassIDType.AssetBundle,
ClassIDType.ResourceManager,
ClassIDType.GameObject,
ClassIDType.Transform,
});
}
@@ -40,8 +73,9 @@ namespace AssetStudio
if (classIDTypes.Contains(ClassIDType.Sprite))
{
filteredAssetTypesList.Add(ClassIDType.Texture2D);
filteredAssetTypesList.Add(ClassIDType.SpriteAtlas);
}
filteredAssetTypesList.UnionWith(classIDTypes);
}
@@ -52,21 +86,21 @@ namespace AssetStudio
public void LoadFilesAndFolders(params string[] path)
{
List<string> pathList = new List<string>();
var pathList = new List<string>();
pathList.AddRange(path);
LoadFilesAndFolders(out _, pathList);
}
public void LoadFilesAndFolders(out string parentPath, params string[] path)
{
List<string> pathList = new List<string>();
var pathList = new List<string>();
pathList.AddRange(path);
LoadFilesAndFolders(out parentPath, pathList);
}
public void LoadFilesAndFolders(out string parentPath, List<string> pathList)
{
List<string> fileList = new List<string>();
var fileList = new List<string>();
bool filesInPath = false;
parentPath = "";
foreach (var path in pathList)
@@ -82,7 +116,7 @@ namespace AssetStudio
MergeSplitAssets(fullPath, true);
fileList.AddRange(Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories));
}
else
else if (File.Exists(fullPath))
{
parentPath = Path.GetDirectoryName(fullPath);
fileList.Add(fullPath);
@@ -112,8 +146,14 @@ namespace AssetStudio
//use a for loop because list size can change
for (var i = 0; i < importFiles.Count; i++)
{
LoadFile(importFiles[i]);
Progress.Report(i + 1, importFiles.Count);
if (LoadFile(importFiles[i]))
{
Progress.Report(i + 1, importFiles.Count);
}
else
{
break;
}
}
importFiles.Clear();
@@ -125,22 +165,20 @@ namespace AssetStudio
ProcessAssets();
}
private void LoadFile(string fullName)
private bool LoadFile(string fullName)
{
var reader = new FileReader(fullName);
LoadFile(reader);
return LoadFile(reader);
}
private void LoadFile(FileReader reader)
private bool LoadFile(FileReader reader)
{
switch (reader.FileType)
switch (reader?.FileType)
{
case FileType.AssetsFile:
LoadAssetsFile(reader);
break;
return LoadAssetsFile(reader);
case FileType.BundleFile:
LoadBundleFile(reader);
break;
return LoadBundleFile(reader);
case FileType.WebFile:
LoadWebFile(reader);
break;
@@ -154,9 +192,10 @@ namespace AssetStudio
LoadZipFile(reader);
break;
}
return true;
}
private void LoadAssetsFile(FileReader reader)
private bool LoadAssetsFile(FileReader reader)
{
if (!assetsFileListHash.Contains(reader.FileName))
{
@@ -164,6 +203,7 @@ namespace AssetStudio
try
{
var assetsFile = new SerializedFile(reader, this);
var dirName = Path.GetDirectoryName(reader.FullPath);
CheckStrippedVersion(assetsFile);
assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.fileName);
@@ -174,12 +214,12 @@ namespace AssetStudio
if (!importFilesHash.Contains(sharedFileName))
{
var sharedFilePath = Path.Combine(Path.GetDirectoryName(reader.FullPath), sharedFileName);
var sharedFilePath = Path.Combine(dirName, sharedFileName);
if (!noexistFiles.Contains(sharedFilePath))
{
if (!File.Exists(sharedFilePath))
{
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
var findFiles = Directory.GetFiles(dirName, sharedFileName, SearchOption.AllDirectories);
if (findFiles.Length > 0)
{
sharedFilePath = findFiles[0];
@@ -202,10 +242,11 @@ namespace AssetStudio
{
Logger.Error(e.Message);
reader.Dispose();
return false;
}
catch (Exception e)
{
Logger.Warning($"Error while reading assets file {reader.FullPath}\r\n{e}");
Logger.Warning($"Failed to read assets file {reader.FullPath}\r\n{e}");
reader.Dispose();
}
}
@@ -214,9 +255,10 @@ namespace AssetStudio
Logger.Info($"Skipping {reader.FullPath}");
reader.Dispose();
}
return true;
}
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null)
private bool LoadAssetsFromMemory(FileReader reader, string originalPath, UnityVersion assetBundleUnityVer = null)
{
if (!assetsFileListHash.Contains(reader.FileName))
{
@@ -224,52 +266,59 @@ namespace AssetStudio
{
var assetsFile = new SerializedFile(reader, this);
assetsFile.originalPath = originalPath;
if (!string.IsNullOrEmpty(unityVersion) && assetsFile.header.m_Version < SerializedFileFormatVersion.Unknown_7)
if (assetBundleUnityVer != null && assetsFile.header.m_Version < SerializedFileFormatVersion.Unknown_7)
{
assetsFile.SetVersion(unityVersion);
assetsFile.SetVersion(assetBundleUnityVer);
}
CheckStrippedVersion(assetsFile);
CheckStrippedVersion(assetsFile, assetBundleUnityVer);
assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.fileName);
}
catch (NotSupportedException e)
{
Logger.Error(e.Message);
resourceFileReaders.Add(reader.FileName, reader);
resourceFileReaders.TryAdd(reader.FileName, reader);
return false;
}
catch (Exception e)
{
Logger.Warning($"Error while reading assets file {reader.FullPath} from {Path.GetFileName(originalPath)}\r\n{e}");
resourceFileReaders.Add(reader.FileName, reader);
Logger.Warning($"Failed to read assets file {reader.FullPath} from {Path.GetFileName(originalPath)}\r\n{e}");
resourceFileReaders.TryAdd(reader.FileName, reader);
}
}
else
{
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
}
return true;
}
private void LoadBundleFile(FileReader reader, string originalPath = null)
private bool LoadBundleFile(FileReader reader, string originalPath = null)
{
Logger.Info("Loading " + reader.FullPath);
try
{
var bundleFile = new BundleFile(reader, SpecifyUnityVersion);
var bundleFile = new BundleFile(reader, ZstdEnabled, specifiedUnityVersion);
foreach (var file in bundleFile.fileList)
{
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
var subReader = new FileReader(dummyPath, file.stream);
if (subReader.FileType == FileType.AssetsFile)
{
LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision);
if (!LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision))
return false;
}
else if (!resourceFileReaders.ContainsKey(file.fileName))
else
{
resourceFileReaders.Add(file.fileName, subReader);
resourceFileReaders.TryAdd(file.fileName, subReader);
}
}
return true;
}
catch (NotSupportedException e)
{
Logger.Error(e.Message);
return false;
}
catch (Exception e)
{
@@ -279,6 +328,7 @@ namespace AssetStudio
str += $" from {Path.GetFileName(originalPath)}";
}
Logger.Warning($"{str}\r\n{e}");
return true;
}
finally
{
@@ -403,10 +453,7 @@ namespace AssetStudio
if (entryReader.FileType == FileType.ResourceFile)
{
entryReader.Position = 0;
if (!resourceFileReaders.ContainsKey(entry.Name))
{
resourceFileReaders.Add(entry.Name, entryReader);
}
resourceFileReaders.TryAdd(entry.Name, entryReader);
}
Progress.Report(++k, progressCount);
}
@@ -427,13 +474,16 @@ namespace AssetStudio
}
}
public void CheckStrippedVersion(SerializedFile assetsFile)
public void CheckStrippedVersion(SerializedFile assetsFile, UnityVersion bundleUnityVer = null)
{
if (assetsFile.IsVersionStripped && string.IsNullOrEmpty(SpecifyUnityVersion))
if (assetsFile.version.IsStripped && specifiedUnityVersion == null)
{
throw new NotSupportedException("The Unity version has been stripped, please set the version in the options");
var msg = "The asset's Unity version has been stripped, please set the version in the options.";
if (bundleUnityVer != null && !bundleUnityVer.IsStripped)
msg += $"\n\nAssumed Unity version based on asset bundle: {bundleUnityVer}";
throw new NotSupportedException(msg);
}
if (!string.IsNullOrEmpty(SpecifyUnityVersion))
if (specifiedUnityVersion != null)
{
assetsFile.SetVersion(SpecifyUnityVersion);
}
@@ -482,7 +532,9 @@ namespace AssetStudio
obj = new Animation(objectReader);
break;
case ClassIDType.AnimationClip:
obj = new AnimationClip(objectReader);
obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled
? new AnimationClip(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader))
: new AnimationClip(objectReader);
break;
case ClassIDType.Animator:
obj = new Animator(objectReader);
@@ -532,11 +584,14 @@ namespace AssetStudio
case ClassIDType.PlayerSettings:
obj = new PlayerSettings(objectReader);
break;
case ClassIDType.PreloadData:
obj = new PreloadData(objectReader);
break;
case ClassIDType.RectTransform:
obj = new RectTransform(objectReader);
break;
case ClassIDType.Shader:
if (objectReader.version[0] < 2021)
if (objectReader.version < 2021)
obj = new Shader(objectReader);
break;
case ClassIDType.SkinnedMeshRenderer:
@@ -552,7 +607,14 @@ namespace AssetStudio
obj = new TextAsset(objectReader);
break;
case ClassIDType.Texture2D:
obj = new Texture2D(objectReader);
obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled
? new Texture2D(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader))
: new Texture2D(objectReader);
break;
case ClassIDType.Texture2DArray:
obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled
? new Texture2DArray(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader))
: new Texture2DArray(objectReader);
break;
case ClassIDType.Transform:
obj = new Transform(objectReader);
@@ -568,7 +630,9 @@ namespace AssetStudio
break;
}
if (obj != null)
{
assetsFile.AddObject(obj);
}
}
catch (Exception e)
{
@@ -635,14 +699,17 @@ namespace AssetStudio
{
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
}
else
else if (m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld))
{
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
if (m_SpriteAtlaOld.m_IsVariant)
{
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
}
}
else
{
Logger.Warning($"\"{m_Sprite.m_Name}\": Sprite loading error. SpriteAtlas with PathID: \"{m_Sprite.m_SpriteAtlas.m_PathID}\" was not found.");
}
}
}
}

View File

@@ -4,7 +4,11 @@ namespace AssetStudio
{
public static class BigArrayPool<T>
{
private static readonly ArrayPool<T> s_shared = ArrayPool<T>.Create(64 * 1024 * 1024, 3);
public static ArrayPool<T> Shared => s_shared;
public static ArrayPool<T> Shared { get; }
static BigArrayPool()
{
Shared = ArrayPool<T>.Create(256 * 1024 * 1024, 5);
}
}
}

View File

@@ -1,4 +1,5 @@
using K4os.Compression.LZ4;
using ZstdSharp;
using System;
using System.IO;
using System.Linq;
@@ -35,7 +36,8 @@ namespace AssetStudio
Lzma,
Lz4,
Lz4HC,
Lzham
Lzham,
Custom,
}
public class BundleFile
@@ -45,7 +47,7 @@ namespace AssetStudio
public string signature;
public uint version;
public string unityVersion;
public string unityRevision;
public UnityVersion unityRevision;
public long size;
public uint compressedBlocksInfoSize;
public uint uncompressedBlocksInfoSize;
@@ -73,13 +75,13 @@ namespace AssetStudio
public StreamFile[] fileList;
public BundleFile(FileReader reader, string specUnityVer = "")
public BundleFile(FileReader reader, bool useZstd, UnityVersion specUnityVer = null)
{
m_Header = new Header();
m_Header.signature = reader.ReadStringToNull();
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
m_Header.unityRevision = new UnityVersion(reader.ReadStringToNull());
switch (m_Header.signature)
{
case "UnityArchive":
@@ -100,40 +102,54 @@ namespace AssetStudio
case "UnityFS":
ReadHeader(reader);
bool isUnityCnEnc = false;
string unityVer = string.IsNullOrEmpty(specUnityVer) ? m_Header.unityRevision : specUnityVer;
int[] ver = new string(unityVer.SkipWhile(x => !char.IsDigit(x)).TakeWhile(x => char.IsDigit(x) || x == '.').ToArray()).Split('.').Select(x => int.Parse(x)).ToArray();
if (ver[0] != 0)
var isUnityCnEnc = false;
var unityVer = m_Header.unityRevision;
if (specUnityVer != null)
{
if (!unityVer.IsStripped && specUnityVer != unityVer)
{
Logger.Warning($"Detected Unity version is different from the specified one ({specUnityVer.FullVersion.Color(ColorConsole.BrightCyan)}).\n" +
$"Assets may load with errors.\n" +
$"It is recommended to specify the detected Unity version: {unityVer.FullVersion.Color(ColorConsole.BrightCyan)}");
}
unityVer = specUnityVer;
}
if (!unityVer.IsStripped)
{
// https://issuetracker.unity3d.com/issues/files-within-assetbundles-do-not-start-on-aligned-boundaries-breaking-patching-on-nintendo-switch
if (ver[0] < 2020 ||
(ver[0] == 2020 && ver[1] <= 3 && ver[2] < 34) ||
(ver[0] == 2021 && ver[1] <= 3 && ver[2] < 2) ||
(ver[0] == 2022 && ver[1] <= 1 && ver[2] < 1))
if (unityVer < 2020
|| unityVer.IsInRange(2020, (2020, 3, 34))
|| unityVer.IsInRange(2021, (2021, 3, 2))
|| unityVer.IsInRange(2022, (2022, 1, 1)))
{
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.OldFlag) != 0;
}
else
{
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.NewFlag) != 0;
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.NewFlag) != 0;
}
}
if (isUnityCnEnc)
{
throw new NotSupportedException("Unsupported bundle file. UnityCN encryption was detected.");
var msg = "Unsupported bundle file. ";
msg += specUnityVer != null
? "UnityCN encryption was detected or the specified Unity version is incorrect."
: "UnityCN encryption was detected.";
throw new NotSupportedException(msg);
}
ReadBlocksInfoAndDirectory(reader, ver);
ReadBlocksInfoAndDirectory(reader, unityVer);
using (var blocksStream = CreateBlocksStream(reader.FullPath))
{
ReadBlocks(reader, blocksStream);
ReadBlocks(reader, blocksStream, useZstd);
ReadFiles(blocksStream, reader.FullPath);
}
break;
}
}
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
private void ReadHeaderAndBlocksInfo(FileReader reader)
{
if (m_Header.version >= 4)
{
@@ -185,7 +201,7 @@ namespace AssetStudio
return blocksStream;
}
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
private void ReadBlocksAndDirectory(FileReader reader, Stream blocksStream)
{
var isCompressed = m_Header.signature == "UnityWeb";
foreach (var blockInfo in m_BlocksInfo)
@@ -246,7 +262,7 @@ namespace AssetStudio
}
}
private void ReadHeader(EndianBinaryReader reader)
private void ReadHeader(FileReader reader)
{
m_Header.size = reader.ReadInt64();
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
@@ -258,7 +274,7 @@ namespace AssetStudio
}
}
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader, int[] unityVer)
private void ReadBlocksInfoAndDirectory(FileReader reader, UnityVersion unityVer)
{
byte[] blocksInfoBytes;
@@ -266,7 +282,7 @@ namespace AssetStudio
{
reader.AlignStream(16);
}
else if (unityVer[0] >= 2019 && unityVer[1] >= 4)
else if (unityVer >= (2019, 4) && m_Header.flags != ArchiveFlags.BlocksAndDirectoryInfoCombined)
{
//check if we need to align the reader
//- align to 16 bytes and check if all are 0
@@ -290,42 +306,44 @@ namespace AssetStudio
{
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
}
MemoryStream blocksInfoUncompresseddStream;
MemoryStream blocksInfoUncompressedStream;
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
switch (compressionType)
{
case CompressionType.None:
{
blocksInfoUncompresseddStream = new MemoryStream(blocksInfoBytes);
break;
}
{
blocksInfoUncompressedStream = new MemoryStream(blocksInfoBytes);
break;
}
case CompressionType.Lzma:
{
blocksInfoUncompressedStream = new MemoryStream((int) (uncompressedSize));
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
{
blocksInfoUncompresseddStream = new MemoryStream((int)(uncompressedSize));
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
{
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
}
blocksInfoUncompresseddStream.Position = 0;
break;
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompressedStream,
m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
}
blocksInfoUncompressedStream.Position = 0;
break;
}
case CompressionType.Lz4:
case CompressionType.Lz4HC:
{
var uncompressedBytes = new byte[uncompressedSize];
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
if (numWrite != uncompressedSize)
{
var uncompressedBytes = new byte[uncompressedSize];
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
if (numWrite != uncompressedSize)
{
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
}
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
break;
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
}
blocksInfoUncompressedStream = new MemoryStream(uncompressedBytes);
break;
}
default:
throw new IOException($"Unsupported compression type {compressionType}");
throw new IOException($"Unsupported block info compression type {compressionType}");
}
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompressedStream))
{
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
var blocksInfoCount = blocksInfoReader.ReadInt32();
@@ -359,43 +377,72 @@ namespace AssetStudio
}
}
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
private void ReadBlocks(FileReader reader, Stream blocksStream, bool useZstd)
{
var zstdCodec = new Decompressor();
var i = 0;
foreach (var blockInfo in m_BlocksInfo)
{
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
switch (compressionType)
{
case CompressionType.None:
{
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
break;
}
{
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
break;
}
case CompressionType.Lzma:
{
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
{
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
case CompressionType.Lz4:
case CompressionType.Lz4HC:
case CompressionType.Custom:
{
var compressedSize = (int)blockInfo.compressedSize;
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
_ = reader.Read(compressedBytes, 0, compressedSize);
var uncompressedSize = (int)blockInfo.uncompressedSize;
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
try
{
var compressedSize = (int)blockInfo.compressedSize;
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
reader.Read(compressedBytes, 0, compressedSize);
var uncompressedSize = (int)blockInfo.uncompressedSize;
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
var compTypeStr = compressionType.ToString();
if (compressionType == CompressionType.Custom)
{
compTypeStr = useZstd ? "Zstd" : "Lz4";
if (i == 0)
{
Logger.Debug($"Custom block compression type was detected. Trying to decompress as {compTypeStr} archive..");
i++;
}
}
int numWrite;
if (compressionType == CompressionType.Custom && useZstd)
{
numWrite = zstdCodec.Unwrap(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
}
else
{
numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
}
if (numWrite != uncompressedSize)
{
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
throw new IOException($"{compTypeStr} block decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
}
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
BigArrayPool<byte>.Shared.Return(compressedBytes);
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
break;
}
finally
{
BigArrayPool<byte>.Shared.Return(compressedBytes, clearArray: true);
BigArrayPool<byte>.Shared.Return(uncompressedBytes, clearArray: true);
}
break;
}
default:
throw new IOException($"Unsupported compression type {compressionType}");
throw new IOException($"Unsupported block compression type {compressionType}");
}
}
blocksStream.Position = 0;

View File

@@ -145,6 +145,7 @@ namespace AssetStudio
ProceduralMaterial = 185,
ProceduralTexture = 186,
Texture2DArray = 187,
Texture2DArrayImage = -187, //fake type
CubemapArray = 188,
OffMeshLink = 191,
OcclusionArea = 192,

View File

@@ -1,4 +1,6 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -15,6 +17,7 @@ namespace AssetStudio
public T inWeight;
public T outWeight;
public Keyframe() { }
public Keyframe(ObjectReader reader, Func<T> readerFunc)
{
@@ -22,7 +25,7 @@ namespace AssetStudio
value = readerFunc();
inSlope = readerFunc();
outSlope = readerFunc();
if (reader.version[0] >= 2018) //2018 and up
if (reader.version >= 2018) //2018 and up
{
weightedMode = reader.ReadInt32();
inWeight = readerFunc();
@@ -38,6 +41,8 @@ namespace AssetStudio
public int m_PostInfinity;
public int m_RotationOrder;
public AnimationCurve() { }
public AnimationCurve(ObjectReader reader, Func<T> readerFunc)
{
var version = reader.version;
@@ -50,7 +55,7 @@ namespace AssetStudio
m_PreInfinity = reader.ReadInt32();
m_PostInfinity = reader.ReadInt32();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3))//5.3 and up
if (version >= (5, 3)) //5.3 and up
{
m_RotationOrder = reader.ReadInt32();
}
@@ -62,6 +67,8 @@ namespace AssetStudio
public AnimationCurve<Quaternion> curve;
public string path;
public QuaternionCurve() { }
public QuaternionCurve(ObjectReader reader)
{
curve = new AnimationCurve<Quaternion>(reader, reader.ReadQuaternion);
@@ -77,6 +84,8 @@ namespace AssetStudio
public byte[] m_Data;
public byte m_BitSize;
public PackedFloatVector() { }
public PackedFloatVector(ObjectReader reader)
{
m_NumItems = reader.ReadUInt32();
@@ -136,6 +145,8 @@ namespace AssetStudio
public byte[] m_Data;
public byte m_BitSize;
public PackedIntVector() { }
public PackedIntVector(ObjectReader reader)
{
m_NumItems = reader.ReadUInt32();
@@ -180,6 +191,8 @@ namespace AssetStudio
public uint m_NumItems;
public byte[] m_Data;
public PackedQuatVector() { }
public PackedQuatVector(ObjectReader reader)
{
m_NumItems = reader.ReadUInt32();
@@ -264,6 +277,8 @@ namespace AssetStudio
public int m_PreInfinity;
public int m_PostInfinity;
public CompressedAnimationCurve() { }
public CompressedAnimationCurve(ObjectReader reader)
{
m_Path = reader.ReadAlignedString();
@@ -280,6 +295,8 @@ namespace AssetStudio
public AnimationCurve<Vector3> curve;
public string path;
public Vector3Curve() { }
public Vector3Curve(ObjectReader reader)
{
curve = new AnimationCurve<Vector3>(reader, reader.ReadVector3);
@@ -294,15 +311,22 @@ namespace AssetStudio
public string path;
public ClassIDType classID;
public PPtr<MonoScript> script;
public int flags;
public FloatCurve() { }
public FloatCurve(ObjectReader reader)
{
var version = reader.version;
curve = new AnimationCurve<float>(reader, reader.ReadSingle);
attribute = reader.ReadAlignedString();
path = reader.ReadAlignedString();
classID = (ClassIDType)reader.ReadInt32();
script = new PPtr<MonoScript>(reader);
if (version >= (2022, 2)) //2022.2 and up
{
flags = reader.ReadInt32();
}
}
}
@@ -311,6 +335,7 @@ namespace AssetStudio
public float time;
public PPtr<Object> value;
public PPtrKeyframe() { }
public PPtrKeyframe(ObjectReader reader)
{
@@ -326,10 +351,13 @@ namespace AssetStudio
public string path;
public int classID;
public PPtr<MonoScript> script;
public int flags;
public PPtrCurve() { }
public PPtrCurve(ObjectReader reader)
{
var version = reader.version;
int numCurves = reader.ReadInt32();
curve = new PPtrKeyframe[numCurves];
for (int i = 0; i < numCurves; i++)
@@ -341,6 +369,10 @@ namespace AssetStudio
path = reader.ReadAlignedString();
classID = reader.ReadInt32();
script = new PPtr<MonoScript>(reader);
if (version >= (2022, 2)) //2022.2 and up
{
flags = reader.ReadInt32();
}
}
}
@@ -349,6 +381,8 @@ namespace AssetStudio
public Vector3 m_Center;
public Vector3 m_Extent;
public AABB() { }
public AABB(ObjectReader reader)
{
m_Center = reader.ReadVector3();
@@ -362,12 +396,14 @@ namespace AssetStudio
public Quaternion q;
public Vector3 s;
public xform() { }
public xform(ObjectReader reader)
{
var version = reader.version;
t = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
t = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
q = reader.ReadQuaternion();
s = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
s = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
}
}
@@ -380,6 +416,8 @@ namespace AssetStudio
public float m_InOut;
public float m_Grab;
public HandPose() { }
public HandPose(ObjectReader reader)
{
m_GrabX = new xform(reader);
@@ -399,15 +437,17 @@ namespace AssetStudio
public Vector3 m_HintT;
public float m_HintWeightT;
public HumanGoal() { }
public HumanGoal(ObjectReader reader)
{
var version = reader.version;
m_X = new xform(reader);
m_WeightT = reader.ReadSingle();
m_WeightR = reader.ReadSingle();
if (version[0] >= 5)//5.0 and up
if (version >= 5)//5.0 and up
{
m_HintT = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_HintT = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_HintWeightT = reader.ReadSingle();
}
}
@@ -424,11 +464,13 @@ namespace AssetStudio
public float[] m_DoFArray;
public Vector3[] m_TDoFArray;
public HumanPose() { }
public HumanPose(ObjectReader reader)
{
var version = reader.version;
m_RootX = new xform(reader);
m_LookAtPosition = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_LookAtPosition = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_LookAtWeight = reader.ReadVector4();
int numGoals = reader.ReadInt32();
@@ -443,13 +485,13 @@ namespace AssetStudio
m_DoFArray = reader.ReadSingleArray();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2))//5.2 and up
if (version >= (5, 2))//5.2 and up
{
int numTDof = reader.ReadInt32();
m_TDoFArray = new Vector3[numTDof];
for (int i = 0; i < numTDof; i++)
{
m_TDoFArray[i] = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_TDoFArray[i] = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
}
}
}
@@ -460,6 +502,8 @@ namespace AssetStudio
public uint[] data;
public uint curveCount;
public StreamedClip() { }
public StreamedClip(ObjectReader reader)
{
data = reader.ReadUInt32Array();
@@ -475,6 +519,8 @@ namespace AssetStudio
public float outSlope;
public float inSlope;
public StreamedCurveKey() { }
public StreamedCurveKey(BinaryReader reader)
{
index = reader.ReadInt32();
@@ -506,6 +552,8 @@ namespace AssetStudio
public float time;
public StreamedCurveKey[] keyList;
public StreamedFrame() { }
public StreamedFrame(BinaryReader reader)
{
time = reader.ReadSingle();
@@ -561,6 +609,8 @@ namespace AssetStudio
public float m_BeginTime;
public float[] m_SampleArray;
public DenseClip() { }
public DenseClip(ObjectReader reader)
{
m_FrameCount = reader.ReadInt32();
@@ -575,6 +625,8 @@ namespace AssetStudio
{
public float[] data;
public ConstantClip() { }
public ConstantClip(ObjectReader reader)
{
data = reader.ReadSingleArray();
@@ -588,11 +640,13 @@ namespace AssetStudio
public uint m_Type;
public uint m_Index;
public ValueConstant() { }
public ValueConstant(ObjectReader reader)
{
var version = reader.version;
m_ID = reader.ReadUInt32();
if (version[0] < 5 || (version[0] == 5 && version[1] < 5))//5.5 down
if (version < (5, 5)) //5.5 down
{
m_TypeID = reader.ReadUInt32();
}
@@ -605,6 +659,8 @@ namespace AssetStudio
{
public ValueConstant[] m_ValueArray;
public ValueArrayConstant() { }
public ValueArrayConstant(ObjectReader reader)
{
int numVals = reader.ReadInt32();
@@ -616,6 +672,18 @@ namespace AssetStudio
}
}
public class OffsetPtr
{
public Clip data;
public OffsetPtr() { }
public OffsetPtr(ObjectReader reader)
{
data = new Clip(reader);
}
}
public class Clip
{
public StreamedClip m_StreamedClip;
@@ -623,16 +691,18 @@ namespace AssetStudio
public ConstantClip m_ConstantClip;
public ValueArrayConstant m_Binding;
public Clip() { }
public Clip(ObjectReader reader)
{
var version = reader.version;
m_StreamedClip = new StreamedClip(reader);
m_DenseClip = new DenseClip(reader);
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_ConstantClip = new ConstantClip(reader);
}
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 3)) //2018.3 down
if (version < (2018, 3)) //2018.3 down
{
m_Binding = new ValueArrayConstant(reader);
}
@@ -688,6 +758,8 @@ namespace AssetStudio
public float m_Start;
public float m_Stop;
public ValueDelta() { }
public ValueDelta(ObjectReader reader)
{
m_Start = reader.ReadSingle();
@@ -705,7 +777,7 @@ namespace AssetStudio
public xform m_MotionStartX;
public xform m_MotionStopX;
public Vector3 m_AverageSpeed;
public Clip m_Clip;
public OffsetPtr m_Clip;
public float m_StartTime;
public float m_StopTime;
public float m_OrientationOffsetY;
@@ -727,24 +799,26 @@ namespace AssetStudio
public bool m_KeepOriginalPositionXZ;
public bool m_HeightFromFeet;
public ClipMuscleConstant() { }
public ClipMuscleConstant(ObjectReader reader)
{
var version = reader.version;
m_DeltaPose = new HumanPose(reader);
m_StartX = new xform(reader);
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5))//5.5 and up
if (version >= (5, 5)) //5.5 and up
{
m_StopX = new xform(reader);
}
m_LeftFootStartX = new xform(reader);
m_RightFootStartX = new xform(reader);
if (version[0] < 5)//5.0 down
if (version < 5)//5.0 down
{
m_MotionStartX = new xform(reader);
m_MotionStopX = new xform(reader);
}
m_AverageSpeed = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_Clip = new Clip(reader);
m_AverageSpeed = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4();//5.4 and up
m_Clip = new OffsetPtr(reader);
m_StartTime = reader.ReadSingle();
m_StopTime = reader.ReadSingle();
m_OrientationOffsetY = reader.ReadSingle();
@@ -753,7 +827,7 @@ namespace AssetStudio
m_AverageAngularSpeed = reader.ReadSingle();
m_IndexArray = reader.ReadInt32Array();
if (version[0] < 4 || (version[0] == 4 && version[1] < 3)) //4.3 down
if (version < (4, 3)) //4.3 down
{
var m_AdditionalCurveIndexArray = reader.ReadInt32Array();
}
@@ -763,13 +837,13 @@ namespace AssetStudio
{
m_ValueArrayDelta[i] = new ValueDelta(reader);
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3))//5.3 and up
if (version >= (5, 3))//5.3 and up
{
m_ValueArrayReferencePose = reader.ReadSingleArray();
}
m_Mirror = reader.ReadBoolean();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_LoopTime = reader.ReadBoolean();
}
@@ -777,7 +851,7 @@ namespace AssetStudio
m_LoopBlendOrientation = reader.ReadBoolean();
m_LoopBlendPositionY = reader.ReadBoolean();
m_LoopBlendPositionXZ = reader.ReadBoolean();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5))//5.5 and up
if (version >= (5, 5))//5.5 and up
{
m_StartAtOrigin = reader.ReadBoolean();
}
@@ -807,7 +881,7 @@ namespace AssetStudio
path = reader.ReadUInt32();
attribute = reader.ReadUInt32();
script = new PPtr<Object>(reader);
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
typeID = (ClassIDType)reader.ReadInt32();
}
@@ -817,7 +891,7 @@ namespace AssetStudio
}
customType = reader.ReadByte();
isPPtrCurve = reader.ReadByte();
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
if (version >= (2022, 1)) //2022.1 and up
{
isIntCurve = reader.ReadByte();
}
@@ -895,6 +969,8 @@ namespace AssetStudio
public int intParameter;
public int messageOptions;
public AnimationEvent() { }
public AnimationEvent(ObjectReader reader)
{
var version = reader.version;
@@ -904,7 +980,7 @@ namespace AssetStudio
data = reader.ReadAlignedString();
objectReferenceParameter = new PPtr<Object>(reader);
floatParameter = reader.ReadSingle();
if (version[0] >= 3) //3 and up
if (version >= 3) //3 and up
{
intParameter = reader.ReadInt32();
}
@@ -940,14 +1016,40 @@ namespace AssetStudio
public AnimationClipBindingConstant m_ClipBindingConstant;
public AnimationEvent[] m_Events;
public AnimationClip() { }
public AnimationClip(ObjectReader reader, IDictionary typeDict) : base(reader)
{
var parsedAnimClip = JsonConvert.DeserializeObject<AnimationClip>(JsonConvert.SerializeObject(typeDict));
m_AnimationType = parsedAnimClip.m_AnimationType;
m_Legacy = parsedAnimClip.m_Legacy;
m_Compressed = parsedAnimClip.m_Compressed;
m_UseHighQualityCurve = parsedAnimClip.m_UseHighQualityCurve;
m_RotationCurves = parsedAnimClip.m_RotationCurves;
m_CompressedRotationCurves = parsedAnimClip.m_CompressedRotationCurves;
m_EulerCurves = parsedAnimClip.m_EulerCurves;
m_PositionCurves = parsedAnimClip.m_PositionCurves;
m_ScaleCurves = parsedAnimClip.m_ScaleCurves;
m_FloatCurves = parsedAnimClip.m_FloatCurves;
m_PPtrCurves = parsedAnimClip.m_PPtrCurves;
m_SampleRate = parsedAnimClip.m_SampleRate;
m_WrapMode = parsedAnimClip.m_WrapMode;
m_Bounds = parsedAnimClip.m_Bounds;
m_MuscleClipSize = parsedAnimClip.m_MuscleClipSize;
m_MuscleClip = parsedAnimClip.m_MuscleClip;
m_ClipBindingConstant = parsedAnimClip.m_ClipBindingConstant;
m_Events = parsedAnimClip.m_Events;
typeDict.Clear();
}
public AnimationClip(ObjectReader reader) : base(reader)
{
if (version[0] >= 5)//5.0 and up
if (version >= 5)//5.0 and up
{
m_Legacy = reader.ReadBoolean();
}
else if (version[0] >= 4)//4.0 and up
else if (version >= 4)//4.0 and up
{
m_AnimationType = (AnimationType)reader.ReadInt32();
if (m_AnimationType == AnimationType.Legacy)
@@ -958,7 +1060,7 @@ namespace AssetStudio
m_Legacy = true;
}
m_Compressed = reader.ReadBoolean();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))//4.3 and up
if (version >= (4, 3))//4.3 and up
{
m_UseHighQualityCurve = reader.ReadBoolean();
}
@@ -977,7 +1079,7 @@ namespace AssetStudio
m_CompressedRotationCurves[i] = new CompressedAnimationCurve(reader);
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3))//5.3 and up
if (version >= (5, 3))//5.3 and up
{
int numEulerCurves = reader.ReadInt32();
m_EulerCurves = new Vector3Curve[numEulerCurves];
@@ -1008,7 +1110,7 @@ namespace AssetStudio
m_FloatCurves[i] = new FloatCurve(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
int numPtrCurves = reader.ReadInt32();
m_PPtrCurves = new PPtrCurve[numPtrCurves];
@@ -1020,20 +1122,20 @@ namespace AssetStudio
m_SampleRate = reader.ReadSingle();
m_WrapMode = reader.ReadInt32();
if (version[0] > 3 || (version[0] == 3 && version[1] >= 4)) //3.4 and up
if (version >= (3, 4)) //3.4 and up
{
m_Bounds = new AABB(reader);
}
if (version[0] >= 4)//4.0 and up
if (version >= 4)//4.0 and up
{
m_MuscleClipSize = reader.ReadUInt32();
m_MuscleClip = new ClipMuscleConstant(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_ClipBindingConstant = new AnimationClipBindingConstant(reader);
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 3)) //2018.3 and up
if (version >= (2018, 3)) //2018.3 and up
{
var m_HasGenericRootTransform = reader.ReadBoolean();
var m_HasMotionFloatCurves = reader.ReadBoolean();
@@ -1045,7 +1147,7 @@ namespace AssetStudio
{
m_Events[i] = new AnimationEvent(reader);
}
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
reader.AlignStream();
}

View File

@@ -17,47 +17,47 @@ namespace AssetStudio
m_Controller = new PPtr<RuntimeAnimatorController>(reader);
var m_CullingMode = reader.ReadInt32();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
if (version >= (4, 5)) //4.5 and up
{
var m_UpdateMode = reader.ReadInt32();
}
var m_ApplyRootMotion = reader.ReadBoolean();
if (version[0] == 4 && version[1] >= 5) //4.5 and up - 5.0 down
if (version == 4 && version.Minor >= 5) //4.5 and up - 5.0 down
{
reader.AlignStream();
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
var m_LinearVelocityBlending = reader.ReadBoolean();
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
if (version >= (2021, 2)) //2021.2 and up
{
var m_StabilizeFeet = reader.ReadBoolean();
}
reader.AlignStream();
}
if (version[0] < 4 || (version[0] == 4 && version[1] < 5)) //4.5 down
if (version < (4, 5)) //4.5 down
{
var m_AnimatePhysics = reader.ReadBoolean();
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_HasTransformHierarchy = reader.ReadBoolean();
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
if (version >= (4, 5)) //4.5 and up
{
var m_AllowConstantClipSamplingOptimization = reader.ReadBoolean();
}
if (version[0] >= 5 && version[0] < 2018) //5.0 and up - 2018 down
if (version.IsInRange(5, 2018)) //5.0 and up - 2018 down
{
reader.AlignStream();
}
if (version[0] >= 2018) //2018 and up
if (version >= 2018) //2018 and up
{
var m_KeepAnimatorControllerStateOnDisable = reader.ReadBoolean();
reader.AlignStream();

View File

@@ -17,7 +17,7 @@ namespace AssetStudio
word0 = reader.ReadUInt32();
word1 = reader.ReadUInt32();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
if (version >= (5, 2)) //5.2 and up
{
word2 = reader.ReadUInt32();
}
@@ -73,12 +73,12 @@ namespace AssetStudio
m_SkeletonMask = new SkeletonMask(reader);
m_Binding = reader.ReadUInt32();
m_LayerBlendingMode = reader.ReadInt32();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
if (version >= (4, 2)) //4.2 and up
{
m_DefaultWeight = reader.ReadSingle();
}
m_IKPass = reader.ReadBoolean();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
if (version >= (4, 2)) //4.2 and up
{
m_SyncedLayerAffectsTiming = reader.ReadBoolean();
}
@@ -131,7 +131,7 @@ namespace AssetStudio
}
m_DestinationState = reader.ReadUInt32();
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
m_FullPathID = reader.ReadUInt32();
}
@@ -140,7 +140,7 @@ namespace AssetStudio
m_UserID = reader.ReadUInt32();
m_TransitionDuration = reader.ReadSingle();
m_TransitionOffset = reader.ReadSingle();
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
m_ExitTime = reader.ReadSingle();
m_HasExitTime = reader.ReadBoolean();
@@ -154,7 +154,7 @@ namespace AssetStudio
m_Atomic = reader.ReadBoolean();
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
if (version >= (4, 5)) //4.5 and up
{
m_CanTransitionToSelf = reader.ReadBoolean();
}
@@ -252,43 +252,41 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_BlendType = reader.ReadUInt32();
}
m_BlendEventID = reader.ReadUInt32();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_BlendEventYID = reader.ReadUInt32();
}
m_ChildIndices = reader.ReadUInt32Array();
if (version[0] < 4 || (version[0] == 4 && version[1] < 1)) //4.1 down
if (version < (4, 1)) //4.1 down
{
m_ChildThresholdArray = reader.ReadSingleArray();
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_Blend1dData = new Blend1dDataConstant(reader);
m_Blend2dData = new Blend2dDataConstant(reader);
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
m_BlendDirectData = new BlendDirectDataConstant(reader);
}
m_ClipID = reader.ReadUInt32();
if (version[0] == 4 && version[1] >= 5) //4.5 - 5.0
if (version == 4 && version.Minor >= 5) //4.5 - 5.0
{
m_ClipIndex = reader.ReadUInt32();
}
m_Duration = reader.ReadSingle();
if (version[0] > 4
|| (version[0] == 4 && version[1] > 1)
|| (version[0] == 4 && version[1] == 1 && version[2] >= 3)) //4.1.3 and up
if (version >= (4, 1, 3)) //4.1.3 and up
{
m_CycleOffset = reader.ReadSingle();
m_Mirror = reader.ReadBoolean();
@@ -313,7 +311,7 @@ namespace AssetStudio
m_NodeArray[i] = new BlendTreeNodeConstant(reader);
}
if (version[0] < 4 || (version[0] == 4 && version[1] < 5)) //4.5 down
if (version < (4, 5)) //4.5 down
{
m_BlendEventArrayConstant = new ValueArrayConstant(reader);
}
@@ -354,7 +352,7 @@ namespace AssetStudio
m_BlendTreeConstantIndexArray = reader.ReadInt32Array();
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
if (version < (5, 2)) //5.2 down
{
int numInfos = reader.ReadInt32();
m_LeafInfoArray = new LeafInfoConstant[numInfos];
@@ -372,41 +370,41 @@ namespace AssetStudio
}
m_NameID = reader.ReadUInt32();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_PathID = reader.ReadUInt32();
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
m_FullPathID = reader.ReadUInt32();
}
m_TagID = reader.ReadUInt32();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 1)) //5.1 and up
if (version >= (5, 1)) //5.1 and up
{
m_SpeedParamID = reader.ReadUInt32();
m_MirrorParamID = reader.ReadUInt32();
m_CycleOffsetParamID = reader.ReadUInt32();
}
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
var m_TimeParamID = reader.ReadUInt32();
}
m_Speed = reader.ReadSingle();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_CycleOffset = reader.ReadSingle();
}
m_IKOnFeet = reader.ReadBoolean();
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
m_WriteDefaultValues = reader.ReadBoolean();
}
m_Loop = reader.ReadBoolean();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_Mirror = reader.ReadBoolean();
}
@@ -480,7 +478,7 @@ namespace AssetStudio
m_AnyStateTransitionConstantArray[i] = new TransitionConstant(reader);
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
int numSelectors = reader.ReadInt32();
m_SelectorStateConstantArray = new SelectorStateConstant[numSelectors];
@@ -509,7 +507,7 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] < 5 || (version[0] == 5 && version[1] < 5)) //5.5 down
if (version < (5, 5)) //5.5 down
{
m_BoolValues = reader.ReadBooleanArray();
reader.AlignStream();
@@ -517,7 +515,7 @@ namespace AssetStudio
m_FloatValues = reader.ReadSingleArray();
}
if (version[0] < 4 || (version[0] == 4 && version[1] < 3)) //4.3 down
if (version < (4, 3)) //4.3 down
{
m_VectorValues = reader.ReadVector4Array();
}
@@ -527,7 +525,7 @@ namespace AssetStudio
m_PositionValues = new Vector3[numPosValues];
for (int i = 0; i < numPosValues; i++)
{
m_PositionValues[i] = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
m_PositionValues[i] = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
}
m_QuaternionValues = reader.ReadVector4Array();
@@ -536,10 +534,10 @@ namespace AssetStudio
m_ScaleValues = new Vector3[numScaleValues];
for (int i = 0; i < numScaleValues; i++)
{
m_ScaleValues[i] = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
m_ScaleValues[i] = version >= (5, 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
if (version >= (5, 5)) //5.5 and up
{
m_FloatValues = reader.ReadSingleArray();
m_IntValues = reader.ReadInt32Array();

View File

@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
namespace AssetStudio
{
@@ -23,22 +20,57 @@ namespace AssetStudio
{
public PPtr<Object>[] m_PreloadTable;
public KeyValuePair<string, AssetInfo>[] m_Container;
public string m_AssetBundleName;
public string[] m_Dependencies;
public bool m_IsStreamedSceneAssetBundle;
public AssetBundle(ObjectReader reader) : base(reader)
{
var m_PreloadTableSize = reader.ReadInt32();
m_PreloadTable = new PPtr<Object>[m_PreloadTableSize];
for (int i = 0; i < m_PreloadTableSize; i++)
for (var i = 0; i < m_PreloadTableSize; i++)
{
m_PreloadTable[i] = new PPtr<Object>(reader);
}
var m_ContainerSize = reader.ReadInt32();
m_Container = new KeyValuePair<string, AssetInfo>[m_ContainerSize];
for (int i = 0; i < m_ContainerSize; i++)
for (var i = 0; i < m_ContainerSize; i++)
{
m_Container[i] = new KeyValuePair<string, AssetInfo>(reader.ReadAlignedString(), new AssetInfo(reader));
}
var m_MainAsset = new AssetInfo(reader);
if (version == (5, 4)) //5.4.x
{
var m_ClassVersionMapSize = reader.ReadInt32();
for (var i = 0; i < m_ClassVersionMapSize; i++)
{
var first = reader.ReadInt32();
var second = reader.ReadInt32();
}
}
if (version >= (4, 2)) //4.2 and up
{
var m_RuntimeCompatibility = reader.ReadUInt32();
}
if (version >= 5) //5.0 and up
{
m_AssetBundleName = reader.ReadAlignedString();
var m_DependenciesSize = reader.ReadInt32();
m_Dependencies = new string[m_DependenciesSize];
for (var i = 0; i < m_DependenciesSize; i++)
{
m_Dependencies[i] = reader.ReadAlignedString();
}
m_IsStreamedSceneAssetBundle = reader.ReadBoolean();
}
}
}
}

View File

@@ -33,7 +33,7 @@ namespace AssetStudio
public AudioClip(ObjectReader reader) : base(reader)
{
if (version[0] < 5)
if (version < 5)
{
m_Format = reader.ReadInt32();
m_Type = (FMODSoundType)reader.ReadInt32();
@@ -41,7 +41,7 @@ namespace AssetStudio
m_UseHardware = reader.ReadBoolean();
reader.AlignStream();
if (version[0] >= 4 || (version[0] == 3 && version[1] >= 2)) //3.2.0 to 5
if (version >= (3, 2)) //3.2.0 to 5
{
int m_Stream = reader.ReadInt32();
m_Size = reader.ReadInt32();
@@ -95,7 +95,7 @@ namespace AssetStudio
public enum FMODSoundType
{
UNKNOWN = 0,
ACC = 1,
AAC = 1,
AIFF = 2,
ASF = 3,
AT3 = 4,

View File

@@ -23,7 +23,7 @@ namespace AssetStudio
public Limit(ObjectReader reader)
{
var version = reader.version;
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4))//5.4 and up
if (version >= (5, 4))//5.4 and up
{
m_Min = reader.ReadVector3();
m_Max = reader.ReadVector3();
@@ -50,7 +50,7 @@ namespace AssetStudio
var version = reader.version;
m_PreQ = reader.ReadVector4();
m_PostQ = reader.ReadVector4();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
if (version >= (5, 4)) //5.4 and up
{
m_Sgn = reader.ReadVector3();
}
@@ -189,7 +189,7 @@ namespace AssetStudio
m_LeftHand = new Hand(reader);
m_RightHand = new Hand(reader);
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
if (version < (2018, 2)) //2018.2 down
{
int numHandles = reader.ReadInt32();
m_Handles = new Handle[numHandles];
@@ -210,7 +210,7 @@ namespace AssetStudio
m_HumanBoneMass = reader.ReadSingleArray();
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
if (version < (2018, 2)) //2018.2 down
{
m_ColliderIndex = reader.ReadInt32Array();
}
@@ -225,7 +225,7 @@ namespace AssetStudio
m_FeetSpacing = reader.ReadSingle();
m_HasLeftHand = reader.ReadBoolean();
m_HasRightHand = reader.ReadBoolean();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
if (version >= (5, 2)) //5.2 and up
{
m_HasTDoF = reader.ReadBoolean();
}
@@ -254,7 +254,7 @@ namespace AssetStudio
m_AvatarSkeleton = new Skeleton(reader);
m_AvatarSkeletonPose = new SkeletonPose(reader);
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_DefaultPose = new SkeletonPose(reader);
@@ -265,7 +265,7 @@ namespace AssetStudio
m_HumanSkeletonIndexArray = reader.ReadInt32Array();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_HumanSkeletonReverseIndexArray = reader.ReadInt32Array();
}
@@ -273,7 +273,7 @@ namespace AssetStudio
m_RootMotionBoneIndex = reader.ReadInt32();
m_RootMotionBoneX = new xform(reader);
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_RootMotionSkeleton = new Skeleton(reader);
m_RootMotionSkeletonPose = new SkeletonPose(reader);

View File

@@ -7,6 +7,8 @@ namespace AssetStudio
{
public abstract class EditorExtension : Object
{
protected EditorExtension() { }
protected EditorExtension(ObjectReader reader) : base(reader)
{
if (platform == BuildTarget.NoTarget)

View File

@@ -11,7 +11,7 @@ namespace AssetStudio
public Font(ObjectReader reader) : base(reader)
{
if ((version[0] == 5 && version[1] >= 5) || version[0] > 5)//5.5 and up
if (version >= (5, 5))//5.5 and up
{
var m_LineSpacing = reader.ReadSingle();
var m_DefaultMaterial = new PPtr<Material>(reader);
@@ -43,7 +43,7 @@ namespace AssetStudio
{
int m_AsciiStartOffset = reader.ReadInt32();
if (version[0] <= 3)
if (version <= 3)
{
int m_FontCountX = reader.ReadInt32();
int m_FontCountY = reader.ReadInt32();
@@ -52,7 +52,7 @@ namespace AssetStudio
float m_Kerning = reader.ReadSingle();
float m_LineSpacing = reader.ReadSingle();
if (version[0] <= 3)
if (version <= 3)
{
int m_PerCharacterKerning_size = reader.ReadInt32();
for (int i = 0; i < m_PerCharacterKerning_size; i++)
@@ -86,7 +86,7 @@ namespace AssetStudio
float vertheight = reader.ReadSingle();
float width = reader.ReadSingle();
if (version[0] >= 4)
if (version >= 4)
{
var flipped = reader.ReadBoolean();
reader.AlignStream();
@@ -103,7 +103,7 @@ namespace AssetStudio
float second = reader.ReadSingle();
}
if (version[0] <= 3)
if (version <= 3)
{
var m_GridFont = reader.ReadBoolean();
reader.AlignStream();

View File

@@ -0,0 +1,31 @@
namespace AssetStudio
{
public class GLTextureSettings
{
public int m_FilterMode;
public int m_Aniso;
public float m_MipBias;
public int m_WrapMode;
public GLTextureSettings() { }
public GLTextureSettings(ObjectReader reader)
{
var version = reader.version;
m_FilterMode = reader.ReadInt32();
m_Aniso = reader.ReadInt32();
m_MipBias = reader.ReadSingle();
if (version >= 2017)//2017.x and up
{
m_WrapMode = reader.ReadInt32(); //m_WrapU
int m_WrapV = reader.ReadInt32();
int m_WrapW = reader.ReadInt32();
}
else
{
m_WrapMode = reader.ReadInt32();
}
}
}
}

View File

@@ -23,7 +23,7 @@ namespace AssetStudio
m_Components = new PPtr<Component>[m_Component_size];
for (int i = 0; i < m_Component_size; i++)
{
if ((version[0] == 5 && version[1] < 5) || version[0] < 5) //5.5 down
if (version < (5, 5)) //5.5 down
{
int first = reader.ReadInt32();
}

View File

@@ -0,0 +1,711 @@
namespace AssetStudio
{
public enum GraphicsFormat
{
/// <summary>
/// The format is not specified.
/// </summary>
None,
/// <summary>
/// A one-component, 8-bit unsigned normalized format that has a single 8-bit R component stored with sRGB nonlinear encoding.
/// </summary>
R8_SRGB,
/// <summary>
/// A two-component, 16-bit unsigned normalized format that has an 8-bit R component stored with sRGB nonlinear encoding in byte 0, and an 8-bit G component stored with sRGB nonlinear encoding in byte 1.
/// </summary>
R8G8_SRGB,
/// <summary>
/// A three-component, 24-bit unsigned normalized format that has an 8-bit R component stored with sRGB nonlinear encoding in byte 0, an 8-bit G component stored with sRGB nonlinear encoding in byte 1, and an 8-bit B component stored with sRGB nonlinear encoding in byte 2.
/// </summary>
R8G8B8_SRGB,
/// <summary>
/// A four-component, 32-bit unsigned normalized format that has an 8-bit R component stored with sRGB nonlinear encoding in byte 0, an 8-bit G component stored with sRGB nonlinear encoding in byte 1, an 8-bit B component stored with sRGB nonlinear encoding in byte 2, and an 8-bit A component in byte 3.
/// </summary>
R8G8B8A8_SRGB,
/// <summary>
/// A one-component, 8-bit unsigned normalized format that has a single 8-bit R component.
/// </summary>
R8_UNorm,
/// <summary>
/// A two-component, 16-bit unsigned normalized format that has an 8-bit R component stored with sRGB nonlinear encoding in byte 0, and an 8-bit G component stored with sRGB nonlinear encoding in byte 1.
/// </summary>
R8G8_UNorm,
/// <summary>
/// A three-component, 24-bit unsigned normalized format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, and an 8-bit B component in byte 2.
/// </summary>
R8G8B8_UNorm,
/// <summary>
/// A four-component, 32-bit unsigned normalized format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, an 8-bit B component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
R8G8B8A8_UNorm,
/// <summary>
/// A one-component, 8-bit signed normalized format that has a single 8-bit R component.
/// </summary>
R8_SNorm,
/// <summary>
/// A two-component, 16-bit signed normalized format that has an 8-bit R component stored with sRGB nonlinear encoding in byte 0, and an 8-bit G component stored with sRGB nonlinear encoding in byte 1.
/// </summary>
R8G8_SNorm,
/// <summary>
/// A three-component, 24-bit signed normalized format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, and an 8-bit B component in byte 2.
/// </summary>
R8G8B8_SNorm,
/// <summary>
/// A four-component, 32-bit signed normalized format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, an 8-bit B component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
R8G8B8A8_SNorm,
/// <summary>
/// A one-component, 8-bit unsigned integer format that has a single 8-bit R component.
/// </summary>
R8_UInt,
/// <summary>
/// A two-component, 16-bit unsigned integer format that has an 8-bit R component in byte 0, and an 8-bit G component in byte 1.
/// </summary>
R8G8_UInt,
/// <summary>
/// A three-component, 24-bit unsigned integer format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, and an 8-bit B component in byte 2.
/// </summary>
R8G8B8_UInt,
/// <summary>
/// A four-component, 32-bit unsigned integer format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, an 8-bit B component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
R8G8B8A8_UInt,
/// <summary>
/// A one-component, 8-bit signed integer format that has a single 8-bit R component.
/// </summary>
R8_SInt,
/// <summary>
/// A two-component, 16-bit signed integer format that has an 8-bit R component in byte 0, and an 8-bit G component in byte 1.
/// </summary>
R8G8_SInt,
/// <summary>
/// A three-component, 24-bit signed integer format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, and an 8-bit B component in byte 2.
/// </summary>
R8G8B8_SInt,
/// <summary>
/// A four-component, 32-bit signed integer format that has an 8-bit R component in byte 0, an 8-bit G component in byte 1, an 8-bit B component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
R8G8B8A8_SInt,
/// <summary>
/// A one-component, 16-bit unsigned normalized format that has a single 16-bit R component.
/// </summary>
R16_UNorm,
/// <summary>
/// A two-component, 32-bit unsigned normalized format that has a 16-bit R component in bytes 0..1, and a 16-bit G component in bytes 2..3.
/// </summary>
R16G16_UNorm,
/// <summary>
/// A three-component, 48-bit unsigned normalized format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, and a 16-bit B component in bytes 4..5.
/// </summary>
R16G16B16_UNorm,
/// <summary>
/// A four-component, 64-bit unsigned normalized format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, a 16-bit B component in bytes 4..5, and a 16-bit A component in bytes 6..7.
/// </summary>
R16G16B16A16_UNorm,
/// <summary>
/// A one-component, 16-bit signed normalized format that has a single 16-bit R component.
/// </summary>
R16_SNorm,
/// <summary>
/// A two-component, 32-bit signed normalized format that has a 16-bit R component in bytes 0..1, and a 16-bit G component in bytes 2..3.
/// </summary>
R16G16_SNorm,
/// <summary>
/// A three-component, 48-bit signed normalized format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, and a 16-bit B component in bytes 4..5.
/// </summary>
R16G16B16_SNorm,
/// <summary>
/// A four-component, 64-bit signed normalized format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, a 16-bit B component in bytes 4..5, and a 16-bit A component in bytes 6..7.
/// </summary>
R16G16B16A16_SNorm,
/// <summary>
/// A one-component, 16-bit unsigned integer format that has a single 16-bit R component.
/// </summary>
R16_UInt,
/// <summary>
/// A two-component, 32-bit unsigned integer format that has a 16-bit R component in bytes 0..1, and a 16-bit G component in bytes 2..3.
/// </summary>
R16G16_UInt,
/// <summary>
/// A three-component, 48-bit unsigned integer format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, and a 16-bit B component in bytes 4..5.
/// </summary>
R16G16B16_UInt,
/// <summary>
/// A four-component, 64-bit unsigned integer format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, a 16-bit B component in bytes 4..5, and a 16-bit A component in bytes 6..7.
/// </summary>
R16G16B16A16_UInt,
/// <summary>
/// A one-component, 16-bit signed integer format that has a single 16-bit R component.
/// </summary>
R16_SInt,
/// <summary>
/// A two-component, 32-bit signed integer format that has a 16-bit R component in bytes 0..1, and a 16-bit G component in bytes 2..3.
/// </summary>
R16G16_SInt,
/// <summary>
/// A three-component, 48-bit signed integer format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, and a 16-bit B component in bytes 4..5.
/// </summary>
R16G16B16_SInt,
/// <summary>
/// A four-component, 64-bit signed integer format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, a 16-bit B component in bytes 4..5, and a 16-bit A component in bytes 6..7.
/// </summary>
R16G16B16A16_SInt,
/// <summary>
/// A one-component, 32-bit unsigned integer format that has a single 32-bit R component.
/// </summary>
R32_UInt,
/// <summary>
/// A two-component, 64-bit unsigned integer format that has a 32-bit R component in bytes 0..3, and a 32-bit G component in bytes 4..7.
/// </summary>
R32G32_UInt,
/// <summary>
/// A three-component, 96-bit unsigned integer format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, and a 32-bit B component in bytes 8..11.
/// </summary>
R32G32B32_UInt,
/// <summary>
/// A four-component, 128-bit unsigned integer format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, a 32-bit B component in bytes 8..11, and a 32-bit A component in bytes 12..15.
/// </summary>
R32G32B32A32_UInt,
/// <summary>
/// A one-component, 32-bit signed integer format that has a single 32-bit R component.
/// </summary>
R32_SInt,
/// <summary>
/// A two-component, 64-bit signed integer format that has a 32-bit R component in bytes 0..3, and a 32-bit G component in bytes 4..7.
/// </summary>
R32G32_SInt,
/// <summary>
/// A three-component, 96-bit signed integer format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, and a 32-bit B component in bytes 8..11.
/// </summary>
R32G32B32_SInt,
/// <summary>
/// A four-component, 128-bit signed integer format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, a 32-bit B component in bytes 8..11, and a 32-bit A component in bytes 12..15.
/// </summary>
R32G32B32A32_SInt,
/// <summary>
/// A one-component, 16-bit signed floating-point format that has a single 16-bit R component.
/// </summary>
R16_SFloat,
/// <summary>
/// A two-component, 32-bit signed floating-point format that has a 16-bit R component in bytes 0..1, and a 16-bit G component in bytes 2..3.
/// </summary>
R16G16_SFloat,
/// <summary>
/// A three-component, 48-bit signed floating-point format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, and a 16-bit B component in bytes 4..5.
/// </summary>
R16G16B16_SFloat,
/// <summary>
/// A four-component, 64-bit signed floating-point format that has a 16-bit R component in bytes 0..1, a 16-bit G component in bytes 2..3, a 16-bit B component in bytes 4..5, and a 16-bit A component in bytes 6..7.
/// </summary>
R16G16B16A16_SFloat,
/// <summary>
/// A one-component, 32-bit signed floating-point format that has a single 32-bit R component.
/// </summary>
R32_SFloat,
/// <summary>
/// A two-component, 64-bit signed floating-point format that has a 32-bit R component in bytes 0..3, and a 32-bit G component in bytes 4..7.
/// </summary>
R32G32_SFloat,
/// <summary>
/// A three-component, 96-bit signed floating-point format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, and a 32-bit B component in bytes 8..11.
/// </summary>
R32G32B32_SFloat,
/// <summary>
/// A four-component, 128-bit signed floating-point format that has a 32-bit R component in bytes 0..3, a 32-bit G component in bytes 4..7, a 32-bit B component in bytes 8..11, and a 32-bit A component in bytes 12..15.
/// </summary>
R32G32B32A32_SFloat,
/// <summary>
/// A three-component, 24-bit unsigned normalized format that has an 8-bit B component stored with sRGB nonlinear encoding in byte 0, an 8-bit G component stored with sRGB nonlinear encoding in byte 1, and an 8-bit R component stored with sRGB nonlinear encoding in byte 2.
/// </summary>
B8G8R8_SRGB = 56,
/// <summary>
/// A four-component, 32-bit unsigned normalized format that has an 8-bit B component stored with sRGB nonlinear encoding in byte 0, an 8-bit G component stored with sRGB nonlinear encoding in byte 1, an 8-bit R component stored with sRGB nonlinear encoding in byte 2, and an 8-bit A component in byte 3.
/// </summary>
B8G8R8A8_SRGB,
/// <summary>
/// A three-component, 24-bit unsigned normalized format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, and an 8-bit R component in byte 2.
/// </summary>
B8G8R8_UNorm,
/// <summary>
/// A four-component, 32-bit unsigned normalized format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, an 8-bit R component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
B8G8R8A8_UNorm,
/// <summary>
/// A three-component, 24-bit signed normalized format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, and an 8-bit R component in byte 2.
/// </summary>
B8G8R8_SNorm,
/// <summary>
/// A four-component, 32-bit signed normalized format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, an 8-bit R component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
B8G8R8A8_SNorm,
/// <summary>
/// A three-component, 24-bit unsigned integer format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, and an 8-bit R component in byte 2
/// </summary>
B8G8R8_UInt,
/// <summary>
/// A four-component, 32-bit unsigned integer format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, an 8-bit R component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
B8G8R8A8_UInt,
/// <summary>
/// A three-component, 24-bit signed integer format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, and an 8-bit R component in byte 2.
/// </summary>
B8G8R8_SInt,
/// <summary>
/// A four-component, 32-bit signed integer format that has an 8-bit B component in byte 0, an 8-bit G component in byte 1, an 8-bit R component in byte 2, and an 8-bit A component in byte 3.
/// </summary>
B8G8R8A8_SInt,
/// <summary>
/// A four-component, 16-bit packed unsigned normalized format that has a 4-bit R component in bits 12..15, a 4-bit G component in bits 8..11, a 4-bit B component in bits 4..7, and a 4-bit A component in bits 0..3.
/// </summary>
R4G4B4A4_UNormPack16,
/// <summary>
/// A four-component, 16-bit packed unsigned normalized format that has a 4-bit B component in bits 12..15, a 4-bit G component in bits 8..11, a 4-bit R component in bits 4..7, and a 4-bit A component in bits 0..3.
/// </summary>
B4G4R4A4_UNormPack16,
/// <summary>
/// A three-component, 16-bit packed unsigned normalized format that has a 5-bit R component in bits 11..15, a 6-bit G component in bits 5..10, and a 5-bit B component in bits 0..4.
/// </summary>
R5G6B5_UNormPack16,
/// <summary>
/// A three-component, 16-bit packed unsigned normalized format that has a 5-bit B component in bits 11..15, a 6-bit G component in bits 5..10, and a 5-bit R component in bits 0..4.
/// </summary>
B5G6R5_UNormPack16,
/// <summary>
/// A four-component, 16-bit packed unsigned normalized format that has a 5-bit R component in bits 11..15, a 5-bit G component in bits 6..10, a 5-bit B component in bits 1..5, and a 1-bit A component in bit 0.
/// </summary>
R5G5B5A1_UNormPack16,
/// <summary>
/// A four-component, 16-bit packed unsigned normalized format that has a 5-bit B component in bits 11..15, a 5-bit G component in bits 6..10, a 5-bit R component in bits 1..5, and a 1-bit A component in bit 0.
/// </summary>
B5G5R5A1_UNormPack16,
/// <summary>
/// A four-component, 16-bit packed unsigned normalized format that has a 1-bit A component in bit 15, a 5-bit R component in bits 10..14, a 5-bit G component in bits 5..9, and a 5-bit B component in bits 0..4.
/// </summary>
A1R5G5B5_UNormPack16,
/// <summary>
/// A three-component, 32-bit packed unsigned floating-point format that has a 5-bit shared exponent in bits 27..31, a 9-bit B component mantissa in bits 18..26, a 9-bit G component mantissa in bits 9..17, and a 9-bit R component mantissa in bits 0..8.
/// </summary>
E5B9G9R9_UFloatPack32,
/// <summary>
/// A three-component, 32-bit packed unsigned floating-point format that has a 10-bit B component in bits 22..31, an 11-bit G component in bits 11..21, an 11-bit R component in bits 0..10.
/// </summary>
B10G11R11_UFloatPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 2-bit A component in bits 30..31, a 10-bit B component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit R component in bits 0..9.
/// </summary>
A2B10G10R10_UNormPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned integer format that has a 2-bit A component in bits 30..31, a 10-bit B component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit R component in bits 0..9.
/// </summary>
A2B10G10R10_UIntPack32,
/// <summary>
/// A four-component, 32-bit packed signed integer format that has a 2-bit A component in bits 30..31, a 10-bit B component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit R component in bits 0..9.
/// </summary>
A2B10G10R10_SIntPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 2-bit A component in bits 30..31, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9.
/// </summary>
A2R10G10B10_UNormPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned integer format that has a 2-bit A component in bits 30..31, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9.
/// </summary>
A2R10G10B10_UIntPack32,
/// <summary>
/// A four-component, 32-bit packed signed integer format that has a 2-bit A component in bits 30..31, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9.
/// </summary>
A2R10G10B10_SIntPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 2-bit A component in bits 30..31, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are gamma encoded and their values range from -0.5271 to 1.66894. The alpha component is clamped to either 0.0 or 1.0 on sampling, rendering, and writing operations.
/// </summary>
A2R10G10B10_XRSRGBPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 2-bit A component in bits 30..31, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are linearly encoded and their values range from -0.752941 to 1.25098 (pre-expansion). The alpha component is clamped to either 0.0 or 1.0 on sampling, rendering, and writing operations.
/// </summary>
A2R10G10B10_XRUNormPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are gamma encoded and their values range from -0.5271 to 1.66894. The alpha component is clamped to either 0.0 or 1.0 on sampling, rendering, and writing operations.
/// </summary>
R10G10B10_XRSRGBPack32,
/// <summary>
/// A four-component, 32-bit packed unsigned normalized format that has a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are linearly encoded and their values range from -0.752941 to 1.25098 (pre-expansion).
/// </summary>
R10G10B10_XRUNormPack32,
/// <summary>
/// A four-component, 64-bit packed unsigned normalized format that has a 10-bit A component in bits 30..39, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are gamma encoded and their values range from -0.5271 to 1.66894. The alpha component is clamped to either 0.0 or 1.0 on sampling, rendering, and writing operations.
/// </summary>
A10R10G10B10_XRSRGBPack32,
/// <summary>
/// A four-component, 64-bit packed unsigned normalized format that has a 10-bit A component in bits 30..39, a 10-bit R component in bits 20..29, a 10-bit G component in bits 10..19, and a 10-bit B component in bits 0..9. The components are linearly encoded and their values range from -0.752941 to 1.25098 (pre-expansion). The alpha component is clamped to either 0.0 or 1.0 on sampling, rendering, and writing operations.
/// </summary>
A10R10G10B10_XRUNormPack32,
/// <summary>
/// A one-component, 16-bit unsigned normalized format that has a single 16-bit depth component.
/// </summary>
D16_UNorm = 90,
/// <summary>
/// A two-component, 32-bit format that has 24 unsigned normalized bits in the depth component and, optionally: 8 bits that are unused.
/// </summary>
D24_UNorm,
/// <summary>
/// A two-component, 32-bit packed format that has 8 unsigned integer bits in the stencil component, and 24 unsigned normalized bits in the depth component.
/// </summary>
D24_UNorm_S8_UInt,
/// <summary>
/// A one-component, 32-bit signed floating-point format that has 32-bits in the depth component.
/// </summary>
D32_SFloat,
/// <summary>
/// A two-component format that has 32 signed float bits in the depth component and 8 unsigned integer bits in the stencil component. There are optionally: 24-bits that are unused.
/// </summary>
D32_SFloat_S8_UInt,
/// <summary>
/// A one-component, 8-bit unsigned integer format that has 8-bits in the stencil component.
/// </summary>
S8_UInt,
/// <summary>
/// A three-component, block-compressed format (also known as BC1). Each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data with sRGB nonlinear encoding. This format has a 1 bit alpha channel.
/// </summary>
RGBA_DXT1_SRGB,
/// <summary>
/// A three-component, block-compressed format (also known as BC1). Each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data. This format has a 1 bit alpha channel.
/// </summary>
RGBA_DXT1_UNorm,
/// <summary>
/// A four-component, block-compressed format (also known as BC2) where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values with sRGB nonlinear encoding.
/// </summary>
RGBA_DXT3_SRGB,
/// <summary>
/// A four-component, block-compressed format (also known as BC2) where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values.
/// </summary>
RGBA_DXT3_UNorm,
/// <summary>
/// A four-component, block-compressed format (also known as BC3) where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values with sRGB nonlinear encoding.
/// </summary>
RGBA_DXT5_SRGB,
/// <summary>
/// A four-component, block-compressed format (also known as BC3) where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values.
/// </summary>
RGBA_DXT5_UNorm,
/// <summary>
/// A one-component, block-compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized red texel data.
/// </summary>
R_BC4_UNorm,
/// <summary>
/// A one-component, block-compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of signed normalized red texel data.
/// </summary>
R_BC4_SNorm,
/// <summary>
/// A two-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RG texel data with the first 64 bits encoding red values followed by 64 bits encoding green values.
/// </summary>
RG_BC5_UNorm,
/// <summary>
/// A two-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of signed normalized RG texel data with the first 64 bits encoding red values followed by 64 bits encoding green values.
/// </summary>
RG_BC5_SNorm,
/// <summary>
/// A three-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned floating-point RGB texel data.
/// </summary>
RGB_BC6H_UFloat,
/// <summary>
/// A three-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of signed floating-point RGB texel data.
/// </summary>
RGB_BC6H_SFloat,
/// <summary>
/// A four-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_BC7_SRGB,
/// <summary>
/// A four-component, block-compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_BC7_UNorm,
/// <summary>
/// A three-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 8×4 rectangle of unsigned normalized RGB texel data with sRGB nonlinear encoding. This format has no alpha and is considered opaque.
/// </summary>
RGB_PVRTC_2Bpp_SRGB,
/// <summary>
/// A three-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 8×4 rectangle of unsigned normalized RGB texel data. This format has no alpha and is considered opaque.
/// </summary>
RGB_PVRTC_2Bpp_UNorm,
/// <summary>
/// A three-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data with sRGB nonlinear encoding. This format has no alpha and is considered opaque.
/// </summary>
RGB_PVRTC_4Bpp_SRGB,
/// <summary>
/// A three-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data. This format has no alpha and is considered opaque.
/// </summary>
RGB_PVRTC_4Bpp_UNorm,
/// <summary>
/// A four-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 8×4 rectangle of unsigned normalized RGBA texel data with the first 32 bits encoding alpha values followed by 32 bits encoding RGB values with sRGB nonlinear encoding applied.
/// </summary>
RGBA_PVRTC_2Bpp_SRGB,
/// <summary>
/// A four-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 8×4 rectangle of unsigned normalized RGBA texel data with the first 32 bits encoding alpha values followed by 32 bits encoding RGB values.
/// </summary>
RGBA_PVRTC_2Bpp_UNorm,
/// <summary>
/// A four-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 32 bits encoding alpha values followed by 32 bits encoding RGB values with sRGB nonlinear encoding applied.
/// </summary>
RGBA_PVRTC_4Bpp_SRGB,
/// <summary>
/// A four-component, PVRTC compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 32 bits encoding alpha values followed by 32 bits encoding RGB values.
/// </summary>
RGBA_PVRTC_4Bpp_UNorm,
/// <summary>
/// A three-component, ETC compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data. This format has no alpha and is considered opaque.
/// </summary>
RGB_ETC_UNorm,
/// <summary>
/// A three-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data with sRGB nonlinear encoding. This format has no alpha and is considered opaque.
/// </summary>
RGB_ETC2_SRGB,
/// <summary>
/// A three-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data. This format has no alpha and is considered opaque.
/// </summary>
RGB_ETC2_UNorm,
/// <summary>
/// A four-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data with sRGB nonlinear encoding, and provides 1 bit of alpha.
/// </summary>
RGB_A1_ETC2_SRGB,
/// <summary>
/// A four-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGB texel data, and provides 1 bit of alpha.
/// </summary>
RGB_A1_ETC2_UNorm,
/// <summary>
/// A four-component, ETC2 compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values with sRGB nonlinear encoding applied.
/// </summary>
RGBA_ETC2_SRGB,
/// <summary>
/// A four-component, ETC2 compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with the first 64 bits encoding alpha values followed by 64 bits encoding RGB values.
/// </summary>
RGBA_ETC2_UNorm,
/// <summary>
/// A one-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized red texel data.
/// </summary>
R_EAC_UNorm,
/// <summary>
/// A one-component, ETC2 compressed format where each 64-bit compressed texel block encodes a 4×4 rectangle of signed normalized red texel data.
/// </summary>
R_EAC_SNorm,
/// <summary>
/// A two-component, ETC2 compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RG texel data with the first 64 bits encoding red values followed by 64 bits encoding green values.
/// </summary>
RG_EAC_UNorm,
/// <summary>
/// A two-component, ETC2 compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of signed normalized RG texel data with the first 64 bits encoding red values followed by 64 bits encoding green values.
/// </summary>
RG_EAC_SNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC4X4_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC4X4_UNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 5×5 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC5X5_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 5×5 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC5X5_UNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 6×6 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC6X6_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 6×6 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC6X6_UNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes an 8×8 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC8X8_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes an 8×8 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC8X8_UNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 10×10 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC10X10_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 10×10 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC10X10_UNorm,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 12×12 rectangle of unsigned normalized RGBA texel data with sRGB nonlinear encoding applied to the RGB components.
/// </summary>
RGBA_ASTC12X12_SRGB,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 12×12 rectangle of unsigned normalized RGBA texel data.
/// </summary>
RGBA_ASTC12X12_UNorm,
/// <summary>
/// YUV 4:2:2 Video resource format.
/// </summary>
YUV2,
/// <summary>
/// GraphicsFormat.YUV2.
/// </summary>
VideoAuto = 144,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 4×4 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC4X4_UFloat,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 5×5 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC5X5_UFloat,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 6×6 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC6X6_UFloat,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes an 8×8 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC8X8_UFloat,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 10×10 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC10X10_UFloat,
/// <summary>
/// A four-component, ASTC compressed format where each 128-bit compressed texel block encodes a 12×12 rectangle of float RGBA texel data.
/// </summary>
RGBA_ASTC12X12_UFloat,
/// <summary>
/// A two-component, 24-bit format that has 16 unsigned normalized bits in the depth component and 8 unsigned integer bits in the stencil component. Most platforms do not support this format.
/// </summary>
D16_UNorm_S8_UInt,
}
public static class GraphicsFormatExtension
{
public static TextureFormat ToTextureFormat(this GraphicsFormat graphicsFormat)
{
switch (graphicsFormat)
{
case GraphicsFormat.R8_SRGB:
case GraphicsFormat.R8_UInt:
case GraphicsFormat.R8_UNorm:
return TextureFormat.R8;
case GraphicsFormat.R8G8_SRGB:
case GraphicsFormat.R8G8_UInt:
case GraphicsFormat.R8G8_UNorm:
return TextureFormat.RG16;
case GraphicsFormat.R8G8B8_SRGB:
case GraphicsFormat.R8G8B8_UInt:
case GraphicsFormat.R8G8B8_UNorm:
return TextureFormat.RGB24;
case GraphicsFormat.R8G8B8A8_SRGB:
case GraphicsFormat.R8G8B8A8_UInt:
case GraphicsFormat.R8G8B8A8_UNorm:
return TextureFormat.RGBA32;
case GraphicsFormat.R16_UInt:
case GraphicsFormat.R16_UNorm:
return TextureFormat.R16;
case GraphicsFormat.R16G16_UInt:
case GraphicsFormat.R16G16_UNorm:
return TextureFormat.RG32;
case GraphicsFormat.R16G16B16_UInt:
case GraphicsFormat.R16G16B16_UNorm:
return TextureFormat.RGB48;
case GraphicsFormat.R16G16B16A16_UInt:
case GraphicsFormat.R16G16B16A16_UNorm:
return TextureFormat.RGBA64;
case GraphicsFormat.R16_SFloat:
return TextureFormat.RHalf;
case GraphicsFormat.R16G16_SFloat:
return TextureFormat.RGHalf;
case GraphicsFormat.R16G16B16_SFloat: //?
case GraphicsFormat.R16G16B16A16_SFloat:
return TextureFormat.RGBAHalf;
case GraphicsFormat.R32_SFloat:
return TextureFormat.RFloat;
case GraphicsFormat.R32G32_SFloat:
return TextureFormat.RGFloat;
case GraphicsFormat.R32G32B32_SFloat: //?
case GraphicsFormat.R32G32B32A32_SFloat:
return TextureFormat.RGBAFloat;
case GraphicsFormat.B8G8R8A8_SRGB:
case GraphicsFormat.B8G8R8A8_UInt:
case GraphicsFormat.B8G8R8A8_UNorm:
return TextureFormat.BGRA32;
case GraphicsFormat.E5B9G9R9_UFloatPack32:
return TextureFormat.RGB9e5Float;
case GraphicsFormat.RGBA_DXT1_SRGB:
case GraphicsFormat.RGBA_DXT1_UNorm:
return TextureFormat.DXT1;
case GraphicsFormat.RGBA_DXT3_SRGB:
case GraphicsFormat.RGBA_DXT3_UNorm:
return TextureFormat.DXT3;
case GraphicsFormat.RGBA_DXT5_SRGB:
case GraphicsFormat.RGBA_DXT5_UNorm:
return TextureFormat.DXT5;
case GraphicsFormat.R_BC4_UNorm:
return TextureFormat.BC4;
case GraphicsFormat.RG_BC5_UNorm:
return TextureFormat.BC5;
case GraphicsFormat.RGB_BC6H_SFloat:
case GraphicsFormat.RGB_BC6H_UFloat:
return TextureFormat.BC6H;
case GraphicsFormat.RGBA_BC7_SRGB:
case GraphicsFormat.RGBA_BC7_UNorm:
return TextureFormat.BC7;
case GraphicsFormat.RGB_PVRTC_2Bpp_SRGB:
case GraphicsFormat.RGB_PVRTC_2Bpp_UNorm:
case GraphicsFormat.RGBA_PVRTC_2Bpp_SRGB:
case GraphicsFormat.RGBA_PVRTC_2Bpp_UNorm:
return TextureFormat.PVRTC_RGBA2;
case GraphicsFormat.RGB_PVRTC_4Bpp_SRGB:
case GraphicsFormat.RGB_PVRTC_4Bpp_UNorm:
case GraphicsFormat.RGBA_PVRTC_4Bpp_SRGB:
case GraphicsFormat.RGBA_PVRTC_4Bpp_UNorm:
return TextureFormat.PVRTC_RGBA4;
case GraphicsFormat.RGB_ETC_UNorm:
return TextureFormat.ETC_RGB4;
case GraphicsFormat.RGB_ETC2_SRGB:
case GraphicsFormat.RGB_ETC2_UNorm:
return TextureFormat.ETC2_RGB;
case GraphicsFormat.RGB_A1_ETC2_SRGB:
case GraphicsFormat.RGB_A1_ETC2_UNorm:
return TextureFormat.ETC2_RGBA1;
case GraphicsFormat.RGBA_ETC2_SRGB:
case GraphicsFormat.RGBA_ETC2_UNorm:
return TextureFormat.ETC2_RGBA8;
case GraphicsFormat.R_EAC_UNorm:
return TextureFormat.EAC_R;
case GraphicsFormat.R_EAC_SNorm:
return TextureFormat.EAC_R_SIGNED;
case GraphicsFormat.RG_EAC_UNorm:
return TextureFormat.EAC_RG;
case GraphicsFormat.RG_EAC_SNorm:
return TextureFormat.EAC_RG_SIGNED;
case GraphicsFormat.RGBA_ASTC4X4_SRGB:
case GraphicsFormat.RGBA_ASTC4X4_UNorm:
return TextureFormat.ASTC_RGBA_4x4;
case GraphicsFormat.RGBA_ASTC5X5_SRGB:
case GraphicsFormat.RGBA_ASTC5X5_UNorm:
return TextureFormat.ASTC_RGBA_5x5;
case GraphicsFormat.RGBA_ASTC6X6_SRGB:
case GraphicsFormat.RGBA_ASTC6X6_UNorm:
return TextureFormat.ASTC_RGBA_6x6;
case GraphicsFormat.RGBA_ASTC8X8_SRGB:
case GraphicsFormat.RGBA_ASTC8X8_UNorm:
return TextureFormat.ASTC_RGBA_8x8;
case GraphicsFormat.RGBA_ASTC10X10_SRGB:
case GraphicsFormat.RGBA_ASTC10X10_UNorm:
return TextureFormat.ASTC_RGBA_10x10;
case GraphicsFormat.RGBA_ASTC12X12_SRGB:
case GraphicsFormat.RGBA_ASTC12X12_UNorm:
return TextureFormat.ASTC_RGBA_12x12;
case GraphicsFormat.YUV2:
case GraphicsFormat.VideoAuto:
return TextureFormat.YUY2;
default:
return 0;
}
}
}
}

View File

@@ -34,7 +34,7 @@ namespace AssetStudio
m_TexEnvs[i] = new KeyValuePair<string, UnityTexEnv>(reader.ReadAlignedString(), new UnityTexEnv(reader));
}
if (version[0] >= 2021) //2021.1 and up
if (version >= 2021) //2021.1 and up
{
int m_IntsSize = reader.ReadInt32();
m_Ints = new KeyValuePair<string, int>[m_IntsSize];
@@ -69,39 +69,39 @@ namespace AssetStudio
{
m_Shader = new PPtr<Shader>(reader);
if (version[0] == 4 && version[1] >= 1) //4.x
if (version == 4 && version.Minor >= 1) //4.x
{
var m_ShaderKeywords = reader.ReadStringArray();
}
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 3)) //2021.3 and up
if (version >= (2021, 3)) //2021.3 and up
{
var m_ValidKeywords = reader.ReadStringArray();
var m_InvalidKeywords = reader.ReadStringArray();
}
else if (version[0] >= 5) //5.0 ~ 2021.2
else if (version >= 5) //5.0 ~ 2021.2
{
var m_ShaderKeywords = reader.ReadAlignedString();
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
var m_LightmapFlags = reader.ReadUInt32();
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
var m_EnableInstancingVariants = reader.ReadBoolean();
//var m_DoubleSidedGI = a_Stream.ReadBoolean(); //2017 and up
reader.AlignStream();
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
var m_CustomRenderQueue = reader.ReadInt32();
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 1)) //5.1 and up
if (version >= (5, 1)) //5.1 and up
{
var stringTagMapSize = reader.ReadInt32();
for (int i = 0; i < stringTagMapSize; i++)
@@ -111,7 +111,7 @@ namespace AssetStudio
}
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
var disabledShaderPasses = reader.ReadStringArray();
}

View File

@@ -40,7 +40,7 @@ namespace AssetStudio
m_Vertices = new PackedFloatVector(reader);
m_UV = new PackedFloatVector(reader);
if (version[0] < 5)
if (version < 5)
{
m_BindPoses = new PackedFloatVector(reader);
}
@@ -49,15 +49,15 @@ namespace AssetStudio
m_Weights = new PackedIntVector(reader);
m_NormalSigns = new PackedIntVector(reader);
m_TangentSigns = new PackedIntVector(reader);
if (version[0] >= 5)
if (version >= 5)
{
m_FloatColors = new PackedFloatVector(reader);
}
m_BoneIndices = new PackedIntVector(reader);
m_Triangles = new PackedIntVector(reader);
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 and up
if (version >= (3, 5)) //3.5 and up
{
if (version[0] < 5)
if (version < 5)
{
m_Colors = new PackedIntVector(reader);
}
@@ -87,7 +87,7 @@ namespace AssetStudio
channelMask = reader.ReadUInt32();
offset = reader.ReadUInt32();
if (version[0] < 4) //4.0 down
if (version < 4) //4.0 down
{
stride = reader.ReadUInt32();
align = reader.ReadUInt32();
@@ -131,14 +131,14 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] < 2018)//2018 down
if (version < 2018)//2018 down
{
m_CurrentChannels = reader.ReadUInt32();
}
m_VertexCount = reader.ReadUInt32();
if (version[0] >= 4) //4.0 and up
if (version >= 4) //4.0 and up
{
var m_ChannelsSize = reader.ReadInt32();
m_Channels = new ChannelInfo[m_ChannelsSize];
@@ -148,9 +148,9 @@ namespace AssetStudio
}
}
if (version[0] < 5) //5.0 down
if (version < 5) //5.0 down
{
if (version[0] < 4)
if (version < 4)
{
m_Streams = new StreamInfo[4];
}
@@ -164,7 +164,7 @@ namespace AssetStudio
m_Streams[i] = new StreamInfo(reader);
}
if (version[0] < 4) //4.0 down
if (version < 4) //4.0 down
{
GetChannels(version);
}
@@ -178,7 +178,7 @@ namespace AssetStudio
reader.AlignStream();
}
private void GetStreams(int[] version)
private void GetStreams(UnityVersion version)
{
var streamCount = m_Channels.Max(x => x.stream) + 1;
m_Streams = new StreamInfo[streamCount];
@@ -213,7 +213,7 @@ namespace AssetStudio
}
}
private void GetChannels(int[] version)
private void GetChannels(UnityVersion version)
{
m_Channels = new ChannelInfo[6];
for (int i = 0; i < 6; i++)
@@ -305,20 +305,20 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] == 4 && version[1] < 3) //4.3 down
if (version < (4, 3)) //4.3 down
{
var name = reader.ReadAlignedString();
}
firstVertex = reader.ReadUInt32();
vertexCount = reader.ReadUInt32();
if (version[0] == 4 && version[1] < 3) //4.3 down
if (version < (4, 3)) //4.3 down
{
var aabbMinDelta = reader.ReadVector3();
var aabbMaxDelta = reader.ReadVector3();
}
hasNormals = reader.ReadBoolean();
hasTangents = reader.ReadBoolean();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
reader.AlignStream();
}
@@ -352,7 +352,7 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
int numVerts = reader.ReadInt32();
vertices = new BlendShapeVertex[numVerts];
@@ -425,17 +425,17 @@ namespace AssetStudio
indexCount = reader.ReadUInt32();
topology = (GfxPrimitiveType)reader.ReadInt32();
if (version[0] < 4) //4.0 down
if (version < 4) //4.0 down
{
triangleCount = reader.ReadUInt32();
}
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
if (version >= (2017, 3)) //2017.3 and up
{
baseVertex = reader.ReadUInt32();
}
if (version[0] >= 3) //3.0 and up
if (version >= 3) //3.0 and up
{
firstVertex = reader.ReadUInt32();
vertexCount = reader.ReadUInt32();
@@ -474,12 +474,12 @@ namespace AssetStudio
public Mesh(ObjectReader reader) : base(reader)
{
if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) //3.5 down
if (version < (3, 5)) //3.5 down
{
m_Use16BitIndices = reader.ReadInt32() > 0;
}
if (version[0] == 2 && version[1] <= 5) //2.5 and down
if (version <= (2, 5)) //2.5 and down
{
int m_IndexBuffer_size = reader.ReadInt32();
@@ -505,21 +505,21 @@ namespace AssetStudio
m_SubMeshes[i] = new SubMesh(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
if (version >= (4, 1)) //4.1 and up
{
m_Shapes = new BlendShapeData(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_BindPose = reader.ReadMatrixArray();
m_BoneNameHashes = reader.ReadUInt32Array();
var m_RootBoneNameHash = reader.ReadUInt32();
}
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
if (version >= (2, 6)) //2.6.0 and up
{
if (version[0] >= 2019) //2019 and up
if (version >= 2019) //2019 and up
{
var m_BonesAABBSize = reader.ReadInt32();
var m_BonesAABB = new MinMaxAABB[m_BonesAABBSize];
@@ -532,9 +532,9 @@ namespace AssetStudio
}
var m_MeshCompression = reader.ReadByte();
if (version[0] >= 4)
if (version >= 4)
{
if (version[0] < 5)
if (version < 5)
{
var m_StreamCompression = reader.ReadByte();
}
@@ -545,9 +545,9 @@ namespace AssetStudio
reader.AlignStream();
//Unity fixed it in 2017.3.1p1 and later versions
if ((version[0] > 2017 || (version[0] == 2017 && version[1] >= 4)) || //2017.4
((version[0] == 2017 && version[1] == 3 && version[2] == 1) && buildType.IsPatch) || //fixed after 2017.3.1px
((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression
if (version >= (2017, 4) //2017.4
|| version == (2017, 3, 1) && buildType.IsPatch //fixed after 2017.3.1px
|| version == (2017, 3) && m_MeshCompression == 0)//2017.3.xfx with no compression
{
var m_IndexFormat = reader.ReadInt32();
m_Use16BitIndices = m_IndexFormat == 0;
@@ -569,7 +569,7 @@ namespace AssetStudio
}
}
if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) //3.4.2 and earlier
if (version < (3, 5)) //3.4.2 and earlier
{
m_VertexCount = reader.ReadInt32();
m_Vertices = reader.ReadSingleArray(m_VertexCount * 3); //Vector3
@@ -586,7 +586,7 @@ namespace AssetStudio
m_UV1 = reader.ReadSingleArray(reader.ReadInt32() * 2); //Vector2
if (version[0] == 2 && version[1] <= 5) //2.5 and down
if (version <= (2, 5)) //2.5 and down
{
int m_TangentSpace_size = reader.ReadInt32();
m_Normals = new float[m_TangentSpace_size * 3];
@@ -611,7 +611,7 @@ namespace AssetStudio
}
else
{
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
if (version < (2018, 2)) //2018.2 down
{
m_Skin = new BoneWeights4[reader.ReadInt32()];
for (int s = 0; s < m_Skin.Length; s++)
@@ -620,7 +620,7 @@ namespace AssetStudio
}
}
if (version[0] == 3 || (version[0] == 4 && version[1] <= 2)) //4.2 and down
if (version <= (4, 2)) //4.2 and down
{
m_BindPose = reader.ReadMatrixArray();
}
@@ -628,14 +628,14 @@ namespace AssetStudio
m_VertexData = new VertexData(reader);
}
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and later
if (version >= (2, 6)) //2.6.0 and later
{
m_CompressedMesh = new CompressedMesh(reader);
}
reader.Position += 24; //AABB m_LocalAABB
if (version[0] < 3 || (version[0] == 3 && version[1] <= 4)) //3.4.2 and earlier
if (version <= (3, 4)) //3.4.2 and earlier
{
int m_Colors_size = reader.ReadInt32();
m_Colors = new float[m_Colors_size * 4];
@@ -651,12 +651,12 @@ namespace AssetStudio
int m_MeshUsageFlags = reader.ReadInt32();
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
if (version >= (2022, 1)) //2022.1 and up
{
int m_CookingOptions = reader.ReadInt32();
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
var m_BakedConvexCollisionMesh = reader.ReadUInt8Array();
reader.AlignStream();
@@ -664,14 +664,14 @@ namespace AssetStudio
reader.AlignStream();
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
if (version >= (2018, 2)) //2018.2 and up
{
var m_MeshMetrics = new float[2];
m_MeshMetrics[0] = reader.ReadSingle();
m_MeshMetrics[1] = reader.ReadSingle();
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 3)) //2018.3 and up
if (version >= (2018, 3)) //2018.3 and up
{
reader.AlignStream();
m_StreamData = new StreamingInfo(reader);
@@ -690,12 +690,12 @@ namespace AssetStudio
m_VertexData.m_DataSize = resourceReader.GetData();
}
}
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 and up
if (version >= (3, 5)) //3.5 and up
{
ReadVertexData();
}
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and later
if (version >= (2, 6)) //2.6.0 and later
{
DecompressCompressedMesh();
}
@@ -716,7 +716,7 @@ namespace AssetStudio
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
if (channelMask.Get(chn))
{
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
if (version < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
{
m_Channel.dimension = 4;
}
@@ -752,7 +752,7 @@ namespace AssetStudio
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
if (version[0] >= 2018)
if (version >= 2018)
{
switch (chn)
{
@@ -841,7 +841,7 @@ namespace AssetStudio
m_UV1 = componentsFloatArray;
break;
case 5:
if (version[0] >= 5) //kShaderChannelTexCoord2
if (version >= 5) //kShaderChannelTexCoord2
{
m_UV2 = componentsFloatArray;
}
@@ -906,7 +906,7 @@ namespace AssetStudio
}
}
//BindPose
if (version[0] < 5)
if (version < 5)
{
if (m_CompressedMesh.m_BindPoses.m_NumItems > 0)
{
@@ -983,7 +983,7 @@ namespace AssetStudio
}
}
//FloatColor
if (version[0] >= 5)
if (version >= 5)
{
if (m_CompressedMesh.m_FloatColors.m_NumItems > 0)
{
@@ -1074,7 +1074,7 @@ namespace AssetStudio
m_Indices.Add(m_IndexBuffer[firstIndex + i + 2]);
}
}
else if (version[0] < 4 || topology == GfxPrimitiveType.TriangleStrip)
else if (version < 4 || topology == GfxPrimitiveType.TriangleStrip)
{
// de-stripify :
uint triIndex = 0;
@@ -1238,9 +1238,9 @@ namespace AssetStudio
SInt32
}
public static VertexFormat ToVertexFormat(int format, int[] version)
public static VertexFormat ToVertexFormat(int format, UnityVersion version)
{
if (version[0] < 2017)
if (version < 2017)
{
switch ((VertexChannelFormat)format)
{
@@ -1258,7 +1258,7 @@ namespace AssetStudio
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else if (version[0] < 2019)
else if (version < 2019)
{
switch ((VertexFormat2017)format)
{

View File

@@ -13,11 +13,11 @@ namespace AssetStudio
public MonoScript(ObjectReader reader) : base(reader)
{
if (version[0] > 3 || (version[0] == 3 && version[1] >= 4)) //3.4 and up
if (version >= (3, 4)) //3.4 and up
{
var m_ExecutionOrder = reader.ReadInt32();
}
if (version[0] < 5) //5.0 down
if (version < 5) //5.0 down
{
var m_PropertiesHash = reader.ReadUInt32();
}
@@ -25,17 +25,17 @@ namespace AssetStudio
{
var m_PropertiesHash = reader.ReadBytes(16);
}
if (version[0] < 3) //3.0 down
if (version < 3) //3.0 down
{
var m_PathName = reader.ReadAlignedString();
}
m_ClassName = reader.ReadAlignedString();
if (version[0] >= 3) //3.0 and up
if (version >= 3) //3.0 and up
{
m_Namespace = reader.ReadAlignedString();
}
m_AssemblyName = reader.ReadAlignedString();
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
if (version < (2018, 2)) //2018.2 down
{
var m_IsEditorScript = reader.ReadBoolean();
}

View File

@@ -9,6 +9,8 @@ namespace AssetStudio
{
public string m_Name;
protected NamedObject() { }
protected NamedObject(ObjectReader reader) : base(reader)
{
m_Name = reader.ReadAlignedString();

View File

@@ -1,19 +1,27 @@
using System.Collections.Specialized;
using Newtonsoft.Json;
using System.Collections.Specialized;
namespace AssetStudio
{
public class Object
{
[JsonIgnore]
public SerializedFile assetsFile;
[JsonIgnore]
public ObjectReader reader;
public long m_PathID;
public int[] version;
[JsonIgnore]
public UnityVersion version;
protected BuildType buildType;
[JsonIgnore]
public BuildTarget platform;
public ClassIDType type;
[JsonIgnore]
public SerializedType serializedType;
public uint byteSize;
public Object() { }
public Object(ObjectReader reader)
{
this.reader = reader;
@@ -51,6 +59,24 @@ namespace AssetStudio
return null;
}
public string DumpObject()
{
string str = null;
try
{
str = JsonConvert.SerializeObject(this, new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}).Replace(" ", " ");
}
catch
{
//ignore
}
return str;
}
public OrderedDictionary ToType()
{
if (serializedType?.m_Type != null)

View File

@@ -7,45 +7,47 @@ namespace AssetStudio
public int m_FileID;
public long m_PathID;
private SerializedFile assetsFile;
private int index = -2; //-2 - Prepare, -1 - Missing
private SerializedFile _assetsFile;
private int _index = -2; //-2 - Prepare, -1 - Missing
public PPtr(ObjectReader reader)
{
m_FileID = reader.ReadInt32();
m_PathID = reader.m_Version < SerializedFileFormatVersion.Unknown_14 ? reader.ReadInt32() : reader.ReadInt64();
assetsFile = reader.assetsFile;
_assetsFile = reader.assetsFile;
}
public PPtr() { }
private bool TryGetAssetsFile(out SerializedFile result)
{
result = null;
if (m_FileID == 0)
{
result = assetsFile;
result = _assetsFile;
return true;
}
if (m_FileID > 0 && m_FileID - 1 < assetsFile.m_Externals.Count)
if (m_FileID > 0 && m_FileID - 1 < _assetsFile.m_Externals.Count)
{
var assetsManager = assetsFile.assetsManager;
var assetsManager = _assetsFile.assetsManager;
var assetsFileList = assetsManager.assetsFileList;
var assetsFileIndexCache = assetsManager.assetsFileIndexCache;
if (index == -2)
if (_index == -2)
{
var m_External = assetsFile.m_Externals[m_FileID - 1];
var m_External = _assetsFile.m_Externals[m_FileID - 1];
var name = m_External.fileName;
if (!assetsFileIndexCache.TryGetValue(name, out index))
if (!assetsFileIndexCache.TryGetValue(name, out _index))
{
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, index);
_index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, _index);
}
}
if (index >= 0)
if (_index >= 0)
{
result = assetsFileList[index];
result = assetsFileList[_index];
return true;
}
}
@@ -53,8 +55,9 @@ namespace AssetStudio
return false;
}
public bool TryGet(out T result)
public bool TryGet(out T result, SerializedFile assetsFile = null)
{
_assetsFile = _assetsFile ?? assetsFile;
if (TryGetAssetsFile(out var sourceFile))
{
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
@@ -71,8 +74,9 @@ namespace AssetStudio
return false;
}
public bool TryGet<T2>(out T2 result) where T2 : Object
public bool TryGet<T2>(out T2 result, SerializedFile assetsFile = null) where T2 : Object
{
_assetsFile = _assetsFile ?? assetsFile;
if (TryGetAssetsFile(out var sourceFile))
{
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
@@ -92,20 +96,20 @@ namespace AssetStudio
public void Set(T m_Object)
{
var name = m_Object.assetsFile.fileName;
if (string.Equals(assetsFile.fileName, name, StringComparison.OrdinalIgnoreCase))
if (string.Equals(_assetsFile.fileName, name, StringComparison.OrdinalIgnoreCase))
{
m_FileID = 0;
}
else
{
m_FileID = assetsFile.m_Externals.FindIndex(x => string.Equals(x.fileName, name, StringComparison.OrdinalIgnoreCase));
m_FileID = _assetsFile.m_Externals.FindIndex(x => string.Equals(x.fileName, name, StringComparison.OrdinalIgnoreCase));
if (m_FileID == -1)
{
assetsFile.m_Externals.Add(new FileIdentifier
_assetsFile.m_Externals.Add(new FileIdentifier
{
fileName = m_Object.assetsFile.fileName
});
m_FileID = assetsFile.m_Externals.Count;
m_FileID = _assetsFile.m_Externals.Count;
}
else
{
@@ -113,14 +117,14 @@ namespace AssetStudio
}
}
var assetsManager = assetsFile.assetsManager;
var assetsManager = _assetsFile.assetsManager;
var assetsFileList = assetsManager.assetsFileList;
var assetsFileIndexCache = assetsManager.assetsFileIndexCache;
if (!assetsFileIndexCache.TryGetValue(name, out index))
if (!assetsFileIndexCache.TryGetValue(name, out _index))
{
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, index);
_index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, _index);
}
m_PathID = m_Object.m_PathID;

View File

@@ -12,7 +12,7 @@ namespace AssetStudio
public PlayerSettings(ObjectReader reader) : base(reader)
{
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4.0 nad up
if (version >= (5, 4)) //5.4.0 and up
{
var productGUID = reader.ReadBytes(16);
}
@@ -23,12 +23,12 @@ namespace AssetStudio
reader.AlignStream();
int defaultScreenOrientation = reader.ReadInt32();
int targetDevice = reader.ReadInt32();
if (version[0] < 5 || (version[0] == 5 && version[1] < 3)) //5.3 down
if (version < (5, 3)) //5.3 down
{
if (version[0] < 5) //5.0 down
if (version < 5) //5.0 down
{
int targetPlatform = reader.ReadInt32(); //4.0 and up targetGlesGraphics
if (version[0] > 4 || (version[0] == 4 && version[1] >= 6)) //4.6 and up
if (version >= (4, 6)) //4.6 and up
{
var targetIOSGraphics = reader.ReadInt32();
}
@@ -40,7 +40,7 @@ namespace AssetStudio
var useOnDemandResources = reader.ReadBoolean();
reader.AlignStream();
}
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 and up
if (version >= (3, 5)) //3.5 and up
{
var accelerometerFrequency = reader.ReadInt32();
}

View File

@@ -0,0 +1,35 @@
namespace AssetStudio
{
public sealed class PreloadData : NamedObject
{
public PPtr<Object>[] m_Assets;
public PreloadData(ObjectReader reader) : base(reader)
{
var m_PreloadTableSize = reader.ReadInt32();
m_Assets = new PPtr<Object>[m_PreloadTableSize];
for (var i = 0; i < m_PreloadTableSize; i++)
{
m_Assets[i] = new PPtr<Object>(reader);
}
/*
if (version[0] >= 5) //5.0 and up
{
var m_DependenciesSize = reader.ReadInt32();
var m_Dependencies = new string[m_DependenciesSize];
for (var i = 0; i < m_DependenciesSize; i++)
{
m_Dependencies[i] = reader.ReadAlignedString();
}
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
{
var m_ExplicitDataLayout = reader.ReadBoolean();
}
*/
}
}
}

View File

@@ -25,7 +25,7 @@ namespace AssetStudio
protected Renderer(ObjectReader reader) : base(reader)
{
if (version[0] < 5) //5.0 down
if (version < 5) //5.0 down
{
var m_Enabled = reader.ReadBoolean();
var m_CastShadows = reader.ReadBoolean();
@@ -34,27 +34,27 @@ namespace AssetStudio
}
else //5.0 and up
{
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
if (version >= (5, 4)) //5.4 and up
{
var m_Enabled = reader.ReadBoolean();
var m_CastShadows = reader.ReadByte();
var m_ReceiveShadows = reader.ReadByte();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
var m_DynamicOccludee = reader.ReadByte();
}
if (version[0] >= 2021) //2021.1 and up
if (version >= 2021) //2021.1 and up
{
var m_StaticShadowCaster = reader.ReadByte();
}
var m_MotionVectors = reader.ReadByte();
var m_LightProbeUsage = reader.ReadByte();
var m_ReflectionProbeUsage = reader.ReadByte();
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
if (version >= (2019, 3)) //2019.3 and up
{
var m_RayTracingMode = reader.ReadByte();
}
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
var m_RayTraceProcedural = reader.ReadByte();
}
@@ -69,12 +69,12 @@ namespace AssetStudio
reader.AlignStream();
}
if (version[0] >= 2018) //2018 and up
if (version >= 2018) //2018 and up
{
var m_RenderingLayerMask = reader.ReadUInt32();
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 3)) //2018.3 and up
if (version >= (2018, 3)) //2018.3 and up
{
var m_RendererPriority = reader.ReadInt32();
}
@@ -83,12 +83,12 @@ namespace AssetStudio
var m_LightmapIndexDynamic = reader.ReadUInt16();
}
if (version[0] >= 3) //3.0 and up
if (version >= 3) //3.0 and up
{
var m_LightmapTilingOffset = reader.ReadVector4();
}
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
var m_LightmapTilingOffsetDynamic = reader.ReadVector4();
}
@@ -100,13 +100,13 @@ namespace AssetStudio
m_Materials[i] = new PPtr<Material>(reader);
}
if (version[0] < 3) //3.0 down
if (version < 3) //3.0 down
{
var m_LightmapTilingOffset = reader.ReadVector4();
}
else //3.0 and up
{
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
if (version >= (5, 5)) //5.5 and up
{
m_StaticBatchInfo = new StaticBatchInfo(reader);
}
@@ -118,17 +118,17 @@ namespace AssetStudio
var m_StaticBatchRoot = new PPtr<Transform>(reader);
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
if (version >= (5, 4)) //5.4 and up
{
var m_ProbeAnchor = new PPtr<Transform>(reader);
var m_LightProbeVolumeOverride = new PPtr<GameObject>(reader);
}
else if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 - 5.3
else if (version >= (3, 5)) //3.5 - 5.3
{
var m_UseLightProbes = reader.ReadBoolean();
reader.AlignStream();
if (version[0] >= 5)//5.0 and up
if (version >= 5)//5.0 and up
{
var m_ReflectionProbeUsage = reader.ReadInt32();
}
@@ -136,9 +136,9 @@ namespace AssetStudio
var m_LightProbeAnchor = new PPtr<Transform>(reader); //5.0 and up m_ProbeAnchor
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
if (version[0] == 4 && version[1] == 3) //4.3
if (version == (4, 3)) //4.3
{
var m_SortingLayer = reader.ReadInt16();
}

View File

@@ -243,14 +243,14 @@ namespace AssetStudio
}
rtSeparateBlend = reader.ReadBoolean();
reader.AlignStream();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
zClip = new SerializedShaderFloatValue(reader);
}
zTest = new SerializedShaderFloatValue(reader);
zWrite = new SerializedShaderFloatValue(reader);
culling = new SerializedShaderFloatValue(reader);
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
conservative = new SerializedShaderFloatValue(reader);
}
@@ -359,7 +359,7 @@ namespace AssetStudio
m_NameIndex = reader.ReadInt32();
m_Index = reader.ReadInt32();
m_SamplerIndex = reader.ReadInt32();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
if (version >= (2017, 3)) //2017.3 and up
{
var m_MultiSampled = reader.ReadBoolean();
}
@@ -380,7 +380,7 @@ namespace AssetStudio
m_NameIndex = reader.ReadInt32();
m_Index = reader.ReadInt32();
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
m_ArraySize = reader.ReadInt32();
}
@@ -415,7 +415,7 @@ namespace AssetStudio
{
m_VectorParams[i] = new VectorParameter(reader);
}
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
if (version >= (2017, 3)) //2017.3 and up
{
int numStructParams = reader.ReadInt32();
m_StructParams = new StructParameter[numStructParams];
@@ -426,11 +426,8 @@ namespace AssetStudio
}
m_Size = reader.ReadInt32();
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
(version[0] > 2021) ||
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 and up
if (version.IsInRange((2020, 3, 2), 2021) //2020.3.2f1 and up
|| version >= (2021, 1, 4)) //2021.1.4f1 and up
{
m_IsPartialCB = reader.ReadBoolean();
reader.AlignStream();
@@ -584,7 +581,7 @@ namespace AssetStudio
m_BlobIndex = reader.ReadUInt32();
m_Channels = new ParserBindChannels(reader);
if ((version[0] >= 2019 && version[0] < 2021) || (version[0] == 2021 && version[1] < 2)) //2019 ~2021.1
if (version.IsInRange(2019, (2021, 2))) //2019 ~2021.1
{
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
reader.AlignStream();
@@ -594,7 +591,7 @@ namespace AssetStudio
else
{
m_KeywordIndices = reader.ReadUInt16Array();
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
reader.AlignStream();
}
@@ -604,11 +601,8 @@ namespace AssetStudio
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
reader.AlignStream();
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
(version[0] > 2021) ||
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
if (version.IsInRange((2020, 3, 2), 2021) //2020.3.2f1 and up
|| version >= (2021, 1, 1)) //2021.1.1f1 and up
{
m_Parameters = new SerializedProgramParameters(reader);
}
@@ -663,7 +657,7 @@ namespace AssetStudio
m_UAVParams[i] = new UAVParameter(reader);
}
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
int numSamplers = reader.ReadInt32();
m_Samplers = new SamplerParameter[numSamplers];
@@ -674,9 +668,9 @@ namespace AssetStudio
}
}
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
if (version[0] >= 2021) //2021.1 and up
if (version >= 2021) //2021.1 and up
{
var m_ShaderRequirements = reader.ReadInt64();
}
@@ -705,16 +699,13 @@ namespace AssetStudio
m_SubPrograms[i] = new SerializedSubProgram(reader);
}
if ((version[0] == 2020 && version[1] > 3) ||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
(version[0] > 2021) ||
(version[0] == 2021 && version[1] > 1) ||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
if (version.IsInRange((2020, 3, 2), 2021) //2020.3.2f1 and up
|| version >= (2021, 1, 1)) //2021.1.1f1 and up
{
m_CommonParameters = new SerializedProgramParameters(reader);
}
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
if (version >= (2022, 1)) //2022.1 and up
{
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
reader.AlignStream();
@@ -756,7 +747,7 @@ namespace AssetStudio
{
var version = reader.version;
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
if (version >= (2020, 2)) //2020.2 and up
{
int numEditorDataHash = reader.ReadInt32();
m_EditorDataHash = new Hash128[numEditorDataHash];
@@ -767,7 +758,7 @@ namespace AssetStudio
reader.AlignStream();
m_Platforms = reader.ReadUInt8Array();
reader.AlignStream();
if (version[0] < 2021 || (version[0] == 2021 && version[1] < 2)) //2021.1 and down
if (version <= (2021, 1)) //2021.1 and down
{
m_LocalKeywordMask = reader.ReadUInt16Array();
reader.AlignStream();
@@ -791,12 +782,12 @@ namespace AssetStudio
progGeometry = new SerializedProgram(reader);
progHull = new SerializedProgram(reader);
progDomain = new SerializedProgram(reader);
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
if (version >= (2019, 3)) //2019.3 and up
{
progRayTracing = new SerializedProgram(reader);
}
m_HasInstancingVariant = reader.ReadBoolean();
if (version[0] >= 2018) //2018 and up
if (version >= 2018) //2018 and up
{
var m_HasProceduralInstancingVariant = reader.ReadBoolean();
}
@@ -805,7 +796,7 @@ namespace AssetStudio
m_Name = reader.ReadAlignedString();
m_TextureName = reader.ReadAlignedString();
m_Tags = new SerializedTagMap(reader);
if (version[0] == 2021 && version[1] >= 2) //2021.2 ~2021.x
if (version == 2021 && version.Minor >= 2) //2021.2 ~2021.x
{
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
reader.AlignStream();
@@ -898,7 +889,7 @@ namespace AssetStudio
m_SubShaders[i] = new SerializedSubShader(reader);
}
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
if (version >= (2021, 2)) //2021.2 and up
{
m_KeywordNames = reader.ReadStringArray();
m_KeywordFlags = reader.ReadUInt8Array();
@@ -916,7 +907,7 @@ namespace AssetStudio
m_Dependencies[i] = new SerializedShaderDependency(reader);
}
if (version[0] >= 2021) //2021.1 and up
if (version >= 2021) //2021.1 and up
{
int m_CustomEditorForRenderPipelinesSize = reader.ReadInt32();
m_CustomEditorForRenderPipelines = new SerializedCustomEditorForRenderPipeline[m_CustomEditorForRenderPipelinesSize];
@@ -977,11 +968,11 @@ namespace AssetStudio
public Shader(ObjectReader reader) : base(reader)
{
if (version[0] == 5 && version[1] >= 5 || version[0] > 5) //5.5 and up
if (version >= (5, 5)) //5.5 and up
{
m_ParsedForm = new SerializedShader(reader);
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
if (version >= (2019, 3)) //2019.3 and up
{
offsets = reader.ReadUInt32ArrayArray();
compressedLengths = reader.ReadUInt32ArrayArray();
@@ -1002,7 +993,7 @@ namespace AssetStudio
new PPtr<Shader>(reader);
}
if (version[0] >= 2018)
if (version >= 2018)
{
var m_NonModifiableTexturesCount = reader.ReadInt32();
for (int i = 0; i < m_NonModifiableTexturesCount; i++)
@@ -1020,7 +1011,7 @@ namespace AssetStudio
m_Script = reader.ReadUInt8Array();
reader.AlignStream();
var m_PathName = reader.ReadAlignedString();
if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4
if (version == 5 && version.Minor >= 3) //5.3 - 5.4
{
decompressedSize = reader.ReadUInt32();
m_SubProgramBlob = reader.ReadUInt8Array();

View File

@@ -18,7 +18,7 @@ namespace AssetStudio
var m_SkinNormals = reader.ReadBoolean(); //3.1.0 and below
reader.AlignStream();
if (version[0] == 2 && version[1] < 6) //2.6 down
if (version < (2, 6)) //2.6 down
{
var m_DisableAnimationWhenOffscreen = new PPtr<Animation>(reader);
}
@@ -31,7 +31,7 @@ namespace AssetStudio
m_Bones[b] = new PPtr<Transform>(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
if (version >= (4, 3)) //4.3 and up
{
m_BlendShapeWeights = reader.ReadSingleArray();
}

View File

@@ -12,7 +12,7 @@ namespace AssetStudio
public SecondarySpriteTexture(ObjectReader reader)
{
texture = new PPtr<Texture2D>(reader);
name = reader.ReadStringToNull();
name = reader.ReadAlignedString();
}
}
@@ -68,7 +68,7 @@ namespace AssetStudio
var version = reader.version;
pos = reader.ReadVector3();
if (version[0] < 4 || (version[0] == 4 && version[1] <= 3)) //4.3 and down
if (version <= (4, 3)) //4.3 and down
{
uv = reader.ReadVector2();
}
@@ -99,12 +99,12 @@ namespace AssetStudio
var version = reader.version;
texture = new PPtr<Texture2D>(reader);
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
if (version >= (5, 2)) //5.2 and up
{
alphaTexture = new PPtr<Texture2D>(reader);
}
if (version[0] >= 2019) //2019 and up
if (version >= 2019) //2019 and up
{
var secondaryTexturesSize = reader.ReadInt32();
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
@@ -114,7 +114,7 @@ namespace AssetStudio
}
}
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
var m_SubMeshesSize = reader.ReadInt32();
m_SubMeshes = new SubMesh[m_SubMeshesSize];
@@ -141,11 +141,11 @@ namespace AssetStudio
reader.AlignStream();
}
if (version[0] >= 2018) //2018 and up
if (version >= 2018) //2018 and up
{
m_Bindpose = reader.ReadMatrixArray();
if (version[0] == 2018 && version[1] < 2) //2018.2 down
if (version < (2018, 2)) //2018.2 down
{
var m_SourceSkinSize = reader.ReadInt32();
for (int i = 0; i < m_SourceSkinSize; i++)
@@ -157,18 +157,18 @@ namespace AssetStudio
textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
atlasRectOffset = reader.ReadVector2();
}
settingsRaw = new SpriteSettings(reader);
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
if (version >= (4, 5)) //4.5 and up
{
uvTransform = reader.ReadVector4();
}
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
downscaleMultiplier = reader.ReadSingle();
}
@@ -210,28 +210,26 @@ namespace AssetStudio
{
m_Rect = new Rectf(reader);
m_Offset = reader.ReadVector2();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
if (version >= (4, 5)) //4.5 and up
{
m_Border = reader.ReadVector4();
}
m_PixelsToUnits = reader.ReadSingle();
if (version[0] > 5
|| (version[0] == 5 && version[1] > 4)
|| (version[0] == 5 && version[1] == 4 && version[2] >= 2)
|| (version[0] == 5 && version[1] == 4 && version[2] == 1 && buildType.IsPatch && version[3] >= 3)) //5.4.1p3 and up
if (version >= (5, 4, 2)
|| version == (5, 4, 1) && buildType.IsPatch && version.Build >= 3) //5.4.1p3 and up
{
m_Pivot = reader.ReadVector2();
}
m_Extrude = reader.ReadUInt32();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up
if (version >= (5, 3)) //5.3 and up
{
m_IsPolygon = reader.ReadBoolean();
reader.AlignStream();
}
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
var first = new Guid(reader.ReadBytes(16));
var second = reader.ReadInt64();
@@ -244,7 +242,7 @@ namespace AssetStudio
m_RD = new SpriteRenderData(reader);
if (version[0] >= 2017) //2017 and up
if (version >= 2017) //2017 and up
{
var m_PhysicsShapeSize = reader.ReadInt32();
m_PhysicsShape = new Vector2[m_PhysicsShapeSize][];

View File

@@ -22,14 +22,14 @@ namespace AssetStudio
alphaTexture = new PPtr<Texture2D>(reader);
textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
atlasRectOffset = reader.ReadVector2();
}
uvTransform = reader.ReadVector4();
downscaleMultiplier = reader.ReadSingle();
settingsRaw = new SpriteSettings(reader);
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
if (version >= (2020, 2)) //2020.2 and up
{
var secondaryTexturesSize = reader.ReadInt32();
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];

View File

@@ -0,0 +1,27 @@
namespace AssetStudio
{
public class StreamingInfo
{
public long offset; //ulong
public uint size;
public string path;
public StreamingInfo() { }
public StreamingInfo(ObjectReader reader)
{
var version = reader.version;
if (version >= 2020) //2020.1 and up
{
offset = reader.ReadInt64();
}
else
{
offset = reader.ReadUInt32();
}
size = reader.ReadUInt32();
path = reader.ReadAlignedString();
}
}
}

View File

@@ -1,19 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssetStudio
namespace AssetStudio
{
public abstract class Texture : NamedObject
{
protected Texture() { }
protected Texture(ObjectReader reader) : base(reader)
{
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
if (version >= (2017, 3)) //2017.3 and up
{
var m_ForcedFallbackFormat = reader.ReadInt32();
var m_DownscaleFallback = reader.ReadBoolean();
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
if (version < (2023, 2)) //2023.2 down
{
var m_ForcedFallbackFormat = reader.ReadInt32();
var m_DownscaleFallback = reader.ReadBoolean();
}
if (version >= (2020, 2)) //2020.2 and up
{
var m_IsAlphaChannelOptional = reader.ReadBoolean();
}

View File

@@ -1,79 +1,89 @@
using System;
using System.Collections;
using Newtonsoft.Json;
namespace AssetStudio
{
public class StreamingInfo
{
public long offset; //ulong
public uint size;
public string path;
public StreamingInfo(ObjectReader reader)
{
var version = reader.version;
if (version[0] >= 2020) //2020.1 and up
{
offset = reader.ReadInt64();
}
else
{
offset = reader.ReadUInt32();
}
size = reader.ReadUInt32();
path = reader.ReadAlignedString();
}
}
public class GLTextureSettings
{
public int m_FilterMode;
public int m_Aniso;
public float m_MipBias;
public int m_WrapMode;
public GLTextureSettings(ObjectReader reader)
{
var version = reader.version;
m_FilterMode = reader.ReadInt32();
m_Aniso = reader.ReadInt32();
m_MipBias = reader.ReadSingle();
if (version[0] >= 2017)//2017.x and up
{
m_WrapMode = reader.ReadInt32(); //m_WrapU
int m_WrapV = reader.ReadInt32();
int m_WrapW = reader.ReadInt32();
}
else
{
m_WrapMode = reader.ReadInt32();
}
}
}
public sealed class Texture2D : Texture
{
public int m_Width;
public int m_Height;
public int m_CompleteImageSize;
public TextureFormat m_TextureFormat;
public bool m_MipMap;
public int m_MipCount;
public GLTextureSettings m_TextureSettings;
public int m_ImageCount;
public byte[] m_PlatformBlob;
public ResourceReader image_data;
public StreamingInfo m_StreamData;
public Texture2D() { }
public Texture2D(Texture2DArray m_Texture2DArray, int layer) // Texture2DArrayImage
{
reader = m_Texture2DArray.reader;
assetsFile = m_Texture2DArray.assetsFile;
version = m_Texture2DArray.version;
platform = m_Texture2DArray.platform;
m_Name = $"{m_Texture2DArray.m_Name}_{layer + 1}";
type = ClassIDType.Texture2DArrayImage;
m_PathID = m_Texture2DArray.m_PathID;
m_Width = m_Texture2DArray.m_Width;
m_Height = m_Texture2DArray.m_Height;
m_TextureFormat = m_Texture2DArray.m_Format.ToTextureFormat();
m_MipCount = m_Texture2DArray.m_MipCount;
m_TextureSettings = m_Texture2DArray.m_TextureSettings;
m_StreamData = m_Texture2DArray.m_StreamData;
m_PlatformBlob = Array.Empty<byte>();
m_MipMap = m_MipCount > 1;
m_ImageCount = 1;
//var imgActualDataSize = GetImageDataSize(m_TextureFormat);
//var mipmapSize = (int)(m_Texture2DArray.m_DataSize / m_Texture2DArray.m_Depth - imgActualDataSize);
m_CompleteImageSize = (int)m_Texture2DArray.m_DataSize / m_Texture2DArray.m_Depth;
var offset = layer * m_CompleteImageSize + m_Texture2DArray.image_data.Offset;
image_data = !string.IsNullOrEmpty(m_StreamData?.path)
? new ResourceReader(m_StreamData.path, assetsFile, offset, m_CompleteImageSize)
: new ResourceReader(reader, offset, m_CompleteImageSize);
byteSize = (uint)(m_Width * m_Height) * 4;
}
public Texture2D(ObjectReader reader, IDictionary typeDict) : base(reader)
{
var parsedTex2d = JsonConvert.DeserializeObject<Texture2D>(JsonConvert.SerializeObject(typeDict));
m_Width = parsedTex2d.m_Width;
m_Height = parsedTex2d.m_Height;
m_CompleteImageSize = parsedTex2d.m_CompleteImageSize;
m_TextureFormat = parsedTex2d.m_TextureFormat;
m_MipMap = parsedTex2d.m_MipMap;
m_MipCount = parsedTex2d.m_MipCount;
m_ImageCount = parsedTex2d.m_ImageCount;
m_TextureSettings = parsedTex2d.m_TextureSettings;
m_StreamData = parsedTex2d.m_StreamData;
m_PlatformBlob = parsedTex2d.m_PlatformBlob ?? Array.Empty<byte>();
image_data = !string.IsNullOrEmpty(m_StreamData?.path)
? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size)
: new ResourceReader(reader, parsedTex2d.image_data.Offset, parsedTex2d.image_data.Size);
typeDict.Clear();
}
public Texture2D(ObjectReader reader) : base(reader)
{
m_Width = reader.ReadInt32();
m_Height = reader.ReadInt32();
var m_CompleteImageSize = reader.ReadInt32();
if (version[0] >= 2020) //2020.1 and up
m_CompleteImageSize = reader.ReadInt32();
if (version >= 2020) //2020.1 and up
{
var m_MipsStripped = reader.ReadInt32();
}
m_TextureFormat = (TextureFormat)reader.ReadInt32();
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
if (version < (5, 2)) //5.2 down
{
m_MipMap = reader.ReadBoolean();
}
@@ -81,140 +91,132 @@ namespace AssetStudio
{
m_MipCount = reader.ReadInt32();
}
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
if (version >= (2, 6)) //2.6.0 and up
{
var m_IsReadable = reader.ReadBoolean();
}
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
var m_IsPreProcessed = reader.ReadBoolean();
}
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
if (version >= (2019, 3)) //2019.3 and up
{
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
}
if (version[0] >= 3) //3.0.0 - 5.4
{
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
if (version >= (2022, 2)) //2022.2 and up
{
var m_ReadAllowed = reader.ReadBoolean();
var m_IgnoreMipmapLimit = reader.ReadBoolean();
reader.AlignStream();
}
else
{
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
}
}
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
if (version.IsInRange(3, (5, 5))) //3.0.0 - 5.4
{
var m_ReadAllowed = reader.ReadBoolean();
}
if (version >= (2022, 2)) //2022.2 and up
{
var m_MipmapLimitGroupName = reader.ReadAlignedString();
}
if (version >= (2018, 2)) //2018.2 and up
{
var m_StreamingMipmaps = reader.ReadBoolean();
}
reader.AlignStream();
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
if (version >= (2018, 2)) //2018.2 and up
{
var m_StreamingMipmapsPriority = reader.ReadInt32();
}
var m_ImageCount = reader.ReadInt32();
m_ImageCount = reader.ReadInt32();
var m_TextureDimension = reader.ReadInt32();
m_TextureSettings = new GLTextureSettings(reader);
if (version[0] >= 3) //3.0 and up
if (version >= 3) //3.0 and up
{
var m_LightmapFormat = reader.ReadInt32();
}
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5.0 and up
if (version >= (3, 5)) //3.5.0 and up
{
var m_ColorSpace = reader.ReadInt32();
}
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
if (version >= (2020, 2)) //2020.2 and up
{
var m_PlatformBlob = reader.ReadUInt8Array();
m_PlatformBlob = reader.ReadUInt8Array();
reader.AlignStream();
}
else
{
m_PlatformBlob = Array.Empty<byte>();
}
var image_data_size = reader.ReadInt32();
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
if (image_data_size == 0 && version >= (5, 3))//5.3.0 and up
{
m_StreamData = new StreamingInfo(reader);
}
ResourceReader resourceReader;
if (!string.IsNullOrEmpty(m_StreamData?.path))
image_data = !string.IsNullOrEmpty(m_StreamData?.path)
? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size)
: new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
}
// https://docs.unity3d.com/2023.3/Documentation/Manual/class-TextureImporterOverride.html
private int GetImageDataSize(TextureFormat textureFormat)
{
var imgDataSize = m_Width * m_Height;
switch (textureFormat)
{
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
case TextureFormat.ASTC_RGBA_5x5:
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/
imgDataSize = (int)(Math.Floor((m_Width + 4) / 5f) * Math.Floor((m_Height + 4) / 5f) * 16);
break;
case TextureFormat.ASTC_RGBA_6x6:
imgDataSize = (int)(Math.Floor((m_Width + 5) / 6f) * Math.Floor((m_Height + 5) / 6f) * 16);
break;
case TextureFormat.ASTC_RGBA_8x8:
imgDataSize = (int)(Math.Floor((m_Width + 7) / 8f) * Math.Floor((m_Height + 7) / 8f) * 16);
break;
case TextureFormat.ASTC_RGBA_10x10:
imgDataSize = (int)(Math.Floor((m_Width + 9) / 10f) * Math.Floor((m_Height + 9) / 10f) * 16);
break;
case TextureFormat.ASTC_RGBA_12x12:
imgDataSize = (int)(Math.Floor((m_Width + 11) / 12f) * Math.Floor((m_Height + 11) / 12f) * 16);
break;
case TextureFormat.DXT1:
case TextureFormat.EAC_R:
case TextureFormat.EAC_R_SIGNED:
case TextureFormat.ATC_RGB4:
case TextureFormat.ETC_RGB4:
case TextureFormat.ETC2_RGB:
case TextureFormat.ETC2_RGBA1:
case TextureFormat.PVRTC_RGBA4:
imgDataSize /= 2;
break;
case TextureFormat.PVRTC_RGBA2:
imgDataSize /= 4;
break;
case TextureFormat.R16:
case TextureFormat.RGB565:
imgDataSize *= 2;
break;
case TextureFormat.RGB24:
imgDataSize *= 3;
break;
case TextureFormat.RG32:
case TextureFormat.RGBA32:
case TextureFormat.ARGB32:
case TextureFormat.BGRA32:
case TextureFormat.RGB9e5Float:
imgDataSize *= 4;
break;
case TextureFormat.RGB48:
imgDataSize *= 6;
break;
case TextureFormat.RGBAHalf:
case TextureFormat.RGBA64:
imgDataSize *= 8;
break;
}
else
{
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
}
image_data = resourceReader;
return imgDataSize;
}
}
public enum TextureFormat
{
Alpha8 = 1,
ARGB4444,
RGB24,
RGBA32,
ARGB32,
ARGBFloat,
RGB565,
BGR24,
R16,
DXT1,
DXT3,
DXT5,
RGBA4444,
BGRA32,
RHalf,
RGHalf,
RGBAHalf,
RFloat,
RGFloat,
RGBAFloat,
YUY2,
RGB9e5Float,
RGBFloat,
BC6H,
BC7,
BC4,
BC5,
DXT1Crunched,
DXT5Crunched,
PVRTC_RGB2,
PVRTC_RGBA2,
PVRTC_RGB4,
PVRTC_RGBA4,
ETC_RGB4,
ATC_RGB4,
ATC_RGBA8,
EAC_R = 41,
EAC_R_SIGNED,
EAC_RG,
EAC_RG_SIGNED,
ETC2_RGB,
ETC2_RGBA1,
ETC2_RGBA8,
ASTC_RGB_4x4,
ASTC_RGB_5x5,
ASTC_RGB_6x6,
ASTC_RGB_8x8,
ASTC_RGB_10x10,
ASTC_RGB_12x12,
ASTC_RGBA_4x4,
ASTC_RGBA_5x5,
ASTC_RGBA_6x6,
ASTC_RGBA_8x8,
ASTC_RGBA_10x10,
ASTC_RGBA_12x12,
ETC_RGB4_3DS,
ETC_RGBA8_3DS,
RG16,
R8,
ETC_RGB4Crunched,
ETC2_RGBA8Crunched,
ASTC_HDR_4x4,
ASTC_HDR_5x5,
ASTC_HDR_6x6,
ASTC_HDR_8x8,
ASTC_HDR_10x10,
ASTC_HDR_12x12,
RG32,
RGB48,
RGBA64
}
}

View File

@@ -0,0 +1,73 @@
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
namespace AssetStudio
{
public sealed class Texture2DArray : Texture
{
public int m_Width;
public int m_Height;
public int m_Depth;
public GraphicsFormat m_Format;
public int m_MipCount;
public uint m_DataSize;
public GLTextureSettings m_TextureSettings;
public int m_ColorSpace;
public ResourceReader image_data;
public StreamingInfo m_StreamData;
public List<Texture2D> TextureList;
public Texture2DArray() { }
public Texture2DArray(ObjectReader reader) : base(reader)
{
m_ColorSpace = reader.ReadInt32();
m_Format = (GraphicsFormat)reader.ReadInt32();
m_Width = reader.ReadInt32();
m_Height = reader.ReadInt32();
m_Depth = reader.ReadInt32();
m_MipCount = reader.ReadInt32();
m_DataSize = reader.ReadUInt32();
m_TextureSettings = new GLTextureSettings(reader);
if (version >= (2020, 2)) //2020.2 and up
{
var m_UsageMode = reader.ReadInt32();
}
var m_IsReadable = reader.ReadBoolean();
reader.AlignStream();
var image_data_size = reader.ReadInt32();
if (image_data_size == 0)
{
m_StreamData = new StreamingInfo(reader);
}
image_data = !string.IsNullOrEmpty(m_StreamData?.path)
? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, (int)m_StreamData.size)
: new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
TextureList = new List<Texture2D>();
}
public Texture2DArray(ObjectReader reader, IDictionary typeDict) : base(reader)
{
var parsedTex2dArray = JsonConvert.DeserializeObject<Texture2DArray>(JsonConvert.SerializeObject(typeDict));
m_Width = parsedTex2dArray.m_Width;
m_Height = parsedTex2dArray.m_Height;
m_Depth = parsedTex2dArray.m_Depth;
m_Format = parsedTex2dArray.m_Format;
m_MipCount = parsedTex2dArray.m_MipCount;
m_DataSize = parsedTex2dArray.m_DataSize;
m_TextureSettings = parsedTex2dArray.m_TextureSettings;
m_StreamData = parsedTex2dArray.m_StreamData;
image_data = !string.IsNullOrEmpty(m_StreamData?.path)
? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size)
: new ResourceReader(reader, parsedTex2dArray.image_data.Offset, parsedTex2dArray.image_data.Size);
typeDict.Clear();
TextureList = new List<Texture2D>();
}
}
}

View File

@@ -0,0 +1,282 @@
namespace AssetStudio
{
public enum TextureFormat
{
/// <summary>
/// Alpha-only texture format, 8 bit integer.
/// </summary>
Alpha8 = 1,
/// <summary>
/// A 16 bits/pixel texture format. Texture stores color with an alpha channel.
/// </summary>
ARGB4444,
/// <summary>
/// Three channel (RGB) texture format, 8-bits unsigned integer per channel.
/// </summary>
RGB24,
/// <summary>
/// Four channel (RGBA) texture format, 8-bits unsigned integer per channel.
/// </summary>
RGBA32,
/// <summary>
/// Color with alpha texture format, 8-bits per channel.
/// </summary>
ARGB32,
/// <summary>
/// </summary>
ARGBFloat,
/// <summary>
/// A 16 bit color texture format.
/// </summary>
RGB565,
/// <summary>
/// </summary>
BGR24,
/// <summary>
/// Single channel (R) texture format, 16 bit integer.
/// </summary>
R16,
/// <summary>
/// Compressed color texture format.
/// </summary>
DXT1,
/// <summary>
/// </summary>
DXT3,
/// <summary>
/// Compressed color with alpha channel texture format.
/// </summary>
DXT5,
/// <summary>
/// Color and alpha texture format, 4 bit per channel.
/// </summary>
RGBA4444,
/// <summary>
/// Color with alpha texture format, 8-bits per channel.
/// </summary>
BGRA32,
/// <summary>
/// Scalar (R) texture format, 16 bit floating point.
/// </summary>
RHalf,
/// <summary>
/// Two color (RG) texture format, 16 bit floating point per channel.
/// </summary>
RGHalf,
/// <summary>
/// RGB color and alpha texture format, 16 bit floating point per channel.
/// </summary>
RGBAHalf,
/// <summary>
/// Scalar (R) texture format, 32 bit floating point.
/// </summary>
RFloat,
/// <summary>
/// Two color (RG) texture format, 32 bit floating point per channel.
/// </summary>
RGFloat,
/// <summary>
/// RGB color and alpha texture format, 32-bit floats per channel.
/// </summary>
RGBAFloat,
/// <summary>
/// A format that uses the YUV color space and is often used for video encoding or playback.
/// </summary>
YUY2,
/// <summary>
/// RGB HDR format, with 9 bit mantissa per channel and a 5 bit shared exponent.
/// </summary>
RGB9e5Float,
/// <summary>
/// </summary>
RGBFloat,
/// <summary>
/// HDR compressed color texture format.
/// </summary>
BC6H,
/// <summary>
/// High quality compressed color texture format.
/// </summary>
BC7,
/// <summary>
/// Compressed one channel (R) texture format.
/// </summary>
BC4,
/// <summary>
/// Compressed two-channel (RG) texture format.
/// </summary>
BC5,
/// <summary>
/// Compressed color texture format with Crunch compression for smaller storage sizes.
/// </summary>
DXT1Crunched,
/// <summary>
/// Compressed color with alpha channel texture format with Crunch compression for smaller storage sizes.
/// </summary>
DXT5Crunched,
/// <summary>
/// PowerVR (iOS) 2 bits/pixel compressed color texture format.
/// </summary>
PVRTC_RGB2,
/// <summary>
/// PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format.
/// </summary>
PVRTC_RGBA2,
/// <summary>
/// PowerVR (iOS) 4 bits/pixel compressed color texture format.
/// </summary>
PVRTC_RGB4,
/// <summary>
/// PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format.
/// </summary>
PVRTC_RGBA4,
/// <summary>
/// ETC (GLES2.0) 4 bits/pixel compressed RGB texture format.
/// </summary>
ETC_RGB4,
/// <summary>
/// ATC (ATITC) 4 bits/pixel compressed RGB texture format.
/// </summary>
ATC_RGB4,
/// <summary>
/// ATC (ATITC) 8 bits/pixel compressed RGB texture format.
/// </summary>
ATC_RGBA8,
/// <summary>
/// ETC2 / EAC (GL ES 3.0) 4 bits/pixel compressed unsigned single-channel texture format.
/// </summary>
EAC_R = 41,
/// <summary>
/// ETC2 / EAC (GL ES 3.0) 4 bits/pixel compressed signed single-channel texture format.
/// </summary>
EAC_R_SIGNED,
/// <summary>
/// ETC2 / EAC (GL ES 3.0) 8 bits/pixel compressed unsigned dual-channel (RG) texture format.
/// </summary>
EAC_RG,
/// <summary>
/// ETC2 / EAC (GL ES 3.0) 8 bits/pixel compressed signed dual-channel (RG) texture format.
/// </summary>
EAC_RG_SIGNED,
/// <summary>
/// ETC2 (GL ES 3.0) 4 bits/pixel compressed RGB texture format.
/// </summary>
ETC2_RGB,
/// <summary>
/// ETC2 (GL ES 3.0) 4 bits/pixel RGB+1-bit alpha texture format.
/// </summary>
ETC2_RGBA1,
/// <summary>
/// ETC2 (GL ES 3.0) 8 bits/pixel compressed RGBA texture format.
/// </summary>
ETC2_RGBA8,
/// <summary>
/// ASTC (4x4 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_4x4,
/// <summary>
/// ASTC (5x5 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_5x5,
/// <summary>
/// ASTC (6x6 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_6x6,
/// <summary>
/// ASTC (8x8 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_8x8,
/// <summary>
/// ASTC (10x10 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_10x10,
/// <summary>
/// ASTC (12x12 pixel block in 128 bits) compressed RGB texture format.
/// </summary>
ASTC_RGB_12x12,
/// <summary>
/// ASTC (4x4 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_4x4,
/// <summary>
/// ASTC (5x5 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_5x5,
/// <summary>
/// ASTC (6x6 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_6x6,
/// <summary>
/// ASTC (8x8 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_8x8,
/// <summary>
/// ASTC (10x10 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_10x10,
/// <summary>
/// ASTC (12x12 pixel block in 128 bits) compressed RGBA texture format.
/// </summary>
ASTC_RGBA_12x12,
/// <summary>
/// ETC 4 bits/pixel compressed RGB texture format.
/// </summary>
ETC_RGB4_3DS,
/// <summary>
/// ETC 4 bits/pixel RGB + 4 bits/pixel Alpha compressed texture format.
/// </summary>
ETC_RGBA8_3DS,
/// <summary>
/// Two color (RG) texture format, 8-bits per channel.
/// </summary>
RG16,
/// <summary>
/// Single channel (R) texture format, 8 bit integer.
/// </summary>
R8,
/// <summary>
/// Compressed color texture format with Crunch compression for smaller storage sizes.
/// </summary>
ETC_RGB4Crunched,
/// <summary>
/// Compressed color with alpha channel texture format using Crunch compression for smaller storage sizes.
/// </summary>
ETC2_RGBA8Crunched,
/// <summary>
/// ASTC (4x4 pixel block in 128 bits) compressed RGB(A) HDR texture format.
/// </summary>
ASTC_HDR_4x4,
/// <summary>
/// ASTC (5x5 pixel block in 128 bits) compressed RGB(A) HDR texture format.
/// </summary>
ASTC_HDR_5x5,
/// <summary>
/// ASTC (6x6 pixel block in 128 bits) compressed RGB(A) HDR texture format.
/// </summary>
ASTC_HDR_6x6,
/// <summary>
/// ASTC (8x8 pixel block in 128 bits) compressed RGB(A) texture format.
/// </summary>
ASTC_HDR_8x8,
/// <summary>
/// ASTC (10x10 pixel block in 128 bits) compressed RGB(A) HDR texture format.
/// </summary>
ASTC_HDR_10x10,
/// <summary>
/// ASTC (12x12 pixel block in 128 bits) compressed RGB(A) HDR texture format.
/// </summary>
ASTC_HDR_12x12,
/// <summary>
/// Two channel (RG) texture format, 16-bits unsigned integer per channel.
/// </summary>
RG32,
/// <summary>
/// Three channel (RGB) texture format, 16-bits unsigned integer per channel.
/// </summary>
RGB48,
/// <summary>
/// Four channel (RGBA) texture format, 16-bits unsigned integer per channel.
/// </summary>
RGBA64,
}
}

View File

@@ -34,7 +34,7 @@ namespace AssetStudio
var m_ProxyHeight = reader.ReadUInt32();
Width = reader.ReadUInt32();
Height = reader.ReadUInt32();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
if (version >= (2017, 2)) //2017.2 and up
{
var m_PixelAspecRatioNum = reader.ReadUInt32();
var m_PixelAspecRatioDen = reader.ReadUInt32();
@@ -46,7 +46,7 @@ namespace AssetStudio
reader.AlignStream();
var m_AudioSampleRate = reader.ReadUInt32Array();
var m_AudioLanguage = reader.ReadStringArray();
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
var m_VideoShadersSize = reader.ReadInt32();
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
@@ -57,7 +57,7 @@ namespace AssetStudio
}
m_ExternalResources = new StreamedResource(reader);
m_HasSplitAlpha = reader.ReadBoolean();
if (version[0] >= 2020) //2020.1 and up
if (version >= 2020) //2020.1 and up
{
var m_sRGB = reader.ReadBoolean();
}

View File

@@ -1,10 +1,10 @@
using System;
namespace AssetStudioCLI
namespace AssetStudio
{
// Represents set with 16 base colors using ANSI escape codes, which should be supported in most terminals
// (well, except for windows editions before windows 10)
public static class CLIAnsiColors
public static class ColorConsole
{
public static readonly string
Black = "\u001b[30m",
@@ -27,7 +27,7 @@ namespace AssetStudioCLI
public static string Color(this string str, string ansiColor)
{
if (!CLIWinAnsiFix.isAnsiSupported)
if (!ColorConsoleHelper.isAnsiCodesSupported)
{
return str;
}
@@ -35,10 +35,10 @@ namespace AssetStudioCLI
return $"{ansiColor}{str}{Reset}";
}
public static void ANSICodesTest()
public static void AnsiCodesTest()
{
Console.WriteLine("ANSI escape codes test");
Console.WriteLine($"Supported: {CLIWinAnsiFix.isAnsiSupported}");
Console.WriteLine($"Supported: {ColorConsoleHelper.isAnsiCodesSupported}");
Console.WriteLine("\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m");
Console.WriteLine("\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m");
Console.WriteLine("\u001b[30;1m A \u001b[31;1m B \u001b[32;1m C \u001b[33;1m D \u001b[0m");

View File

@@ -2,11 +2,11 @@
using System;
using System.Runtime.InteropServices;
namespace AssetStudioCLI
namespace AssetStudio
{
static class CLIWinAnsiFix
internal static class ColorConsoleHelper
{
public static readonly bool isAnsiSupported;
public static readonly bool isAnsiCodesSupported;
private const int STD_OUTPUT_HANDLE = -11;
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
@@ -19,21 +19,21 @@ namespace AssetStudioCLI
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int nStdHandle);
static CLIWinAnsiFix()
static ColorConsoleHelper()
{
bool isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
if (isWin)
{
isAnsiSupported = TryEnableVTMode();
if (!isAnsiSupported)
isAnsiCodesSupported = TryEnableVTMode();
if (!isAnsiCodesSupported)
{
//Check for bash terminal emulator. E.g., Git Bash, Cmder
isAnsiSupported = Environment.GetEnvironmentVariable("TERM") != null;
isAnsiCodesSupported = Environment.GetEnvironmentVariable("TERM") != null;
}
}
else
{
isAnsiSupported = true;
isAnsiCodesSupported = true;
}
}
@@ -51,12 +51,7 @@ namespace AssetStudioCLI
outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(iStdOut, outConsoleMode))
{
return false;
}
return true;
return SetConsoleMode(iStdOut, outConsoleMode);
}
}
}

149
AssetStudio/CubismModel.cs Normal file
View File

@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using static AssetStudio.EndianSpanReader;
namespace AssetStudio
{
public enum CubismSDKVersion : byte
{
V30 = 1,
V33,
V40,
V42,
V50
}
public sealed class CubismModel : IDisposable
{
public CubismSDKVersion Version { get; }
public string VersionDescription { get; }
public float CanvasWidth { get; }
public float CanvasHeight { get; }
public float CentralPosX { get; }
public float CentralPosY { get; }
public float PixelPerUnit { get; }
public uint PartCount { get; }
public uint ParamCount { get; }
public HashSet<string> PartNames { get; }
public HashSet<string> ParamNames { get; }
private byte[] modelData;
private int modelDataSize;
private bool isBigEndian;
public CubismModel(MonoBehaviour moc)
{
var reader = moc.reader;
reader.Reset();
reader.Position += 28; //PPtr<GameObject> m_GameObject, m_Enabled, PPtr<MonoScript>
reader.ReadAlignedString(); //m_Name
modelDataSize = (int)reader.ReadUInt32();
modelData = BigArrayPool<byte>.Shared.Rent(modelDataSize);
_ = reader.Read(modelData, 0, modelDataSize);
var sdkVer = modelData[4];
if (Enum.IsDefined(typeof(CubismSDKVersion), sdkVer))
{
Version = (CubismSDKVersion)sdkVer;
VersionDescription = ParseVersion();
}
else
{
var msg = $"Unknown SDK version ({sdkVer})";
VersionDescription = msg;
Version = 0;
Logger.Warning($"Live2D model \"{moc.m_Name}\": " + msg);
return;
}
isBigEndian = BitConverter.ToBoolean(modelData, 5);
//offsets
var countInfoTableOffset = (int)SpanToUint32(modelData, 64, isBigEndian);
var canvasInfoOffset = (int)SpanToUint32(modelData, 68, isBigEndian);
var partIdsOffset = SpanToUint32(modelData, 76, isBigEndian);
var parameterIdsOffset = SpanToUint32(modelData, 264, isBigEndian);
//canvas
PixelPerUnit = ToSingle(modelData, canvasInfoOffset, isBigEndian);
CentralPosX = ToSingle(modelData, canvasInfoOffset + 4, isBigEndian);
CentralPosY = ToSingle(modelData, canvasInfoOffset + 8, isBigEndian);
CanvasWidth = ToSingle(modelData, canvasInfoOffset + 12, isBigEndian);
CanvasHeight = ToSingle(modelData, canvasInfoOffset + 16, isBigEndian);
//model
PartCount = SpanToUint32(modelData, countInfoTableOffset, isBigEndian);
ParamCount = SpanToUint32(modelData, countInfoTableOffset + 20, isBigEndian);
PartNames = ReadMocStringHashSet(modelData, (int)partIdsOffset, (int)PartCount);
ParamNames = ReadMocStringHashSet(modelData, (int)parameterIdsOffset, (int)ParamCount);
}
public void SaveMoc3(string savePath)
{
if (!savePath.EndsWith(".moc3"))
savePath += ".moc3";
using (var file = File.OpenWrite(savePath))
{
file.Write(modelData, 0, modelDataSize);
}
}
private string ParseVersion()
{
switch (Version)
{
case CubismSDKVersion.V30:
return "SDK3.0/Cubism3.0(3.2)";
case CubismSDKVersion.V33:
return "SDK3.3/Cubism3.3";
case CubismSDKVersion.V40:
return "SDK4.0/Cubism4.0";
case CubismSDKVersion.V42:
return "SDK4.2/Cubism4.2";
case CubismSDKVersion.V50:
return "SDK5.0/Cubism5.0";
default:
return "";
}
}
private static float ToSingle(ReadOnlySpan<byte> data, int index, bool isBigEndian) //net framework ver
{
var bytes = data.Slice(index, index + 4).ToArray();
if ((isBigEndian && BitConverter.IsLittleEndian) || (!isBigEndian && !BitConverter.IsLittleEndian))
(bytes[0], bytes[1], bytes[2], bytes[3]) = (bytes[3], bytes[2], bytes[1], bytes[0]);
return BitConverter.ToSingle(bytes, 0);
}
private static HashSet<string> ReadMocStringHashSet(ReadOnlySpan<byte> data, int index, int count)
{
const int strLen = 64;
var strHashSet = new HashSet<string>();
for (var i = 0; i < count; i++)
{
if (index + i * strLen <= data.Length)
{
var buff = data.Slice(index + i * strLen, strLen);
strHashSet.Add(Encoding.UTF8.GetString(buff.ToArray()).TrimEnd('\0'));
}
}
return strHashSet;
}
private void Dispose(bool disposing)
{
if (disposing)
{
BigArrayPool<byte>.Shared.Return(modelData, clearArray: true);
}
}
public void Dispose()
{
Dispose(true);
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Buffers.Binary;
namespace AssetStudio
{
public static class EndianSpanReader
{
public static uint SpanToUint32(Span<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadUInt32BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(start));
}
public static uint SpanToUint16(Span<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadUInt16BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(start));
}
public static long SpanToInt64(Span<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadInt64BigEndian(data.Slice(start))
: BinaryPrimitives.ReadInt64LittleEndian(data.Slice(start));
}
}
}

View File

@@ -35,10 +35,13 @@ namespace AssetStudio
return "";
}
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767)
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767, Encoding encoding = null)
{
var bytes = new List<byte>();
int count = 0;
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
return reader.ReadUnicodeStringToNull(maxLength * 2);
Span<byte> bytes = stackalloc byte[maxLength];
var count = 0;
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
{
var b = reader.ReadByte();
@@ -46,10 +49,28 @@ namespace AssetStudio
{
break;
}
bytes.Add(b);
bytes[count] = b;
count++;
}
return Encoding.UTF8.GetString(bytes.ToArray());
bytes = bytes.Slice(0, count);
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
}
private static string ReadUnicodeStringToNull(this BinaryReader reader, int maxLength)
{
var bytes = new List<byte>();
var count = 0;
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
{
var b = reader.ReadBytes(2);
if (b.Length < 2 || (b[0] == 0 && b[1] == 0))
{
break;
}
bytes.AddRange(b);
count += 2;
}
return Encoding.Unicode.GetString(bytes.ToArray());
}
public static Quaternion ReadQuaternion(this BinaryReader reader)

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Linq;
using System;
using System.IO;
using static AssetStudio.EndianSpanReader;
namespace AssetStudio
{
@@ -37,66 +38,69 @@ namespace AssetStudio
case "UnityWebData1.0":
return FileType.WebFile;
default:
{
var buff = ReadBytes(40).AsSpan();
var magic = Span<byte>.Empty;
Position = 0;
magic = buff.Length > 2 ? buff.Slice(0, 2) : magic;
if (magic.SequenceEqual(gzipMagic))
{
byte[] magic = ReadBytes(2);
Position = 0;
if (gzipMagic.SequenceEqual(magic))
{
return FileType.GZipFile;
}
Position = 0x20;
magic = ReadBytes(6);
Position = 0;
if (brotliMagic.SequenceEqual(magic))
{
return FileType.BrotliFile;
}
if (IsSerializedFile())
{
return FileType.AssetsFile;
}
magic = ReadBytes(4);
Position = 0;
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
return FileType.ZipFile;
return FileType.ResourceFile;
return FileType.GZipFile;
}
magic = buff.Length > 38 ? buff.Slice(32, 6) : magic;
if (magic.SequenceEqual(brotliMagic))
{
return FileType.BrotliFile;
}
if (IsSerializedFile(buff))
{
return FileType.AssetsFile;
}
magic = buff.Length > 4 ? buff.Slice(0, 4): magic;
if (magic.SequenceEqual(zipMagic) || magic.SequenceEqual(zipSpannedMagic))
{
return FileType.ZipFile;
}
return FileType.ResourceFile;
}
}
}
private bool IsSerializedFile()
private bool IsSerializedFile(Span<byte> buff)
{
var fileSize = BaseStream.Length;
if (fileSize < 20)
{
return false;
}
var m_MetadataSize = ReadUInt32();
long m_FileSize = ReadUInt32();
var m_Version = ReadUInt32();
long m_DataOffset = ReadUInt32();
var m_Endianess = ReadByte();
var m_Reserved = ReadBytes(3);
var isBigEndian = Endian == EndianType.BigEndian;
//var m_MetadataSize = SpanToUint32(buff, 0, isBigEndian);
long m_FileSize = SpanToUint32(buff, 4, isBigEndian);
var m_Version = SpanToUint32(buff, 8, isBigEndian);
long m_DataOffset = SpanToUint32(buff, 12, isBigEndian);
//var m_Endianess = buff[16];
//var m_Reserved = buff.Slice(17, 3);
if (m_Version >= 22)
{
if (fileSize < 48)
{
Position = 0;
return false;
}
m_MetadataSize = ReadUInt32();
m_FileSize = ReadInt64();
m_DataOffset = ReadInt64();
//m_MetadataSize = SpanToUint32(buff, 20, isBigEndian);
m_FileSize = SpanToInt64(buff, 24, isBigEndian);
m_DataOffset = SpanToInt64(buff, 32, isBigEndian);
}
Position = 0;
if (m_FileSize != fileSize)
{
return false;
}
if (m_DataOffset > fileSize)
if (m_FileSize != fileSize || m_DataOffset > fileSize)
{
return false;
}
return true;
}
}

View File

@@ -53,15 +53,24 @@ namespace AssetStudio
public static FileReader DecompressGZip(FileReader reader)
{
using (reader)
try
{
var stream = new MemoryStream();
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
using (reader)
{
gs.CopyTo(stream);
var stream = new MemoryStream();
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
{
gs.CopyTo(stream);
}
stream.Position = 0;
return new FileReader(reader.FullPath, stream);
}
stream.Position = 0;
return new FileReader(reader.FullPath, stream);
}
catch (System.Exception e)
{
Logger.Warning($"Error while decompressing gzip file {reader.FullPath}\r\n{e}");
reader.Dispose();
return null;
}
}

View File

@@ -17,7 +17,7 @@ namespace AssetStudio
public BuildTarget platform;
public SerializedFileFormatVersion m_Version;
public int[] version => assetsFile.version;
public UnityVersion version => assetsFile.version;
public BuildType buildType => assetsFile.buildType;
public ObjectReader(EndianBinaryReader reader, SerializedFile assetsFile, ObjectInfo objectInfo) : base(reader.BaseStream, reader.Endian)

View File

@@ -7,25 +7,31 @@ namespace AssetStudio
private bool needSearch;
private string path;
private SerializedFile assetsFile;
private long offset;
private long size;
private BinaryReader reader;
public int Size { get => (int)size; }
public int Size
{
get => (int)size;
set => size = value;
}
public long Offset { get; set; }
public ResourceReader() { }
public ResourceReader(string path, SerializedFile assetsFile, long offset, long size)
{
needSearch = true;
this.path = path;
this.assetsFile = assetsFile;
this.offset = offset;
this.Offset = offset;
this.size = size;
}
public ResourceReader(BinaryReader reader, long offset, long size)
{
this.reader = reader;
this.offset = offset;
this.Offset = offset;
this.size = size;
}
@@ -52,8 +58,12 @@ namespace AssetStudio
if (File.Exists(resourceFilePath))
{
needSearch = false;
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName, out reader))
{
return reader;
}
reader = new BinaryReader(File.OpenRead(resourceFilePath));
assetsFile.assetsManager.resourceFileReaders.Add(resourceFileName, reader);
assetsFile.assetsManager.resourceFileReaders.TryAdd(resourceFileName, reader);
return reader;
}
throw new FileNotFoundException($"Can't find the resource file {resourceFileName}");
@@ -67,21 +77,27 @@ namespace AssetStudio
public byte[] GetData()
{
var binaryReader = GetReader();
binaryReader.BaseStream.Position = offset;
return binaryReader.ReadBytes((int)size);
lock (binaryReader)
{
binaryReader.BaseStream.Position = Offset;
return binaryReader.ReadBytes((int) size);
}
}
public void GetData(byte[] buff)
{
var binaryReader = GetReader();
binaryReader.BaseStream.Position = offset;
binaryReader.Read(buff, 0, (int)size);
lock (binaryReader)
{
binaryReader.BaseStream.Position = Offset;
binaryReader.Read(buff, 0, (int) size);
}
}
public void WriteData(string path)
{
var binaryReader = GetReader();
binaryReader.BaseStream.Position = offset;
binaryReader.BaseStream.Position = Offset;
using (var writer = File.OpenWrite(path))
{
binaryReader.BaseStream.CopyTo(writer, size);

View File

@@ -13,7 +13,7 @@ namespace AssetStudio
public string fullName;
public string originalPath;
public string fileName;
public int[] version = { 0, 0, 0, 0 };
public UnityVersion version = new UnityVersion();
public BuildType buildType;
public List<Object> Objects;
public Dictionary<long, Object> ObjectsDic;
@@ -73,7 +73,7 @@ namespace AssetStudio
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7)
{
unityVersion = reader.ReadStringToNull();
SetVersion(unityVersion);
SetVersion(new UnityVersion(unityVersion));
}
if (header.m_Version >= SerializedFileFormatVersion.Unknown_8)
{
@@ -217,19 +217,13 @@ namespace AssetStudio
//reader.AlignStream(16);
}
public void SetVersion(string stringVersion)
public void SetVersion(UnityVersion unityVer)
{
if (stringVersion != strippedVersion)
if (unityVer != null && !unityVer.IsStripped)
{
unityVersion = stringVersion;
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
if (buildSplit.Length == 0)
throw new NotSupportedException("Specified Unity version is not in a correct format.\n" +
"Specify full Unity version, including letters at the end.\n" +
"Example: 2017.4.39f1");
buildType = new BuildType(buildSplit[0]);
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
version = versionSplit.Select(int.Parse).ToArray();
unityVersion = unityVer.FullVersion;
buildType = new BuildType(unityVer.BuildType);
version = unityVer;
}
}
@@ -377,9 +371,5 @@ namespace AssetStudio
Objects.Add(obj);
ObjectsDic.Add(obj.m_PathID, obj);
}
public bool IsVersionStripped => unityVersion == strippedVersion;
private const string strippedVersion = "0.0.0";
}
}

View File

@@ -20,7 +20,7 @@ namespace AssetStudio
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
Logger.Info($"Failed to read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
return sb.ToString();
}
@@ -116,7 +116,7 @@ namespace AssetStudio
{
append = false;
var size = reader.ReadInt32();
reader.ReadBytes(size);
reader.BaseStream.Position += size;
i += 2;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), "int", "size", size);
@@ -171,13 +171,13 @@ namespace AssetStudio
for (int i = 1; i < m_Nodes.Count; i++)
{
var m_Node = m_Nodes[i];
var varNameStr = m_Node.m_Name;
var varNameStr = m_Node.m_Name.Replace("image data", "image_data");
obj[varNameStr] = ReadValue(m_Nodes, reader, ref i);
}
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
Logger.Info($"Failed to read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
return obj;
}
@@ -262,7 +262,13 @@ namespace AssetStudio
case "TypelessData":
{
var size = reader.ReadInt32();
value = reader.ReadBytes(size);
var dic = new OrderedDictionary
{
{ "Offset", reader.BaseStream.Position },
{ "Size", size }
};
value = dic;
reader.BaseStream.Position += size;
i += 2;
break;
}

449
AssetStudio/UnityVersion.cs Normal file
View File

@@ -0,0 +1,449 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace AssetStudio
{
public class UnityVersion : IComparable
{
public int Major { get; }
public int Minor { get; }
public int Patch { get; }
public int Build { get; }
public string BuildType { get; }
public string FullVersion { get; }
public bool IsStripped => this == (0, 0, 0);
public UnityVersion(string version)
{
if (string.IsNullOrEmpty(version))
throw new ArgumentException("Unity version cannot be empty.");
try
{
int[] ver = Regex.Matches(version, @"\d+").Cast<Match>().Select(x => int.Parse(x.Value)).ToArray();
(Major, Minor, Patch) = (ver[0], ver[1], ver[2]);
if (ver.Length == 4)
Build = ver[3];
FullVersion = version;
}
catch (Exception)
{
throw new NotSupportedException($"Failed to parse Unity version: \"{version}\".");
}
string[] build = Regex.Matches(version, @"\D+").Cast<Match>().Select(x => x.Value).ToArray();
if (build.Length > 2)
{
BuildType = build[2];
}
}
public UnityVersion(int major = 0, int minor = 0, int patch = 0)
{
(Major, Minor, Patch) = (major, minor, patch);
FullVersion = $"{Major}.{Minor}.{Patch}";
if (!IsStripped)
{
Build = 1;
BuildType = "f";
FullVersion += $"{BuildType}{Build}";
}
}
#region UnityVer, UnityVer
public static bool operator ==(UnityVersion left, UnityVersion right)
{
return Equals(left, right);
}
public static bool operator !=(UnityVersion left, UnityVersion right)
{
return !Equals(left, right);
}
public static bool operator >(UnityVersion left, UnityVersion right)
{
return left?.CompareTo(right) > 0;
}
public static bool operator <(UnityVersion left, UnityVersion right)
{
return left?.CompareTo(right) < 0;
}
public static bool operator >=(UnityVersion left, UnityVersion right)
{
return left == right || left > right;
}
public static bool operator <=(UnityVersion left, UnityVersion right)
{
return left == right || left < right;
}
#endregion
#region UnityVer, int
public static bool operator ==(UnityVersion left, int right)
{
return left?.Major == right;
}
public static bool operator !=(UnityVersion left, int right)
{
return left?.Major != right;
}
public static bool operator >(UnityVersion left, int right)
{
return left?.Major > right;
}
public static bool operator <(UnityVersion left, int right)
{
return left?.Major < right;
}
public static bool operator >=(UnityVersion left, int right)
{
return left?.Major >= right;
}
public static bool operator <=(UnityVersion left, int right)
{
return left?.Major <= right;
}
#endregion
#region UnityVer, (int, int)
public static bool operator ==(UnityVersion left, (int, int) right)
{
return (left?.Major, left?.Minor) == (right.Item1, right.Item2);
}
public static bool operator !=(UnityVersion left, (int, int) right)
{
return (left?.Major, left?.Minor) != (right.Item1, right.Item2);
}
public static bool operator >(UnityVersion left, (int, int) right)
{
return left?.CompareTo(right) > 0;
}
public static bool operator <(UnityVersion left, (int, int) right)
{
return left?.CompareTo(right) < 0;
}
public static bool operator >=(UnityVersion left, (int, int) right)
{
return left == right || left > right;
}
public static bool operator <=(UnityVersion left, (int, int) right)
{
return left == right || left < right;
}
#endregion
#region UnityVer, (int, int, int)
public static bool operator ==(UnityVersion left, (int, int, int) right)
{
return (left?.Major, left?.Minor, left?.Patch) == (right.Item1, right.Item2, right.Item3);
}
public static bool operator !=(UnityVersion left, (int, int, int) right)
{
return (left?.Major, left?.Minor, left?.Patch) != (right.Item1, right.Item2, right.Item3);
}
public static bool operator >(UnityVersion left, (int, int, int) right)
{
return left?.CompareTo(right) > 0;
}
public static bool operator <(UnityVersion left, (int, int, int) right)
{
return left?.CompareTo(right) < 0;
}
public static bool operator >=(UnityVersion left, (int, int, int) right)
{
return left == right || left > right;
}
public static bool operator <=(UnityVersion left, (int, int, int) right)
{
return left == right || left < right;
}
#endregion
#region int, UnityVer
public static bool operator ==(int left, UnityVersion right)
{
return left == right?.Major;
}
public static bool operator !=(int left, UnityVersion right)
{
return left != right?.Major;
}
public static bool operator >(int left, UnityVersion right)
{
return left > right?.Major;
}
public static bool operator <(int left, UnityVersion right)
{
return left < right?.Major;
}
public static bool operator >=(int left, UnityVersion right)
{
return left >= right?.Major;
}
public static bool operator <=(int left, UnityVersion right)
{
return left <= right?.Major;
}
#endregion
#region (int, int), UnityVer
public static bool operator ==((int, int) left, UnityVersion right)
{
return (left.Item1, left.Item2) == (right?.Major, right?.Minor);
}
public static bool operator !=((int, int) left, UnityVersion right)
{
return (left.Item1, left.Item2) != (right?.Major, right?.Minor);
}
public static bool operator >((int, int) left, UnityVersion right)
{
return right?.CompareTo(left) < 0;
}
public static bool operator <((int, int) left, UnityVersion right)
{
return right?.CompareTo(left) > 0;
}
public static bool operator >=((int, int) left, UnityVersion right)
{
return left == right || left > right;
}
public static bool operator <=((int, int) left, UnityVersion right)
{
return left == right || left < right;
}
#endregion
#region (int, int, int), UnityVer
public static bool operator ==((int, int, int) left, UnityVersion right)
{
return (left.Item1, left.Item2, left.Item3) == (right?.Major, right?.Minor, right?.Patch);
}
public static bool operator !=((int, int, int) left, UnityVersion right)
{
return (left.Item1, left.Item2, left.Item3) != (right?.Major, right?.Minor, right?.Patch);
}
public static bool operator >((int, int, int) left, UnityVersion right)
{
return right?.CompareTo(left) < 0;
}
public static bool operator <((int, int, int) left, UnityVersion right)
{
return right?.CompareTo(left) > 0;
}
public static bool operator >=((int, int, int) left, UnityVersion right)
{
return left == right || left > right;
}
public static bool operator <=((int, int, int) left, UnityVersion right)
{
return left == right || left < right;
}
#endregion
private int CompareTo((int, int) other)
{
var result = Major.CompareTo(other.Item1);
if (result != 0)
{
return result;
}
result = Minor.CompareTo(other.Item2);
if (result != 0)
{
return result;
}
return 0;
}
private int CompareTo((int, int, int) other)
{
var result = CompareTo((other.Item1, other.Item2));
if (result != 0)
{
return result;
}
result = Patch.CompareTo(other.Item3);
if (result != 0)
{
return result;
}
return 0;
}
private int CompareTo(UnityVersion other)
{
return CompareTo((other.Major, other.Minor, other.Patch));
}
private bool Equals(UnityVersion other)
{
return (Major, Minor, Patch) == (other.Major, other.Minor, other.Patch);
}
public override bool Equals(object other)
{
return other is UnityVersion otherUnityVer && Equals(otherUnityVer);
}
public override int GetHashCode()
{
var result = Major * 31;
result = result * 31 + Minor;
result = result * 31 + Patch;
result = result * 31 + Build;
return result.GetHashCode();
}
public int CompareTo(object obj)
{
return CompareTo((UnityVersion)obj);
}
public sealed override string ToString()
{
return FullVersion;
}
public Tuple<int, int, int> ToTuple()
{
return new Tuple<int, int, int>(Major, Minor, Patch);
}
public int[] ToArray()
{
return new[] {Major, Minor, Patch};
}
}
public static class UnityVersionExtensions
{
/// <summary>
/// Checks if the Unity version is within the range limits specified by the "lowerLimit" and "upperLimit" attributes.
/// </summary>
/// <param name="ver"></param>
/// <param name="lowerLimit">Minimal version. Included in the range.</param>
/// <param name="upperLimit">Maximal version. Not included in the range.</param>
/// <returns><see langword="true"/> if the Unity version is within the specified range; otherwise <see langword="false"/>.</returns>
/// <remarks>[lowerLimit, upperLimit)</remarks>
public static bool IsInRange(this UnityVersion ver, UnityVersion lowerLimit, UnityVersion upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, int lowerLimit, UnityVersion upperLimit)
{
return ver.Major >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int) lowerLimit, UnityVersion upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int, int) lowerLimit, UnityVersion upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, UnityVersion lowerLimit, int upperLimit)
{
return ver >= lowerLimit && ver.Major < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, UnityVersion lowerLimit, (int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, UnityVersion lowerLimit, (int, int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, int lowerLimit, int upperLimit)
{
return ver.Major >= lowerLimit && ver.Major < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, int lowerLimit, (int, int) upperLimit)
{
return ver.Major >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, int lowerLimit, (int, int, int) upperLimit)
{
return ver.Major >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int) lowerLimit, int upperLimit)
{
return ver >= lowerLimit && ver.Major < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int, int) lowerLimit, int upperLimit)
{
return ver >= lowerLimit && ver.Major < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int) lowerLimit, (int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int) lowerLimit, (int, int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int, int) lowerLimit, (int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
public static bool IsInRange(this UnityVersion ver, (int, int, int) lowerLimit, (int, int, int) upperLimit)
{
return ver >= lowerLimit && ver < upperLimit;
}
}
}

View File

@@ -2,11 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModCLI</AssemblyName>
<Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare; Copyright © aelurum 2023-2024</Copyright>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>embedded</DebugType>
</PropertyGroup>
@@ -24,6 +24,8 @@
<Target Name="CopyExtraFilesPortable" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' ">
<Message Text="Copying windows extra files for $(TargetFramework)... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
@@ -32,6 +34,9 @@
<Target Name="CopyExtraFilesPortableNet" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
<Message Text="Copying other platforms extra files for $(TargetFramework)... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libAssetStudioFBXNative.so" DestinationFolder="$(TargetDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)runtimes\osx-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-arm64\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)runtimes\osx-arm64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x86\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libfmod.dylib" DestinationFolder="$(TargetDir)runtimes\osx-x64\native" ContinueOnError="false" />
@@ -42,6 +47,8 @@
The dll is cross-platform while the executable isn't -->
<Target Name="PublishExtraFilesPortable" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' ">
<Message Text="Publishing windows extra files for Portable build ($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
@@ -50,6 +57,9 @@
<Target Name="PublishExtraFilesPortableNet" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
<Message Text="Publishing other platforms extra files for Portable build ($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x64\native\libAssetStudioFBXNative.so" DestinationFolder="$(PublishDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-x64\native\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)runtimes\osx-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-arm64\native\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)runtimes\osx-arm64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x86\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x86\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\linux-x64\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x64\native" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)runtimes\osx-x64\native\libfmod.dylib" DestinationFolder="$(PublishDir)runtimes\osx-x64\native" ContinueOnError="false" />
@@ -58,39 +68,46 @@
<Target Name="CopyExtraFilesWin86" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x86' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesWin64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x64' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\win-x64\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesWin" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('win-x')) ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\fmod.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesLinux64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libAssetStudioFBXNative.so" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesLinux64" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\libAssetStudioFBXNative.so" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\libfmod.so" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>
<Target Name="CopyExtraFilesMac" AfterTargets="AfterBuild" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(ProjectDir)Libraries\$(RuntimeIdentifier)\libAssetStudioFBXNative.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
<Copy SourceFiles="$(ProjectDir)Libraries\$(RuntimeIdentifier)\libfmod.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
</Target>
<Target Name="PublishExtraFilesMac" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
<Copy SourceFiles="$(TargetDir)\libAssetStudioFBXNative.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
<Copy SourceFiles="$(TargetDir)\libfmod.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
</Target>

View File

@@ -1,9 +1,10 @@
using AssetStudio;
using AssetStudioCLI.Options;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace AssetStudioCLI
{
@@ -16,19 +17,28 @@ namespace AssetStudioCLI
internal class CLILogger : ILogger
{
private readonly LogOutputMode logOutput;
private readonly LoggerEvent logMinLevel;
public string LogName;
public string LogPath;
private static BlockingCollection<string> logMessageCollection = new BlockingCollection<string>();
private readonly LogOutputMode logOutput;
private readonly LoggerEvent logMinLevel;
public CLILogger()
{
logOutput = CLIOptions.o_logOutput.Value;
logMinLevel = CLIOptions.o_logLevel.Value;
var appAssembly = typeof(Program).Assembly.GetName();
var arch = Environment.Is64BitProcess ? "x64" : "x32";
LogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName);
var arch = Environment.Is64BitProcess ? "x64" : "x32";
Console.OutputEncoding = System.Text.Encoding.UTF8;
if (logOutput != LogOutputMode.Console)
{
ConcurrentFileWriter();
}
LogToFile(LoggerEvent.Verbose, $"---{appAssembly.Name} v{appAssembly.Version} [{arch}] | Logger launched---\n" +
$"CMD Args: {string.Join(" ", CLIOptions.cliArgs)}");
@@ -36,15 +46,15 @@ namespace AssetStudioCLI
private static string ColorLogLevel(LoggerEvent logLevel)
{
string formattedLevel = $"[{logLevel}]";
var formattedLevel = $"[{logLevel}]";
switch (logLevel)
{
case LoggerEvent.Info:
return $"{formattedLevel.Color(CLIAnsiColors.BrightCyan)}";
return $"{formattedLevel.Color(ColorConsole.BrightCyan)}";
case LoggerEvent.Warning:
return $"{formattedLevel.Color(CLIAnsiColors.BrightYellow)}";
return $"{formattedLevel.Color(ColorConsole.BrightYellow)}";
case LoggerEvent.Error:
return $"{formattedLevel.Color(CLIAnsiColors.BrightRed)}";
return $"{formattedLevel.Color(ColorConsole.BrightRed)}";
default:
return formattedLevel;
}
@@ -54,16 +64,16 @@ namespace AssetStudioCLI
{
var curTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
message = message.TrimEnd();
var multiLine = message.Contains('\n');
var multiLine = message.Contains("\n");
string formattedMessage;
if (consoleMode)
{
string colorLogLevel = ColorLogLevel(logMsgLevel);
var colorLogLevel = ColorLogLevel(logMsgLevel);
formattedMessage = $"{colorLogLevel} {message}";
if (multiLine)
{
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ");
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ") + $"\n{colorLogLevel}";
}
}
else
@@ -73,7 +83,7 @@ namespace AssetStudioCLI
formattedMessage = $"{curTime} | {logLevel} | {message}";
if (multiLine)
{
formattedMessage = formattedMessage.Replace("\n", $"\n{curTime} | {logLevel} | ");
formattedMessage = formattedMessage.Replace("\n", $"\n{curTime} | {logLevel} | ") + $"\n{curTime} | {logLevel} |";
}
}
return formattedMessage;
@@ -87,15 +97,27 @@ namespace AssetStudioCLI
}
}
public async void LogToFile(LoggerEvent logMsgLevel, string message)
public void LogToFile(LoggerEvent logMsgLevel, string message)
{
if (logOutput != LogOutputMode.Console)
{
logMessageCollection.Add(FormatMessage(logMsgLevel, message));
}
}
private void ConcurrentFileWriter()
{
Task.Run(() =>
{
using (var sw = new StreamWriter(LogPath, append: true, System.Text.Encoding.UTF8))
{
await sw.WriteLineAsync(FormatMessage(logMsgLevel, message));
sw.AutoFlush = true;
foreach (var msg in logMessageCollection.GetConsumingEnumerable())
{
sw.WriteLine(msg);
}
}
}
});
}
public void Log(LoggerEvent logMsgLevel, string message, bool ignoreLevel)

View File

@@ -13,6 +13,7 @@ namespace AssetStudioCLI
public ClassIDType Type;
public string Text;
public string UniqueID;
public GameObjectNode Node;
public AssetItem(Object asset)
{

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace AssetStudioCLI
{
internal class BaseNode
{
public List<BaseNode> nodes = new List<BaseNode>();
public string FullPath = "";
public readonly string Text;
public BaseNode(string name)
{
Text = name;
}
}
}

View File

@@ -0,0 +1,14 @@
using AssetStudio;
namespace AssetStudioCLI
{
internal class GameObjectNode : BaseNode
{
public GameObject gameObject;
public GameObjectNode(GameObject gameObject) : base(gameObject.m_Name)
{
this.gameObject = gameObject;
}
}
}

View File

@@ -1,6 +1,7 @@
using AssetStudio;
using AssetStudioCLI.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -9,110 +10,6 @@ namespace AssetStudioCLI
{
internal static class Exporter
{
public static bool ExportTexture2D(AssetItem item, string exportPath)
{
var m_Texture2D = (Texture2D)item.Asset;
if (CLIOptions.convertTexture)
{
var type = CLIOptions.o_imageFormat.Value;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting \"{m_Texture2D.m_Name}\" to {type}..");
sb.AppendLine($"Width: {m_Texture2D.m_Width}");
sb.AppendLine($"Height: {m_Texture2D.m_Height}");
sb.AppendLine($"Format: {m_Texture2D.m_TextureFormat}");
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
{
case 0: sb.AppendLine("Filter Mode: Point "); break;
case 1: sb.AppendLine("Filter Mode: Bilinear "); break;
case 2: sb.AppendLine("Filter Mode: Trilinear "); break;
}
sb.AppendLine($"Anisotropic level: {m_Texture2D.m_TextureSettings.m_Aniso}");
sb.AppendLine($"Mip map bias: {m_Texture2D.m_TextureSettings.m_MipBias}");
switch (m_Texture2D.m_TextureSettings.m_WrapMode)
{
case 0: sb.AppendLine($"Wrap mode: Repeat"); break;
case 1: sb.AppendLine($"Wrap mode: Clamp"); break;
}
Logger.Debug(sb.ToString());
}
var image = m_Texture2D.ConvertToImage(flip: true);
if (image == null)
{
Logger.Error($"Export error. Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
return false;
}
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true;
}
}
else
{
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true;
}
}
public static bool ExportAudioClip(AssetItem item, string exportPath)
{
string exportFullPath;
var m_AudioClip = (AudioClip)item.Asset;
var m_AudioData = m_AudioClip.m_AudioData.GetData();
if (m_AudioData == null || m_AudioData.Length == 0)
{
Logger.Error($"Export error. \"{item.Text}\": AudioData was not found");
return false;
}
var converter = new AudioClipConverter(m_AudioClip);
if (CLIOptions.o_audioFormat.Value != AudioFormat.None && converter.IsSupport)
{
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting \"{m_AudioClip.m_Name}\" to wav..");
sb.AppendLine(m_AudioClip.version[0] < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
Logger.Debug(sb.ToString());
}
var buffer = converter.ConvertToWav(m_AudioData);
if (buffer == null)
{
Logger.Error($"Export error. \"{item.Text}\": Failed to convert to Wav");
return false;
}
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_AudioData);
}
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true;
}
public static bool ExportVideoClip(AssetItem item, string exportPath)
{
var m_VideoClip = (VideoClip)item.Asset;
@@ -232,31 +129,36 @@ namespace AssetStudioCLI
return false;
}
public static bool ExportSprite(AssetItem item, string exportPath)
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var type = CLIOptions.o_imageFormat.Value;
var alphaMask = SpriteMaskMode.On;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = ((Sprite)item.Asset).GetImage(alphaMask);
if (image != null)
{
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true;
}
}
return false;
var convert = animationList != null
? new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
: new ModelConverter(gameObject, CLIOptions.o_imageFormat.Value);
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
ExportFbx(convert, exportPath);
}
private static void ExportFbx(IImported convert, string exportPath)
{
var eulerFilter = true;
var filterPrecision = 0.25f;
var exportAllNodes = true;
var exportSkins = true;
var exportAnimations = true;
var exportBlendShape = true;
var castToBone = false;
var boneSize = CLIOptions.o_fbxBoneSize.Value;
var exportAllUvsAsDiffuseMaps = false;
var scaleFactor = CLIOptions.o_fbxScaleFactor.Value;
var fbxVersion = 3;
var fbxFormat = 0;
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision,
exportAllNodes, exportSkins, exportAnimations, exportBlendShape, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, fbxVersion, fbxFormat == 1);
}
public static bool ExportRawFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath, mode: "ExportRaw"))
return false;
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
@@ -266,7 +168,7 @@ namespace AssetStudioCLI
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump"))
return false;
var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
@@ -274,6 +176,10 @@ namespace AssetStudioCLI
var m_Type = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader);
str = m_MonoBehaviour.Dump(m_Type);
}
if (string.IsNullOrEmpty(str))
{
str = item.Asset.DumpObject();
}
if (str != null)
{
File.WriteAllText(exportFullPath, str);
@@ -283,22 +189,35 @@ namespace AssetStudioCLI
return false;
}
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
{
var fileName = FixFileName(item.Text);
var filenameFormat = CLIOptions.o_filenameFormat.Value;
switch (filenameFormat)
{
case FilenameFormat.AssetName_PathID:
fileName = $"{fileName} @{item.m_PathID}";
break;
case FilenameFormat.PathID:
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
if (filenameFormat == FilenameFormat.AssetName)
{
Directory.CreateDirectory(dir);
return true;
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Error($"Export error. File \"{fullPath.Color(CLIAnsiColors.BrightRed)}\" already exist");
Logger.Error($"{mode} error. File \"{fullPath.Color(ColorConsole.BrightRed)}\" already exist");
return false;
}
@@ -404,9 +323,10 @@ namespace AssetStudioCLI
switch (item.Type)
{
case ClassIDType.Texture2D:
return ExportTexture2D(item, exportPath);
case ClassIDType.Texture2DArray:
case ClassIDType.Sprite:
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath);
throw new System.NotImplementedException();
case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
@@ -419,8 +339,6 @@ namespace AssetStudioCLI
return ExportMonoBehaviour(item, exportPath);
case ClassIDType.Font:
return ExportFont(item, exportPath);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath);
case ClassIDType.Mesh:
return ExportMesh(item, exportPath);
default:
@@ -430,8 +348,9 @@ namespace AssetStudioCLI
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
return str.Length >= 260
? Path.GetRandomFileName()
: Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,15 +4,17 @@
{
public string Name { get; }
public string Description { get; }
public string Example { get; }
public T Value { get; set; }
public T DefaultValue { get; }
public HelpGroups HelpGroup { get; }
public bool IsFlag { get; }
public Option(T optionDefaultValue, string optionName, string optionDescription, HelpGroups optionHelpGroup, bool isFlag)
public Option(T optionDefaultValue, string optionName, string optionDescription, string optionExample, HelpGroups optionHelpGroup, bool isFlag)
{
Name = optionName;
Description = optionDescription;
Example = optionExample;
DefaultValue = optionDefaultValue;
Value = DefaultValue;
HelpGroup = optionHelpGroup;

View File

@@ -4,14 +4,14 @@ namespace AssetStudioCLI.Options
{
internal static class OptionExtensions
{
public static Action<string, string, HelpGroups, bool> OptionGrouping = (name, desc, group, isFlag) => { };
public static Action<string, string, string, HelpGroups, bool> OptionGrouping = (name, desc, example, group, isFlag) => { };
}
internal class GroupedOption<T> : Option<T>
{
public GroupedOption(T optionDefaultValue, string optionName, string optionDescription, HelpGroups optionHelpGroup, bool isFlag = false) : base(optionDefaultValue, optionName, optionDescription, optionHelpGroup, isFlag)
public GroupedOption(T optionDefaultValue, string optionName, string optionDescription, string optionExample, HelpGroups optionHelpGroup, bool isFlag = false) : base(optionDefaultValue, optionName, optionDescription, optionExample, optionHelpGroup, isFlag)
{
OptionExtensions.OptionGrouping(optionName, optionDescription, optionHelpGroup, isFlag);
OptionExtensions.OptionGrouping(optionName, optionDescription, optionExample, optionHelpGroup, isFlag);
}
}
}

View File

@@ -0,0 +1,223 @@
using AssetStudio;
using AssetStudioCLI.Options;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudioCLI
{
internal static class ParallelExporter
{
private static ConcurrentDictionary<string, bool> savePathHash = new ConcurrentDictionary<string, bool>();
public static bool ExportTexture2D(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
var m_Texture2D = (Texture2D)item.Asset;
if (CLIOptions.convertTexture)
{
var type = CLIOptions.o_imageFormat.Value;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_Texture2D.m_Name}\" to {type}..");
sb.AppendLine($"Width: {m_Texture2D.m_Width}");
sb.AppendLine($"Height: {m_Texture2D.m_Height}");
sb.AppendLine($"Format: {m_Texture2D.m_TextureFormat}");
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
{
case 0: sb.AppendLine("Filter Mode: Point "); break;
case 1: sb.AppendLine("Filter Mode: Bilinear "); break;
case 2: sb.AppendLine("Filter Mode: Trilinear "); break;
}
sb.AppendLine($"Anisotropic level: {m_Texture2D.m_TextureSettings.m_Aniso}");
sb.AppendLine($"Mip map bias: {m_Texture2D.m_TextureSettings.m_MipBias}");
switch (m_Texture2D.m_TextureSettings.m_WrapMode)
{
case 0: sb.AppendLine($"Wrap mode: Repeat"); break;
case 1: sb.AppendLine($"Wrap mode: Clamp"); break;
}
debugLog += sb.ToString();
}
var image = m_Texture2D.ConvertToImage(flip: true);
if (image == null)
{
Logger.Error($"{debugLog}Export error. Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
return false;
}
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
else
{
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
public static bool ExportSprite(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
var type = CLIOptions.o_imageFormat.Value;
var alphaMask = SpriteMaskMode.On;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = ((Sprite)item.Asset).GetImage(alphaMask);
if (image != null)
{
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
return false;
}
public static bool ExportAudioClip(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
string exportFullPath;
var m_AudioClip = (AudioClip)item.Asset;
var m_AudioData = BigArrayPool<byte>.Shared.Rent(m_AudioClip.m_AudioData.Size);
try
{
m_AudioClip.m_AudioData.GetData(m_AudioData);
if (m_AudioData == null || m_AudioData.Length == 0)
{
Logger.Error($"Export error. \"{item.Text}\": AudioData was not found");
return false;
}
var converter = new AudioClipConverter(m_AudioClip);
if (CLIOptions.o_audioFormat.Value != AudioFormat.None && converter.IsSupport)
{
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav..");
sb.AppendLine(m_AudioClip.version < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
debugLog += sb.ToString();
}
var buffer = converter.ConvertToWav(m_AudioData, out var debugLogConverter);
debugLog += debugLogConverter;
if (buffer == null)
{
Logger.Error($"{debugLog}Export error. \"{item.Text}\": Failed to convert fmod audio to Wav");
return false;
}
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out exportFullPath))
return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder();
sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\"..");
sb.AppendLine(m_AudioClip.version < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
debugLog += sb.ToString();
}
File.WriteAllBytes(exportFullPath, m_AudioData);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
finally
{
BigArrayPool<byte>.Shared.Return(m_AudioData, clearArray: true);
}
}
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
{
var fileName = FixFileName(item.Text);
var filenameFormat = CLIOptions.o_filenameFormat.Value;
switch (filenameFormat)
{
case FilenameFormat.AssetName_PathID:
fileName = $"{fileName} @{item.m_PathID}";
break;
case FilenameFormat.PathID:
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (savePathHash.TryAdd(fullPath.ToLower(), true) && !File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
if (filenameFormat == FilenameFormat.AssetName)
{
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Error($"Export error. File \"{fullPath.Color(ColorConsole.BrightRed)}\" already exist");
return false;
}
public static bool ParallelExportConvertFile(AssetItem item, string exportPath, out string debugLog)
{
switch (item.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Texture2DArrayImage:
return ExportTexture2D(item, exportPath, out debugLog);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath, out debugLog);
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath, out debugLog);
default:
throw new NotImplementedException();
}
}
private static string FixFileName(string str)
{
return str.Length >= 260
? Path.GetRandomFileName()
: Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
public static void ClearHash()
{
savePathHash.Clear();
}
}
}

View File

@@ -35,9 +35,9 @@ namespace AssetStudioCLI
if (Studio.LoadAssets())
{
Studio.ParseAssets();
if (CLIOptions.filterBy != FilterBy.None && CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
if (CLIOptions.filterBy != FilterBy.None)
{
Studio.FilterAssets();
Studio.Filter();
}
if (CLIOptions.o_exportAssetList.Value != ExportListType.None)
{
@@ -48,9 +48,12 @@ namespace AssetStudioCLI
case WorkMode.Info:
Studio.ShowExportableAssetsInfo();
break;
case WorkMode.ExportLive2D:
case WorkMode.Live2D:
Studio.ExportLive2D();
break;
case WorkMode.SplitObjects:
Studio.ExportSplitObjects();
break;
default:
Studio.ExportAssets();
break;

View File

@@ -1,49 +1,62 @@
## AssetStudioModCLI
CLI version of AssetStudioMod.
- Supported asset types: `Texture2D`, `Sprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip`, `Mesh`.
- Supported asset types for export: `Texture2D`, `Sprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip`, `Mesh`.
- *There are no plans to add support for `AnimationClip`, `Animator` for now.*
### Usage
```
AssetStudioModCLI <input path to asset file/folder> [-m, --mode <value>]
[-t, --asset-type <value(s)>] [-g, --group-option <value>]
[-o, --output <path>] [-h, --help]
[--log-level <value>] [--log-output <value>]
[--image-format <value>] [--audio-format <value>]
[--export-asset-list <value>] [--filter-by-name <text>]
[-f, --filename-format <value>] [-o, --output <path>]
[-h, --help] [--log-level <value>]
[--log-output <value>] [--image-format <value>]
[--audio-format <value>] [--l2d-motion-mode <value>]
[--l2d-force-bezier] [--fbx-scale-factor <value>]
[--fbx-bone-size <value>] [--filter-by-name <text>]
[--filter-by-container <text>] [--filter-by-pathid <text>]
[--filter-by-text <text>] [--assembly-folder <path>]
[--unity-version <text>] [--not-restore-extension]
[--filter-by-text <text>] [--custom-compression <value>]
[--max-export-tasks <value>] [--export-asset-list <value>]
[--assembly-folder <path>] [--unity-version <text>]
[--not-restore-extension] [--avoid-typetree-loading]
[--load-all]
General Options:
-m, --mode <value> Specify working mode
<Value: export(default) | exportRaw | dump | info | live2d>
<Value: export(default) | exportRaw | dump | info | live2d | splitObjects>
Export - Exports converted assets
ExportRaw - Exports raw data
Dump - Makes asset dumps
Info - Loads file(s), shows the number of available for export assets and exits
Live2D - Exports Live2D Cubism 3 models
Live2D - Exports Live2D Cubism models
SplitObjects - Exports split objects (fbx)
Example: "-m info"
-t, --asset-type <value(s)> Specify asset type(s) to export
<Value(s): tex2d, sprite, textAsset, monoBehaviour, font, shader, movieTexture,
audio, video, mesh | all(default)>
<Value(s): tex2d, tex2dArray, sprite, textAsset, monoBehaviour, font, shader
movieTexture, audio, video, mesh | all(default)>
All - export all asset types, which are listed in the values
*To specify multiple asset types, write them separated by ',' or ';' without spaces
Examples: "-t sprite" or "-t tex2d,sprite,audio" or "-t tex2d;sprite;font"
-g, --group-option <value> Specify the way in which exported assets should be grouped
<Value: none | type | container(default) | containerFull | filename>
<Value: none | type | container(default) | containerFull | filename | sceneHierarchy>
None - Do not group exported assets
Type - Group exported assets by type name
Container - Group exported assets by container path
ContainerFull - Group exported assets by full container path (e.g. with prefab name)
SceneHierarchy - Group exported assets by their node path in scene hierarchy
Filename - Group exported assets by source file name
Example: "-g container"
Example: "-g containerFull"
-f, --filename-format <value> Specify the file name format for exported assets
<Value: assetName(default) | assetName_pathID | pathID>
AssetName - Asset file names will look like "assetName.extension"
AssetName_pathID - Asset file names will look like "assetName @pathID.extension"
PathID - Asset file names will look like "pathID.extension"
Example: "-f assetName_pathID"
-o, --output <path> Specify path to the output folder
If path isn't specifyed, 'ASExport' folder will be created in the program's work folder
If path isn't specified, 'ASExport' folder will be created in the program's work folder
-h, --help Display help and exit
@@ -62,17 +75,32 @@ Convert Options:
None - Do not convert images and export them as texture data (.tex)
Example: "--image-format jpg"
--audio-format <value> Specify the format for converting audio assets
--audio-format <value> Specify the format for converting FMOD audio assets
<Value: none | wav(default)>
None - Do not convert audios and export them in their own format
None - Do not convert fmod audios and export them in their own format
Example: "--audio-format wav"
Advanced Options:
--export-asset-list <value> Specify the format in which you want to export asset list
<Value: none(default) | xml>
None - Do not export asset list
Example: "--export-asset-list xml"
Live2D Options:
--l2d-motion-mode <value> Specify Live2D motion export mode
<Value: monoBehaviour(default) | animationClip>
MonoBehaviour - Try to export motions from MonoBehaviour Fade motions
If no Fade motions are found, the AnimationClip method will be used
AnimationClip - Try to export motions using AnimationClip assets
Example: "--l2d-motion-mode animationClip"
--l2d-force-bezier (Flag) If specified, Linear motion segments will be calculated as Bezier segments
(May help if the exported motions look jerky/not smooth enough)
FBX Options:
--fbx-scale-factor <value> Specify the FBX Scale Factor
<Value: float number from 0 to 100 (default=1)>
Example: "--fbx-scale-factor 50"
--fbx-bone-size <value> Specify the FBX Bone Size
<Value: integer number from 0 to 100 (default=10)>
Example: "--fbx-bone-size 10"
Filter Options:
--filter-by-name <text> Specify the name by which assets should be filtered
*To specify multiple names write them separated by ',' or ';' without spaces
Example: "--filter-by-name char" or "--filter-by-name char,bg"
@@ -90,8 +118,35 @@ Advanced Options:
*To specify multiple values write them separated by ',' or ';' without spaces
Example: "--filter-by-text portrait" or "--filter-by-text portrait,art"
Advanced Options:
--custom-compression <value> Specify the compression type for assets that use custom compression
<Value: zstd(default) | lz4>
Zstd - Try to decompress as zstd archive
Lz4 - Try to decompress as lz4 archive
Example: "--custom-compression lz4"
--max-export-tasks <value> Specify the number of parallel tasks for asset export
<Value: integer number from 1 to max number of cores (default=max)>
Max - Number of cores in your CPU
Example: "--max-export-tasks 8"
--export-asset-list <value> Specify the format in which you want to export asset list
<Value: none(default) | xml>
None - Do not export asset list
Example: "--export-asset-list xml"
--assembly-folder <path> Specify the path to the assembly folder
--unity-version <text> Specify Unity version. Example: "--unity-version 2017.4.39f1"
--unity-version <text> Specify Unity version
Example: "--unity-version 2017.4.39f1"
--not-restore-extension (Flag) If specified, AssetStudio will not try to use/restore original TextAsset
extension name, and will just export all TextAssets with the ".txt" extension
--avoid-typetree-loading (Flag) If specified, AssetStudio will not try to parse assets at load time
using their type tree
--load-all (Flag) If specified, AssetStudio will load assets of all types
(Only for Dump, Info and ExportRaw modes)
```

View File

@@ -1,13 +1,16 @@
using AssetStudio;
using AssetStudioCLI.Options;
using CubismLive2DExtractor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using static AssetStudioCLI.Exporter;
using static CubismLive2DExtractor.Live2DExtractor;
using Ansi = AssetStudioCLI.CLIAnsiColors;
using Ansi = AssetStudio.ColorConsole;
namespace AssetStudioCLI
{
@@ -15,7 +18,9 @@ namespace AssetStudioCLI
{
public static AssetsManager assetsManager = new AssetsManager();
public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
public static List<BaseNode> gameObjectTree = new List<BaseNode>();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
public static List<MonoBehaviour> cubismMocList = new List<MonoBehaviour>();
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
static Studio()
@@ -32,8 +37,12 @@ namespace AssetStudioCLI
{
var isLoaded = false;
assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.Value;
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
assetsManager.ZstdEnabled = CLIOptions.o_customCompressionType.Value == CustomCompressionType.Zstd;
assetsManager.LoadingViaTypeTreeEnabled = !CLIOptions.f_avoidLoadingViaTypetree.Value;
if (!CLIOptions.f_loadAllAssets.Value)
{
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
}
assetsManager.LoadFilesAndFolders(CLIOptions.inputPath);
if (assetsManager.assetsFileList.Count == 0)
{
@@ -52,28 +61,42 @@ namespace AssetStudioCLI
Logger.Info("Parse assets...");
var fileAssetsList = new List<AssetItem>();
var tex2dArrayAssetList = new List<AssetItem>();
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<AssetStudio.Object, AssetItem>(objectCount);
Progress.Reset();
var i = 0;
foreach (var assetsFile in assetsManager.assetsFileList)
{
var preloadTable = Array.Empty<PPtr<AssetStudio.Object>>();
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
objectAssetItemDic.Add(asset, assetItem);
assetItem.UniqueID = "_#" + i;
var isExportable = false;
switch (asset)
{
case PreloadData m_PreloadData:
preloadTable = m_PreloadData.m_Assets;
break;
case AssetBundle m_AssetBundle:
var isStreamedSceneAssetBundle = m_AssetBundle.m_IsStreamedSceneAssetBundle;
if (!isStreamedSceneAssetBundle)
{
preloadTable = m_AssetBundle.m_PreloadTable;
}
assetItem.Text = string.IsNullOrEmpty(m_AssetBundle.m_AssetBundleName) ? m_AssetBundle.m_Name : m_AssetBundle.m_AssetBundleName;
foreach (var m_Container in m_AssetBundle.m_Container)
{
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadSize = isStreamedSceneAssetBundle ? preloadTable.Length : m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
for (var k = preloadIndex; k < preloadEnd; k++)
{
var pptr = m_AssetBundle.m_PreloadTable[k];
var pptr = preloadTable[k];
if (pptr.TryGet(out var obj))
{
containers[obj] = m_Container.Key;
@@ -95,6 +118,12 @@ namespace AssetStudioCLI
assetItem.FullSize = asset.byteSize + m_Texture2D.m_StreamData.size;
assetItem.Text = m_Texture2D.m_Name;
break;
case Texture2DArray m_Texture2DArray:
if (!string.IsNullOrEmpty(m_Texture2DArray.m_StreamData?.path))
assetItem.FullSize = asset.byteSize + m_Texture2DArray.m_StreamData.size;
assetItem.Text = m_Texture2DArray.m_Name;
tex2dArrayAssetList.Add(assetItem);
break;
case AudioClip m_AudioClip:
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size;
@@ -105,34 +134,41 @@ namespace AssetStudioCLI
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
assetItem.Text = m_VideoClip.m_Name;
break;
case Mesh _:
case MovieTexture _:
case TextAsset _:
case Font _:
case Sprite _:
assetItem.Text = ((NamedObject)asset).m_Name;
break;
case Shader m_Shader:
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
break;
case MonoBehaviour m_MonoBehaviour:
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
var assetName = m_MonoBehaviour.m_Name;
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
assetItem.Text = m_Script.m_ClassName;
assetName = assetName == "" ? m_Script.m_ClassName : assetName;
if (m_Script.m_ClassName == "CubismMoc")
{
cubismMocList.Add(m_MonoBehaviour);
}
}
else
assetItem.Text = assetName;
break;
case GameObject m_GameObject:
assetItem.Text = m_GameObject.m_Name;
break;
case Animator m_Animator:
if (m_Animator.m_GameObject.TryGet(out var gameObject))
{
assetItem.Text = m_MonoBehaviour.m_Name;
assetItem.Text = gameObject.m_Name;
}
break;
case NamedObject m_NamedObject:
assetItem.Text = m_NamedObject.m_Name;
break;
}
if (assetItem.Text == "")
if (string.IsNullOrEmpty(assetItem.Text))
{
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
}
isExportable = CLIOptions.o_exportAssetTypes.Value.Contains(asset.type);
if (isExportable)
if (isExportable || (CLIOptions.f_loadAllAssets.Value && CLIOptions.o_exportAssetTypes.Value == CLIOptions.o_exportAssetTypes.DefaultValue))
{
fileAssetsList.Add(assetItem);
}
@@ -141,22 +177,38 @@ namespace AssetStudioCLI
}
foreach (var asset in fileAssetsList)
{
if (containers.ContainsKey(asset.Asset))
if (containers.TryGetValue(asset.Asset, out var container))
{
asset.Container = containers[asset.Asset];
asset.Container = container;
}
}
foreach (var tex2dAssetItem in tex2dArrayAssetList)
{
var m_Texture2DArray = (Texture2DArray)tex2dAssetItem.Asset;
for (var layer = 0; layer < m_Texture2DArray.m_Depth; layer++)
{
var fakeObj = new Texture2D(m_Texture2DArray, layer);
m_Texture2DArray.TextureList.Add(fakeObj);
}
}
parsedAssetsList.AddRange(fileAssetsList);
fileAssetsList.Clear();
if (CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
tex2dArrayAssetList.Clear();
if (CLIOptions.o_workMode.Value != WorkMode.Live2D)
{
containers.Clear();
}
}
if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects || CLIOptions.o_groupAssetsBy.Value == AssetGroupOption.SceneHierarchy)
{
BuildTreeStructure(objectAssetItemDic);
}
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {parsedAssetsList.Count} exportable assets";
var unityVer = assetsManager.assetsFileList[0].version;
long m_ObjectsCount;
if (unityVer[0] > 2020)
if (unityVer > 2020)
{
m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y =>
y.classID != (int)ClassIDType.Shader
@@ -175,6 +227,99 @@ namespace AssetStudioCLI
Logger.Info(log);
}
public static void BuildTreeStructure(Dictionary<AssetStudio.Object, AssetItem> objectAssetItemDic)
{
Logger.Info("Building tree structure...");
var treeNodeDictionary = new Dictionary<GameObject, GameObjectNode>();
var assetsFileCount = assetsManager.assetsFileList.Count;
int j = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var fileNode = new BaseNode(assetsFile.fileName); //RootNode
foreach (var obj in assetsFile.Objects)
{
if (obj is GameObject m_GameObject)
{
if (!treeNodeDictionary.TryGetValue(m_GameObject, out var currentNode))
{
currentNode = new GameObjectNode(m_GameObject);
treeNodeDictionary.Add(m_GameObject, currentNode);
}
foreach (var pptr in m_GameObject.m_Components)
{
if (pptr.TryGet(out var m_Component))
{
objectAssetItemDic[m_Component].Node = currentNode;
if (m_Component is MeshFilter m_MeshFilter)
{
if (m_MeshFilter.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].Node = currentNode;
}
}
else if (m_Component is SkinnedMeshRenderer m_SkinnedMeshRenderer)
{
if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].Node = currentNode;
}
}
}
}
var parentNode = fileNode;
if (m_GameObject.m_Transform != null)
{
if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father))
{
if (m_Father.m_GameObject.TryGet(out var parentGameObject))
{
if (!treeNodeDictionary.TryGetValue(parentGameObject, out var parentGameObjectNode))
{
parentGameObjectNode = new GameObjectNode(parentGameObject);
treeNodeDictionary.Add(parentGameObject, parentGameObjectNode);
}
parentNode = parentGameObjectNode;
}
}
}
parentNode.nodes.Add(currentNode);
}
}
if (fileNode.nodes.Count > 0)
{
GenerateFullPath(fileNode, fileNode.Text);
gameObjectTree.Add(fileNode);
}
Progress.Report(++j, assetsFileCount);
}
treeNodeDictionary.Clear();
objectAssetItemDic.Clear();
}
private static void GenerateFullPath(BaseNode treeNode, string path)
{
treeNode.FullPath = path;
foreach (var node in treeNode.nodes)
{
if (node.nodes.Count > 0)
{
GenerateFullPath(node, Path.Combine(path, node.Text));
}
else
{
node.FullPath = Path.Combine(path, node.Text);
}
}
}
public static void ShowExportableAssetsInfo()
{
var exportableAssetsCountDict = new Dictionary<ClassIDType, int>();
@@ -218,7 +363,20 @@ namespace AssetStudioCLI
}
}
public static void FilterAssets()
public static void Filter()
{
switch (CLIOptions.o_workMode.Value)
{
case WorkMode.Live2D:
case WorkMode.SplitObjects:
break;
default:
FilterAssets();
break;
}
}
private static void FilterAssets()
{
var assetsCount = parsedAssetsList.Count;
var filteredAssets = new List<AssetItem>();
@@ -226,14 +384,14 @@ namespace AssetStudioCLI
switch(CLIOptions.filterBy)
{
case FilterBy.Name:
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
);
break;
case FilterBy.Container:
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers."
@@ -248,8 +406,8 @@ namespace AssetStudioCLI
break;
case FilterBy.NameOrContainer:
filteredAssets = parsedAssetsList.FindAll(x =>
CLIOptions.o_filterByText.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
CLIOptions.o_filterByText.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
CLIOptions.o_filterByText.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
CLIOptions.o_filterByText.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
);
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
@@ -258,8 +416,8 @@ namespace AssetStudioCLI
break;
case FilterBy.NameAndContainer:
filteredAssets = parsedAssetsList.FindAll(x =>
CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
CLIOptions.o_filterByName.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
CLIOptions.o_filterByContainer.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
);
Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
@@ -279,7 +437,10 @@ namespace AssetStudioCLI
var exportedCount = 0;
var groupOption = CLIOptions.o_groupAssetsBy.Value;
foreach (var asset in parsedAssetsList)
var parallelExportCount = CLIOptions.o_maxParallelExportTasks.Value;
var toExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
var toParallelExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
Parallel.ForEach(parsedAssetsList, asset =>
{
string exportPath;
switch (groupOption)
@@ -312,36 +473,75 @@ namespace AssetStudioCLI
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
}
break;
case AssetGroupOption.SceneHierarchy:
if (asset.Node != null)
{
exportPath = Path.Combine(savePath, asset.Node.FullPath);
}
else
{
exportPath = Path.Combine(savePath, "_sceneRoot", asset.TypeString);
}
break;
default:
exportPath = savePath;
break;
}
exportPath += Path.DirectorySeparatorChar;
if (CLIOptions.o_workMode.Value == WorkMode.Export)
{
switch (asset.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Sprite:
case ClassIDType.AudioClip:
toParallelExportAssetDict.TryAdd(asset, exportPath);
break;
case ClassIDType.Texture2DArray:
var m_Texture2DArray = (Texture2DArray)asset.Asset;
toExportCount += m_Texture2DArray.TextureList.Count - 1;
foreach (var texture in m_Texture2DArray.TextureList)
{
var fakeItem = new AssetItem(texture)
{
Text = texture.m_Name,
Container = asset.Container,
};
toParallelExportAssetDict.TryAdd(fakeItem, exportPath);
}
break;
default:
toExportAssetDict.TryAdd(asset, exportPath);
break;
}
}
else
{
toExportAssetDict.TryAdd(asset, exportPath);
}
});
foreach (var toExportAsset in toExportAssetDict)
{
var asset = toExportAsset.Key;
var exportPath = toExportAsset.Value;
var isExported = false;
try
{
switch (CLIOptions.o_workMode.Value)
{
case WorkMode.ExportRaw:
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportRawFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportRawFile(asset, exportPath);
break;
case WorkMode.Dump:
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportDumpFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportDumpFile(asset, exportPath);
break;
case WorkMode.Export:
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportConvertFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportConvertFile(asset, exportPath);
break;
}
}
@@ -349,8 +549,33 @@ namespace AssetStudioCLI
{
Logger.Error($"{asset.SourceFile.originalPath}: [{$"{asset.Type}: {asset.Text}".Color(Ansi.BrightRed)}] : Export error\n{ex}");
}
if (isExported)
{
exportedCount++;
}
Console.Write($"Exported [{exportedCount}/{toExportCount}]\r");
}
Parallel.ForEach(toParallelExportAssetDict, new ParallelOptions { MaxDegreeOfParallelism = parallelExportCount }, toExportAsset =>
{
var asset = toExportAsset.Key;
var exportPath = toExportAsset.Value;
try
{
if (ParallelExporter.ParallelExportConvertFile(asset, exportPath, out var debugLog))
{
Interlocked.Increment(ref exportedCount);
Logger.Debug(debugLog);
Console.Write($"Exported [{exportedCount}/{toExportCount}]\r");
}
}
catch (Exception ex)
{
Logger.Error($"{asset.SourceFile.originalPath}: [{$"{asset.Type}: {asset.Text}".Color(Ansi.BrightRed)}] : Export error\n{ex}");
}
});
ParallelExporter.ClearHash();
Console.WriteLine("");
if (exportedCount == 0)
@@ -391,6 +616,7 @@ namespace AssetStudioCLI
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString),
new XElement("PathID", asset.m_PathID),
new XElement("Source", asset.SourceFile.fullName),
new XElement("TreeNode", asset.Node != null ? asset.Node.FullPath : ""),
new XElement("Size", asset.FullSize)
)
)
@@ -403,73 +629,188 @@ namespace AssetStudioCLI
Logger.Info($"Finished exporting asset list with {parsedAssetsList.Count} items.");
}
public static void ExportSplitObjects()
{
var savePath = CLIOptions.o_outputFolder.Value;
var searchList = CLIOptions.o_filterByName.Value;
var isFiltered = CLIOptions.filterBy == FilterBy.Name;
var exportableObjects = new List<GameObjectNode>();
var exportedCount = 0;
var k = 0;
Logger.Info($"Searching for objects to export..");
Progress.Reset();
var count = gameObjectTree.Sum(x => x.nodes.Count);
foreach (var node in gameObjectTree)
{
foreach (GameObjectNode j in node.nodes)
{
if (isFiltered)
{
if (!searchList.Any(searchText => j.Text.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0))
continue;
}
var gameObjects = new List<GameObject>();
CollectNode(j, gameObjects);
if (gameObjects.All(x => x.m_SkinnedMeshRenderer == null && x.m_MeshFilter == null))
{
Progress.Report(++k, count);
continue;
}
exportableObjects.Add(j);
}
}
gameObjectTree.Clear();
var exportableCount = exportableObjects.Count;
var log = $"Found {exportableCount} exportable object(s) ";
if (isFiltered)
{
log += $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names";
}
Logger.Info(log);
if (exportableCount > 0)
{
Progress.Reset();
k = 0;
foreach (var gameObjectNode in exportableObjects)
{
var gameObject = gameObjectNode.gameObject;
var filename = FixFileName(gameObject.m_Name);
var targetPath = $"{savePath}{filename}{Path.DirectorySeparatorChar}";
//重名文件处理
for (int i = 1; ; i++)
{
if (Directory.Exists(targetPath))
{
targetPath = $"{savePath}{filename} ({i}){Path.DirectorySeparatorChar}";
}
else
{
break;
}
}
Directory.CreateDirectory(targetPath);
//导出FBX
Logger.Info($"Exporting {filename}.fbx");
Progress.Report(k, exportableCount);
try
{
ExportGameObject(gameObject, targetPath);
Logger.Debug($"{gameObject.type} \"{filename}\" saved to \"{targetPath}\"");
exportedCount++;
}
catch (Exception ex)
{
Logger.Error($"Export GameObject:{gameObject.m_Name} error", ex);
}
k++;
}
}
var status = exportedCount > 0
? $"Finished exporting [{exportedCount}/{exportableCount}] object(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\""
: "Nothing exported";
Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true);
}
private static void CollectNode(GameObjectNode node, List<GameObject> gameObjects)
{
gameObjects.Add(node.gameObject);
foreach (GameObjectNode i in node.nodes)
{
CollectNode(i, gameObjects);
}
}
public static void ExportLive2D()
{
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
var useFullContainerPath = false;
var useFullContainerPath = true;
var mocPathList = new List<string>();
var basePathSet = new HashSet<string>();
var motionMode = CLIOptions.o_l2dMotionMode.Value;
var forceBezier = CLIOptions.f_l2dForceBezier.Value;
Progress.Reset();
Logger.Info($"Searching for Live2D files...");
var cubismMocs = parsedAssetsList.Where(x =>
{
if (x.Type == ClassIDType.MonoBehaviour)
{
((MonoBehaviour)x.Asset).m_Script.TryGet(out var m_Script);
return m_Script?.m_ClassName == "CubismMoc";
}
return false;
}).Select(x => x.Asset).ToArray();
if (cubismMocs.Length == 0)
if (cubismMocList.Count == 0)
{
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
return;
}
if (cubismMocs.Length > 1)
{
var basePathSet = cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToHashSet();
if (basePathSet.Count != cubismMocs.Length)
{
useFullContainerPath = true;
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
}
Progress.Reset();
Logger.Info($"Searching for Live2D files...");
foreach (var mocMonoBehaviour in cubismMocList)
{
if (!containers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
continue;
var pathSepIndex = fullContainerPath.LastIndexOf('/');
var basePath = pathSepIndex > 0
? fullContainerPath.Substring(0, pathSepIndex)
: fullContainerPath;
basePathSet.Add(basePath);
mocPathList.Add(fullContainerPath);
}
var basePathList = useFullContainerPath ?
cubismMocs.Select(x => containers[x]).ToList() :
cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToList();
var lookup = containers.ToLookup(
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
if (mocPathList.Count == 0)
{
Logger.Error("Live2D Cubism export error: Cannot find any model related files.");
return;
}
if (basePathSet.Count == mocPathList.Count)
{
mocPathList = basePathSet.ToList();
useFullContainerPath = false;
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
}
basePathSet.Clear();
var lookup = containers.AsParallel().ToLookup(
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
x => x.Key
);
if (cubismMocList[0].serializedType?.m_Type == null && CLIOptions.o_assemblyPath.Value == "")
{
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
}
var totalModelCount = lookup.LongCount(x => x.Key != null);
Logger.Info($"Found {totalModelCount} model(s).");
var name = "";
var parallelTaskCount = CLIOptions.o_maxParallelExportTasks.Value;
var modelCounter = 0;
foreach (var assets in lookup)
{
var container = assets.Key;
if (container == null)
var srcContainer = assets.Key;
if (srcContainer == null)
continue;
name = container;
var container = srcContainer;
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{container.Color(Ansi.BrightCyan)}\"");
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer.Color(Ansi.BrightCyan)}\"");
try
{
var modelName = useFullContainerPath ? Path.GetFileNameWithoutExtension(container) : container.Substring(container.LastIndexOf('/') + 1);
container = Path.HasExtension(container) ? container.Replace(Path.GetExtension(container), "") : container;
var modelName = useFullContainerPath
? Path.GetFileNameWithoutExtension(container)
: container.Substring(container.LastIndexOf('/') + 1);
container = Path.HasExtension(container)
? container.Replace(Path.GetExtension(container), "")
: container;
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
ExtractLive2D(assets, destPath, modelName, assemblyLoader);
var modelExtractor = new Live2DExtractor(assets);
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelTaskCount);
modelCounter++;
}
catch (Exception ex)
{
Logger.Error($"Live2D model export error: \"{name}\"", ex);
Logger.Error($"Live2D model export error: \"{srcContainer}\"", ex);
}
Progress.Report(modelCounter, (int)totalModelCount);
}
var status = modelCounter > 0 ?
$"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" :
"Nothing exported.";

View File

@@ -0,0 +1,22 @@
# Set the minimum version of CMake that can be used
cmake_minimum_required (VERSION 3.8)
# Set the project name
project("AssetStudioFBXNative")
# Set the C++ standard to C++ 14
set(CMAKE_CXX_STANDARD 14)
# Generate the shared library from the library sources
add_library(AssetStudioFBXNative SHARED
asfbx_skin_context.cpp
asfbx_morph_context.cpp
api.cpp
utils.cpp
asfbx_context.cpp
asfbx_anim_context.cpp)
# Add the given directories to those the compiler uses to search for include files
target_include_directories(AssetStudioFBXNative PRIVATE .)
target_link_libraries(AssetStudioFBXNative PRIVATE fbxsdk xml2)

View File

@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.2.0</Version>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>

View File

@@ -164,7 +164,7 @@
this.tableLayoutPanel2.ColumnCount = 3;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 41.37931F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 58.62069F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 111F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 112F));
this.tableLayoutPanel2.Controls.Add(this.label16, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.label17, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.gitPerfareLinkLabel, 2, 0);
@@ -194,7 +194,7 @@
//
this.label17.AutoSize = true;
this.label17.BackColor = System.Drawing.Color.Transparent;
this.label17.Location = new System.Drawing.Point(102, 2);
this.label17.Location = new System.Drawing.Point(101, 2);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(110, 13);
this.label17.TabIndex = 10;
@@ -204,7 +204,7 @@
//
this.gitPerfareLinkLabel.AutoSize = true;
this.gitPerfareLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.gitPerfareLinkLabel.Location = new System.Drawing.Point(239, 2);
this.gitPerfareLinkLabel.Location = new System.Drawing.Point(238, 2);
this.gitPerfareLinkLabel.Name = "gitPerfareLinkLabel";
this.gitPerfareLinkLabel.Size = new System.Drawing.Size(67, 13);
this.gitPerfareLinkLabel.TabIndex = 11;
@@ -226,17 +226,17 @@
//
this.label19.AutoSize = true;
this.label19.BackColor = System.Drawing.Color.Transparent;
this.label19.Location = new System.Drawing.Point(102, 20);
this.label19.Location = new System.Drawing.Point(101, 20);
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(113, 13);
this.label19.TabIndex = 13;
this.label19.Text = "aelurum (c) 2021-2023";
this.label19.Text = "aelurum (c) 2021-2024";
//
// gitAelurumLinkLabel
//
this.gitAelurumLinkLabel.AutoSize = true;
this.gitAelurumLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.gitAelurumLinkLabel.Location = new System.Drawing.Point(239, 20);
this.gitAelurumLinkLabel.Location = new System.Drawing.Point(238, 20);
this.gitAelurumLinkLabel.Name = "gitAelurumLinkLabel";
this.gitAelurumLinkLabel.Size = new System.Drawing.Size(67, 13);
this.gitAelurumLinkLabel.TabIndex = 14;
@@ -250,7 +250,7 @@
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 41.37931F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 58.62069F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 111F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 112F));
this.tableLayoutPanel1.Controls.Add(this.label5, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.productNamelabel, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.label7, 0, 1);
@@ -285,7 +285,7 @@
//
this.productNamelabel.AutoSize = true;
this.productNamelabel.BackColor = System.Drawing.Color.Transparent;
this.productNamelabel.Location = new System.Drawing.Point(102, 2);
this.productNamelabel.Location = new System.Drawing.Point(101, 2);
this.productNamelabel.Name = "productNamelabel";
this.productNamelabel.Size = new System.Drawing.Size(103, 13);
this.productNamelabel.TabIndex = 1;
@@ -306,11 +306,11 @@
this.modVersionLabel.AutoSize = true;
this.modVersionLabel.BackColor = System.Drawing.Color.Transparent;
this.modVersionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.modVersionLabel.Location = new System.Drawing.Point(102, 20);
this.modVersionLabel.Location = new System.Drawing.Point(101, 20);
this.modVersionLabel.Name = "modVersionLabel";
this.modVersionLabel.Size = new System.Drawing.Size(52, 13);
this.modVersionLabel.Size = new System.Drawing.Size(46, 13);
this.modVersionLabel.TabIndex = 3;
this.modVersionLabel.Text = "0.16.48.1";
this.modVersionLabel.Text = "0.18.0.0";
//
// label4
//
@@ -327,7 +327,7 @@
//
this.label8.AutoSize = true;
this.label8.BackColor = System.Drawing.Color.Transparent;
this.label8.Location = new System.Drawing.Point(102, 38);
this.label8.Location = new System.Drawing.Point(101, 38);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(108, 13);
this.label8.TabIndex = 5;
@@ -337,7 +337,7 @@
//
this.checkUpdatesLinkLabel.AutoSize = true;
this.checkUpdatesLinkLabel.BackColor = System.Drawing.Color.Transparent;
this.checkUpdatesLinkLabel.Location = new System.Drawing.Point(239, 20);
this.checkUpdatesLinkLabel.Location = new System.Drawing.Point(238, 20);
this.checkUpdatesLinkLabel.Name = "checkUpdatesLinkLabel";
this.checkUpdatesLinkLabel.Size = new System.Drawing.Size(96, 13);
this.checkUpdatesLinkLabel.TabIndex = 6;
@@ -414,7 +414,7 @@
this.productVersionLabel.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0);
this.productVersionLabel.Size = new System.Drawing.Size(384, 13);
this.productVersionLabel.TabIndex = 2;
this.productVersionLabel.Text = "v0.16.48.1 [x64]";
this.productVersionLabel.Text = "v0.18.0.0 [x64]";
this.productVersionLabel.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
//
// panel2

View File

@@ -10,13 +10,15 @@ namespace AssetStudioGUI
public AboutForm()
{
InitializeComponent();
var productName = Application.ProductName;
var arch = Environment.Is64BitProcess ? "x64" : "x32";
var appAssembly = typeof(Program).Assembly.GetName();
var productName = appAssembly.Name;
var productVer = appAssembly.Version.ToString();
Text += " " + productName;
productTitleLabel.Text = productName;
productVersionLabel.Text = $"v{Application.ProductVersion} [{arch}]";
productVersionLabel.Text = $"v{productVer} [{arch}]";
productNamelabel.Text = productName;
modVersionLabel.Text = Application.ProductVersion;
modVersionLabel.Text = productVer;
licenseRichTextBox.Text = GetLicenseText();
}

View File

@@ -2,13 +2,13 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net472;net6.0-windows;net7.0-windows</TargetFrameworks>
<TargetFrameworks>net472;net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModGUI</AssemblyName>
<Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2024</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
@@ -54,14 +54,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="OpenTK.Graphics" Version="4.8.0" />
<PackageReference Include="OpenTK.Windowing.Desktop" Version="4.8.0" />
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
<PackageReference Include="OpenTK.Windowing.Desktop" Version="4.8.2" />
<Reference Include="OpenTK.WinForms">
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
</Reference>

View File

@@ -39,8 +39,14 @@
this.extractFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.displayAll = new System.Windows.Forms.ToolStripMenuItem();
this.useAssetLoadingViaTypetreeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.assetLoadingToolStripSeparator = new System.Windows.Forms.ToolStripSeparator();
this.enablePreview = new System.Windows.Forms.ToolStripMenuItem();
this.displayInfo = new System.Windows.Forms.ToolStripMenuItem();
this.buildTreeStructureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.customCompressionTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.customCompressionZstdToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.customCompressionLZ4ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem();
this.specifyUnityVersion = new System.Windows.Forms.ToolStripTextBox();
this.showExpOpt = new System.Windows.Forms.ToolStripMenuItem();
@@ -67,7 +73,12 @@
this.toolStripMenuItem8 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem9 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator();
this.allLive2DModelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.live2DCubismModelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.allL2DModelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.selectedL2DModelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.l2DModelWithFadeListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.l2DModelWithFadeMotionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.l2DModelWithClipsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem11 = new System.Windows.Forms.ToolStripMenuItem();
@@ -76,7 +87,9 @@
this.filterTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.showConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripMenuItem();
this.writeLogToFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportClassStructuresMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
@@ -103,7 +116,7 @@
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.tabControl2 = new System.Windows.Forms.TabControl();
this.tabPage4 = new System.Windows.Forms.TabPage();
this.previewPanel = new System.Windows.Forms.Panel();
this.previewPanel = new System.Windows.Forms.PictureBox();
this.assetInfoLabel = new System.Windows.Forms.Label();
this.FMODpanel = new System.Windows.Forms.Panel();
this.FMODcopyright = new System.Windows.Forms.Label();
@@ -137,8 +150,12 @@
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportSelectedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportAnimatorwithselectedAnimationClipMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.dumpSelectedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportAnimatorWithSelectedAnimationClipMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportAsLive2DModelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportL2DWithFadeLstToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportL2DWithFadeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportL2DWithClipsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.goToSceneHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
@@ -154,6 +171,7 @@
this.progressbarPanel.SuspendLayout();
this.tabControl2.SuspendLayout();
this.tabPage4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.previewPanel)).BeginInit();
this.previewPanel.SuspendLayout();
this.FMODpanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).BeginInit();
@@ -229,8 +247,12 @@
//
this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.displayAll,
this.useAssetLoadingViaTypetreeToolStripMenuItem,
this.assetLoadingToolStripSeparator,
this.enablePreview,
this.displayInfo,
this.buildTreeStructureToolStripMenuItem,
this.customCompressionTypeToolStripMenuItem,
this.toolStripMenuItem14,
this.showExpOpt});
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
@@ -241,19 +263,36 @@
//
this.displayAll.CheckOnClick = true;
this.displayAll.Name = "displayAll";
this.displayAll.Size = new System.Drawing.Size(207, 22);
this.displayAll.Size = new System.Drawing.Size(241, 22);
this.displayAll.Text = "Display all assets";
this.displayAll.ToolTipText = "Check this option will display all types assets. Not extractable assets can expor" +
"t the RAW file.";
this.displayAll.CheckedChanged += new System.EventHandler(this.displayAll_CheckedChanged);
//
// useAssetLoadingViaTypetreeToolStripMenuItem
//
this.useAssetLoadingViaTypetreeToolStripMenuItem.Checked = true;
this.useAssetLoadingViaTypetreeToolStripMenuItem.CheckOnClick = true;
this.useAssetLoadingViaTypetreeToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.useAssetLoadingViaTypetreeToolStripMenuItem.Name = "useAssetLoadingViaTypetreeToolStripMenuItem";
this.useAssetLoadingViaTypetreeToolStripMenuItem.Size = new System.Drawing.Size(241, 22);
this.useAssetLoadingViaTypetreeToolStripMenuItem.Text = "Parse assets using their typetree";
this.useAssetLoadingViaTypetreeToolStripMenuItem.ToolTipText = "(Applies to assets with typetree included). Slower but more correct parsing. Only" +
" for Texture2D and AnimationClip assets for now.";
this.useAssetLoadingViaTypetreeToolStripMenuItem.CheckedChanged += new System.EventHandler(this.useAssetLoadingViaTypetreeToolStripMenuItem_CheckedChanged);
//
// assetLoadingToolStripSeparator
//
this.assetLoadingToolStripSeparator.Name = "assetLoadingToolStripSeparator";
this.assetLoadingToolStripSeparator.Size = new System.Drawing.Size(238, 6);
//
// enablePreview
//
this.enablePreview.Checked = true;
this.enablePreview.CheckOnClick = true;
this.enablePreview.CheckState = System.Windows.Forms.CheckState.Checked;
this.enablePreview.Name = "enablePreview";
this.enablePreview.Size = new System.Drawing.Size(207, 22);
this.enablePreview.Size = new System.Drawing.Size(241, 22);
this.enablePreview.Text = "Enable preview";
this.enablePreview.ToolTipText = "Toggle the loading and preview of readable assets, such as images, sounds, text, " +
"etc.\r\nDisable preview if you have performance or compatibility issues.";
@@ -265,19 +304,62 @@
this.displayInfo.CheckOnClick = true;
this.displayInfo.CheckState = System.Windows.Forms.CheckState.Checked;
this.displayInfo.Name = "displayInfo";
this.displayInfo.Size = new System.Drawing.Size(207, 22);
this.displayInfo.Size = new System.Drawing.Size(241, 22);
this.displayInfo.Text = "Display asset information";
this.displayInfo.ToolTipText = "Toggle the overlay that shows information about each asset, eg. image size, forma" +
"t, audio bitrate, etc.";
this.displayInfo.CheckedChanged += new System.EventHandler(this.displayAssetInfo_Check);
//
// buildTreeStructureToolStripMenuItem
//
this.buildTreeStructureToolStripMenuItem.Checked = true;
this.buildTreeStructureToolStripMenuItem.CheckOnClick = true;
this.buildTreeStructureToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.buildTreeStructureToolStripMenuItem.Name = "buildTreeStructureToolStripMenuItem";
this.buildTreeStructureToolStripMenuItem.Size = new System.Drawing.Size(241, 22);
this.buildTreeStructureToolStripMenuItem.Text = "Build tree structure";
this.buildTreeStructureToolStripMenuItem.ToolTipText = "You can disable tree structure building if you don\'t use the Scene Hierarchy tab";
this.buildTreeStructureToolStripMenuItem.CheckedChanged += new System.EventHandler(this.buildTreeStructureToolStripMenuItem_CheckedChanged);
//
// customCompressionTypeToolStripMenuItem
//
this.customCompressionTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.customCompressionZstdToolStripMenuItem,
this.customCompressionLZ4ToolStripMenuItem});
this.customCompressionTypeToolStripMenuItem.Name = "customCompressionTypeToolStripMenuItem";
this.customCompressionTypeToolStripMenuItem.Size = new System.Drawing.Size(241, 22);
this.customCompressionTypeToolStripMenuItem.Text = "Custom compression type";
//
// customCompressionZstdToolStripMenuItem
//
this.customCompressionZstdToolStripMenuItem.Checked = true;
this.customCompressionZstdToolStripMenuItem.CheckOnClick = true;
this.customCompressionZstdToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.customCompressionZstdToolStripMenuItem.Name = "customCompressionZstdToolStripMenuItem";
this.customCompressionZstdToolStripMenuItem.Size = new System.Drawing.Size(130, 22);
this.customCompressionZstdToolStripMenuItem.Text = "Zstd";
this.customCompressionZstdToolStripMenuItem.ToolTipText = "If selected, Zstd-decompression will be used for assets with custom compression t" +
"ype";
this.customCompressionZstdToolStripMenuItem.CheckedChanged += new System.EventHandler(this.customCompressionZstd_CheckedChanged);
//
// customCompressionLZ4ToolStripMenuItem
//
this.customCompressionLZ4ToolStripMenuItem.CheckOnClick = true;
this.customCompressionLZ4ToolStripMenuItem.Name = "customCompressionLZ4ToolStripMenuItem";
this.customCompressionLZ4ToolStripMenuItem.Size = new System.Drawing.Size(130, 22);
this.customCompressionLZ4ToolStripMenuItem.Text = "Lz4/Lz4HC";
this.customCompressionLZ4ToolStripMenuItem.ToolTipText = "If selected, Lz4-decompression will be used for assets with custom compression ty" +
"pe";
this.customCompressionLZ4ToolStripMenuItem.CheckedChanged += new System.EventHandler(this.customCompressionLZ4_CheckedChanged);
//
// toolStripMenuItem14
//
this.toolStripMenuItem14.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.specifyUnityVersion});
this.toolStripMenuItem14.Name = "toolStripMenuItem14";
this.toolStripMenuItem14.Size = new System.Drawing.Size(207, 22);
this.toolStripMenuItem14.Size = new System.Drawing.Size(241, 22);
this.toolStripMenuItem14.Text = "Specify Unity version";
this.toolStripMenuItem14.DropDownClosed += new System.EventHandler(this.specifyUnityVersion_Close);
//
// specifyUnityVersion
//
@@ -290,7 +372,7 @@
// showExpOpt
//
this.showExpOpt.Name = "showExpOpt";
this.showExpOpt.Size = new System.Drawing.Size(207, 22);
this.showExpOpt.Size = new System.Drawing.Size(241, 22);
this.showExpOpt.Text = "Export options";
this.showExpOpt.Click += new System.EventHandler(this.showExpOpt_Click);
//
@@ -312,7 +394,7 @@
this.exportAllObjectssplitToolStripMenuItem1.Name = "exportAllObjectssplitToolStripMenuItem1";
this.exportAllObjectssplitToolStripMenuItem1.Size = new System.Drawing.Size(382, 22);
this.exportAllObjectssplitToolStripMenuItem1.Text = "Export all objects (split)";
this.exportAllObjectssplitToolStripMenuItem1.Click += new System.EventHandler(this.exportAllObjectssplitToolStripMenuItem1_Click);
this.exportAllObjectssplitToolStripMenuItem1.Click += new System.EventHandler(this.exportAllObjectsSplitToolStripMenuItem1_Click);
//
// exportSelectedObjectsToolStripMenuItem
//
@@ -326,7 +408,7 @@
this.exportSelectedObjectsWithAnimationClipToolStripMenuItem.Name = "exportSelectedObjectsWithAnimationClipToolStripMenuItem";
this.exportSelectedObjectsWithAnimationClipToolStripMenuItem.Size = new System.Drawing.Size(382, 22);
this.exportSelectedObjectsWithAnimationClipToolStripMenuItem.Text = "Export selected objects (split) + selected AnimationClips";
this.exportSelectedObjectsWithAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportObjectswithAnimationClipMenuItem_Click);
this.exportSelectedObjectsWithAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportObjectsWithAnimationClipMenuItem_Click);
//
// toolStripSeparator1
//
@@ -338,14 +420,14 @@
this.exportSelectedObjectsmergeToolStripMenuItem.Name = "exportSelectedObjectsmergeToolStripMenuItem";
this.exportSelectedObjectsmergeToolStripMenuItem.Size = new System.Drawing.Size(382, 22);
this.exportSelectedObjectsmergeToolStripMenuItem.Text = "Export selected objects (merge)";
this.exportSelectedObjectsmergeToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedObjectsmergeToolStripMenuItem_Click);
this.exportSelectedObjectsmergeToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedObjectsMergeToolStripMenuItem_Click);
//
// exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem
//
this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem.Name = "exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem";
this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem.Size = new System.Drawing.Size(382, 22);
this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem.Text = "Export selected objects (merge) + selected AnimationClips";
this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem_Click);
this.exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedObjectsMergeWithAnimationClipToolStripMenuItem_Click);
//
// exportToolStripMenuItem
//
@@ -359,7 +441,7 @@
this.toolStripMenuItem2,
this.toolStripMenuItem3,
this.toolStripSeparator6,
this.allLive2DModelsToolStripMenuItem,
this.live2DCubismModelsToolStripMenuItem,
this.toolStripSeparator2,
this.toolStripMenuItem10});
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
@@ -397,7 +479,7 @@
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem.Name = "exportAnimatorWithSelectedAnimationClipToolStripMenuItem";
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem.Size = new System.Drawing.Size(266, 22);
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem.Text = "Animator + selected AnimationClips";
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportAnimatorwithAnimationClipMenuItem_Click);
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.exportAnimatorWithAnimationClipMenuItem_Click);
//
// toolStripSeparator4
//
@@ -471,12 +553,52 @@
this.toolStripSeparator6.Name = "toolStripSeparator6";
this.toolStripSeparator6.Size = new System.Drawing.Size(263, 6);
//
// allLive2DModelsToolStripMenuItem
// live2DCubismModelsToolStripMenuItem
//
this.allLive2DModelsToolStripMenuItem.Name = "allLive2DModelsToolStripMenuItem";
this.allLive2DModelsToolStripMenuItem.Size = new System.Drawing.Size(266, 22);
this.allLive2DModelsToolStripMenuItem.Text = "Live2D Cubism models";
this.allLive2DModelsToolStripMenuItem.Click += new System.EventHandler(this.allLive2DModelsToolStripMenuItem_Click);
this.live2DCubismModelsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.allL2DModelsToolStripMenuItem,
this.selectedL2DModelsToolStripMenuItem,
this.l2DModelWithFadeListToolStripMenuItem,
this.l2DModelWithFadeMotionsToolStripMenuItem,
this.l2DModelWithClipsToolStripMenuItem});
this.live2DCubismModelsToolStripMenuItem.Name = "live2DCubismModelsToolStripMenuItem";
this.live2DCubismModelsToolStripMenuItem.Size = new System.Drawing.Size(266, 22);
this.live2DCubismModelsToolStripMenuItem.Text = "Live2D Cubism models";
//
// allL2DModelsToolStripMenuItem
//
this.allL2DModelsToolStripMenuItem.Name = "allL2DModelsToolStripMenuItem";
this.allL2DModelsToolStripMenuItem.Size = new System.Drawing.Size(292, 22);
this.allL2DModelsToolStripMenuItem.Text = "All models";
this.allL2DModelsToolStripMenuItem.Click += new System.EventHandler(this.exportAllL2D_Click);
//
// selectedL2DModelsToolStripMenuItem
//
this.selectedL2DModelsToolStripMenuItem.Name = "selectedL2DModelsToolStripMenuItem";
this.selectedL2DModelsToolStripMenuItem.Size = new System.Drawing.Size(292, 22);
this.selectedL2DModelsToolStripMenuItem.Text = "Selected models";
this.selectedL2DModelsToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2D_Click);
//
// l2DModelWithFadeListToolStripMenuItem
//
this.l2DModelWithFadeListToolStripMenuItem.Name = "l2DModelWithFadeListToolStripMenuItem";
this.l2DModelWithFadeListToolStripMenuItem.Size = new System.Drawing.Size(292, 22);
this.l2DModelWithFadeListToolStripMenuItem.Text = "Model + selected Fade Motion List";
this.l2DModelWithFadeListToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithFadeList_Click);
//
// l2DModelWithFadeMotionsToolStripMenuItem
//
this.l2DModelWithFadeMotionsToolStripMenuItem.Name = "l2DModelWithFadeMotionsToolStripMenuItem";
this.l2DModelWithFadeMotionsToolStripMenuItem.Size = new System.Drawing.Size(292, 22);
this.l2DModelWithFadeMotionsToolStripMenuItem.Text = "Model + selected Fade motions";
this.l2DModelWithFadeMotionsToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithFadeMotions_Click);
//
// l2DModelWithClipsToolStripMenuItem
//
this.l2DModelWithClipsToolStripMenuItem.Name = "l2DModelWithClipsToolStripMenuItem";
this.l2DModelWithClipsToolStripMenuItem.Size = new System.Drawing.Size(292, 22);
this.l2DModelWithClipsToolStripMenuItem.Text = "Model + selected AnimationClip motions";
this.l2DModelWithClipsToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithClips_Click);
//
// toolStripSeparator2
//
@@ -535,24 +657,44 @@
// debugMenuItem
//
this.debugMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showConsoleToolStripMenuItem,
this.toolStripMenuItem15,
this.writeLogToFileToolStripMenuItem,
this.exportClassStructuresMenuItem});
this.debugMenuItem.Name = "debugMenuItem";
this.debugMenuItem.Size = new System.Drawing.Size(54, 20);
this.debugMenuItem.Text = "Debug";
//
// showConsoleToolStripMenuItem
//
this.showConsoleToolStripMenuItem.Checked = true;
this.showConsoleToolStripMenuItem.CheckOnClick = true;
this.showConsoleToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.showConsoleToolStripMenuItem.Name = "showConsoleToolStripMenuItem";
this.showConsoleToolStripMenuItem.Size = new System.Drawing.Size(288, 22);
this.showConsoleToolStripMenuItem.Text = "Show console logger";
this.showConsoleToolStripMenuItem.Click += new System.EventHandler(this.showConsoleToolStripMenuItem_Click);
//
// toolStripMenuItem15
//
this.toolStripMenuItem15.CheckOnClick = true;
this.toolStripMenuItem15.Name = "toolStripMenuItem15";
this.toolStripMenuItem15.Size = new System.Drawing.Size(200, 22);
this.toolStripMenuItem15.Text = "Show all error messages";
this.toolStripMenuItem15.Size = new System.Drawing.Size(288, 22);
this.toolStripMenuItem15.Text = "Show debug messages in console logger";
this.toolStripMenuItem15.Click += new System.EventHandler(this.toolStripMenuItem15_Click);
//
// writeLogToFileToolStripMenuItem
//
this.writeLogToFileToolStripMenuItem.CheckOnClick = true;
this.writeLogToFileToolStripMenuItem.Name = "writeLogToFileToolStripMenuItem";
this.writeLogToFileToolStripMenuItem.Size = new System.Drawing.Size(288, 22);
this.writeLogToFileToolStripMenuItem.Text = "Write log to file";
this.writeLogToFileToolStripMenuItem.CheckedChanged += new System.EventHandler(this.writeLogToFileToolStripMenuItem_CheckedChanged);
//
// exportClassStructuresMenuItem
//
this.exportClassStructuresMenuItem.Name = "exportClassStructuresMenuItem";
this.exportClassStructuresMenuItem.Size = new System.Drawing.Size(200, 22);
this.exportClassStructuresMenuItem.Size = new System.Drawing.Size(288, 22);
this.exportClassStructuresMenuItem.Text = "Export class structures";
this.exportClassStructuresMenuItem.Click += new System.EventHandler(this.exportClassStructuresMenuItem_Click);
//
@@ -715,7 +857,7 @@
this.listSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listSearch.BackColor = System.Drawing.Color.White;
this.listSearch.BackColor = System.Drawing.SystemColors.Window;
this.listSearch.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.listSearch.DetectUrls = false;
this.listSearch.ForeColor = System.Drawing.SystemColors.GrayText;
@@ -845,8 +987,6 @@
// previewPanel
//
this.previewPanel.BackColor = System.Drawing.SystemColors.ControlDark;
this.previewPanel.BackgroundImage = global::AssetStudioGUI.Properties.Resources.preview;
this.previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
this.previewPanel.Controls.Add(this.assetInfoLabel);
this.previewPanel.Controls.Add(this.FMODpanel);
this.previewPanel.Controls.Add(this.fontPreviewBox);
@@ -854,17 +994,20 @@
this.previewPanel.Controls.Add(this.textPreviewBox);
this.previewPanel.Controls.Add(this.classTextBox);
this.previewPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.previewPanel.Image = global::AssetStudioGUI.Properties.Resources.preview;
this.previewPanel.Location = new System.Drawing.Point(0, 0);
this.previewPanel.Name = "previewPanel";
this.previewPanel.Size = new System.Drawing.Size(768, 607);
this.previewPanel.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.previewPanel.TabIndex = 1;
this.previewPanel.TabStop = false;
this.previewPanel.Resize += new System.EventHandler(this.preview_Resize);
//
// assetInfoLabel
//
this.assetInfoLabel.AutoSize = true;
this.assetInfoLabel.BackColor = System.Drawing.Color.Transparent;
this.assetInfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.assetInfoLabel.ForeColor = System.Drawing.Color.White;
this.assetInfoLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.assetInfoLabel.Location = new System.Drawing.Point(4, 8);
this.assetInfoLabel.Name = "assetInfoLabel";
@@ -907,7 +1050,7 @@
//
this.FMODinfoLabel.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.FMODinfoLabel.AutoSize = true;
this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.HighlightText;
this.FMODinfoLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.FMODinfoLabel.Location = new System.Drawing.Point(275, 255);
this.FMODinfoLabel.Name = "FMODinfoLabel";
@@ -918,7 +1061,7 @@
//
this.FMODtimerLabel.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.FMODtimerLabel.AutoSize = true;
this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.HighlightText;
this.FMODtimerLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.FMODtimerLabel.Location = new System.Drawing.Point(457, 253);
this.FMODtimerLabel.Name = "FMODtimerLabel";
@@ -930,7 +1073,7 @@
//
this.FMODstatusLabel.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.FMODstatusLabel.AutoSize = true;
this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.HighlightText;
this.FMODstatusLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.FMODstatusLabel.Location = new System.Drawing.Point(214, 255);
this.FMODstatusLabel.Name = "FMODstatusLabel";
@@ -1191,46 +1334,82 @@
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.copyToolStripMenuItem,
this.exportSelectedAssetsToolStripMenuItem,
this.exportAnimatorwithselectedAnimationClipMenuItem,
this.dumpSelectedAssetsToolStripMenuItem,
this.exportAnimatorWithSelectedAnimationClipMenuItem,
this.exportAsLive2DModelToolStripMenuItem,
this.exportL2DWithFadeLstToolStripMenuItem,
this.exportL2DWithFadeToolStripMenuItem,
this.exportL2DWithClipsToolStripMenuItem,
this.goToSceneHierarchyToolStripMenuItem,
this.showOriginalFileToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(304, 136);
this.contextMenuStrip1.Size = new System.Drawing.Size(332, 224);
//
// copyToolStripMenuItem
//
this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
this.copyToolStripMenuItem.Size = new System.Drawing.Size(303, 22);
this.copyToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.copyToolStripMenuItem.Text = "Copy text";
this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
//
// exportSelectedAssetsToolStripMenuItem
//
this.exportSelectedAssetsToolStripMenuItem.Name = "exportSelectedAssetsToolStripMenuItem";
this.exportSelectedAssetsToolStripMenuItem.Size = new System.Drawing.Size(303, 22);
this.exportSelectedAssetsToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportSelectedAssetsToolStripMenuItem.Text = "Export selected assets";
this.exportSelectedAssetsToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedAssetsToolStripMenuItem_Click);
//
// exportAnimatorwithselectedAnimationClipMenuItem
//
this.exportAnimatorwithselectedAnimationClipMenuItem.Name = "exportAnimatorwithselectedAnimationClipMenuItem";
this.exportAnimatorwithselectedAnimationClipMenuItem.Size = new System.Drawing.Size(303, 22);
this.exportAnimatorwithselectedAnimationClipMenuItem.Text = "Export Animator + selected AnimationClips";
this.exportAnimatorwithselectedAnimationClipMenuItem.Visible = false;
this.exportAnimatorwithselectedAnimationClipMenuItem.Click += new System.EventHandler(this.exportAnimatorwithAnimationClipMenuItem_Click);
//
// dumpSelectedAssetsToolStripMenuItem
//
this.dumpSelectedAssetsToolStripMenuItem.Name = "dumpSelectedAssetsToolStripMenuItem";
this.dumpSelectedAssetsToolStripMenuItem.Size = new System.Drawing.Size(303, 22);
this.dumpSelectedAssetsToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.dumpSelectedAssetsToolStripMenuItem.Text = "Dump selected assets";
this.dumpSelectedAssetsToolStripMenuItem.Click += new System.EventHandler(this.dumpSelectedAssetsToolStripMenuItem_Click);
//
// exportAnimatorWithSelectedAnimationClipMenuItem
//
this.exportAnimatorWithSelectedAnimationClipMenuItem.Name = "exportAnimatorWithSelectedAnimationClipMenuItem";
this.exportAnimatorWithSelectedAnimationClipMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportAnimatorWithSelectedAnimationClipMenuItem.Text = "Export Animator + selected AnimationClips";
this.exportAnimatorWithSelectedAnimationClipMenuItem.Visible = false;
this.exportAnimatorWithSelectedAnimationClipMenuItem.Click += new System.EventHandler(this.exportAnimatorWithAnimationClipMenuItem_Click);
//
// exportAsLive2DModelToolStripMenuItem
//
this.exportAsLive2DModelToolStripMenuItem.Name = "exportAsLive2DModelToolStripMenuItem";
this.exportAsLive2DModelToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportAsLive2DModelToolStripMenuItem.Text = "Export as Live2D model(s)";
this.exportAsLive2DModelToolStripMenuItem.Visible = false;
this.exportAsLive2DModelToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2D_Click);
//
// exportL2DWithFadeLstToolStripMenuItem
//
this.exportL2DWithFadeLstToolStripMenuItem.Name = "exportL2DWithFadeLstToolStripMenuItem";
this.exportL2DWithFadeLstToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportL2DWithFadeLstToolStripMenuItem.Text = "Export Live2D model + selected Fade Motion List";
this.exportL2DWithFadeLstToolStripMenuItem.Visible = false;
this.exportL2DWithFadeLstToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithFadeList_Click);
//
// exportL2DWithFadeToolStripMenuItem
//
this.exportL2DWithFadeToolStripMenuItem.Name = "exportL2DWithFadeToolStripMenuItem";
this.exportL2DWithFadeToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportL2DWithFadeToolStripMenuItem.Text = "Export Live2D model + selected Fade motions";
this.exportL2DWithFadeToolStripMenuItem.Visible = false;
this.exportL2DWithFadeToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithFadeMotions_Click);
//
// exportL2DWithClipsToolStripMenuItem
//
this.exportL2DWithClipsToolStripMenuItem.Name = "exportL2DWithClipsToolStripMenuItem";
this.exportL2DWithClipsToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.exportL2DWithClipsToolStripMenuItem.Text = "Export Live2D model + selected AnimationClips";
this.exportL2DWithClipsToolStripMenuItem.Visible = false;
this.exportL2DWithClipsToolStripMenuItem.Click += new System.EventHandler(this.exportSelectedL2DWithClips_Click);
//
// goToSceneHierarchyToolStripMenuItem
//
this.goToSceneHierarchyToolStripMenuItem.Name = "goToSceneHierarchyToolStripMenuItem";
this.goToSceneHierarchyToolStripMenuItem.Size = new System.Drawing.Size(303, 22);
this.goToSceneHierarchyToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.goToSceneHierarchyToolStripMenuItem.Text = "Go to scene hierarchy";
this.goToSceneHierarchyToolStripMenuItem.Visible = false;
this.goToSceneHierarchyToolStripMenuItem.Click += new System.EventHandler(this.goToSceneHierarchyToolStripMenuItem_Click);
@@ -1238,7 +1417,7 @@
// showOriginalFileToolStripMenuItem
//
this.showOriginalFileToolStripMenuItem.Name = "showOriginalFileToolStripMenuItem";
this.showOriginalFileToolStripMenuItem.Size = new System.Drawing.Size(303, 22);
this.showOriginalFileToolStripMenuItem.Size = new System.Drawing.Size(331, 22);
this.showOriginalFileToolStripMenuItem.Text = "Show original file";
this.showOriginalFileToolStripMenuItem.Visible = false;
this.showOriginalFileToolStripMenuItem.Click += new System.EventHandler(this.showOriginalFileToolStripMenuItem_Click);
@@ -1256,6 +1435,7 @@
this.Name = "AssetStudioGUIForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "AssetStudioModGUI";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AssetStudioGUIForm_FormClosing);
this.DragDrop += new System.Windows.Forms.DragEventHandler(this.AssetStudioGUIForm_DragDrop);
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.AssetStudioGUIForm_DragEnter);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AssetStudioForm_KeyDown);
@@ -1275,6 +1455,7 @@
this.progressbarPanel.ResumeLayout(false);
this.tabControl2.ResumeLayout(false);
this.tabPage4.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.previewPanel)).EndInit();
this.previewPanel.ResumeLayout(false);
this.previewPanel.PerformLayout();
this.FMODpanel.ResumeLayout(false);
@@ -1309,7 +1490,7 @@
private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportAllAssetsMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportSelectedAssetsMenuItem;
private System.Windows.Forms.Panel previewPanel;
private System.Windows.Forms.PictureBox previewPanel;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
@@ -1351,7 +1532,7 @@
private OpenTK.GLControl glControl1;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
private System.Windows.Forms.ToolStripMenuItem showOriginalFileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportAnimatorwithselectedAnimationClipMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportAnimatorWithSelectedAnimationClipMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportSelectedAssetsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem filterTypeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem allToolStripMenuItem;
@@ -1401,10 +1582,27 @@
private System.Windows.Forms.ComboBox listSearchHistory;
private System.Windows.Forms.RichTextBox listSearch;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator6;
private System.Windows.Forms.ToolStripMenuItem allLive2DModelsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem showRelatedAssetsToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator7;
private System.Windows.Forms.ListView assetListView;
private System.Windows.Forms.ToolStripMenuItem showConsoleToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem writeLogToFileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem buildTreeStructureToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportL2DWithClipsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportAsLive2DModelToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem live2DCubismModelsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem allL2DModelsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem selectedL2DModelsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem l2DModelWithClipsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem l2DModelWithFadeMotionsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportL2DWithFadeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem l2DModelWithFadeListToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportL2DWithFadeLstToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem customCompressionTypeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem customCompressionZstdToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem customCompressionLZ4ToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem useAssetLoadingViaTypetreeToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator assetLoadingToolStripSeparator;
}
}

View File

@@ -89,6 +89,10 @@ namespace AssetStudioGUI
private AlphanumComparatorFast alphanumComparator = new AlphanumComparatorFast();
#endif
//asset list selection
private List<int> selectedIndicesPrevList = new List<int>();
private List<AssetItem> selectedAnimationAssetsList = new List<AssetItem>();
//asset list filter
private System.Timers.Timer delayTimer;
private bool enableFiltering;
@@ -112,21 +116,33 @@ namespace AssetStudioGUI
[DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);
private string guiTitle = string.Empty;
public AssetStudioGUIForm()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
ConsoleWindow.RunConsole(Properties.Settings.Default.showConsole);
InitializeComponent();
Text = $"{Application.ProductName} v{Application.ProductVersion}";
var appAssembly = typeof(Program).Assembly.GetName();
guiTitle = $"{appAssembly.Name} v{appAssembly.Version}";
Text = guiTitle;
delayTimer = new System.Timers.Timer(800);
delayTimer.Elapsed += new ElapsedEventHandler(delayTimer_Elapsed);
delayTimer.Elapsed += delayTimer_Elapsed;
displayAll.Checked = Properties.Settings.Default.displayAll;
displayInfo.Checked = Properties.Settings.Default.displayInfo;
enablePreview.Checked = Properties.Settings.Default.enablePreview;
showConsoleToolStripMenuItem.Checked = Properties.Settings.Default.showConsole;
buildTreeStructureToolStripMenuItem.Checked = Properties.Settings.Default.buildTreeStructure;
useAssetLoadingViaTypetreeToolStripMenuItem.Checked = Properties.Settings.Default.useTypetreeLoading;
FMODinit();
listSearchFilterMode.SelectedIndex = 0;
logger = new GUILogger(StatusStripUpdate);
Logger.Default = logger;
writeLogToFileToolStripMenuItem.Checked = Properties.Settings.Default.useFileLogger;
Progress.Default = new Progress<int>(SetProgressBarValue);
Studio.StatusStripUpdate = StatusStripUpdate;
}
@@ -135,21 +151,31 @@ namespace AssetStudioGUI
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Move;
e.Effect = DragDropEffects.Copy;
}
}
private async void AssetStudioGUIForm_DragDrop(object sender, DragEventArgs e)
{
var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
if (paths.Length > 0)
if (paths.Length == 0)
return;
ResetForm();
for (var i = 0; i < paths.Length; i++)
{
ResetForm();
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
saveDirectoryBackup = openDirectoryBackup;
BuildAssetStructures();
if (paths[i].ToLower().EndsWith(".lnk"))
{
var targetPath = LnkReader.GetLnkTarget(paths[i]);
if (!string.IsNullOrEmpty(targetPath))
{
paths[i] = targetPath;
}
}
}
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
saveDirectoryBackup = openDirectoryBackup;
BuildAssetStructures();
}
private async void loadFile_Click(object sender, EventArgs e)
@@ -158,7 +184,6 @@ namespace AssetStudioGUI
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
{
ResetForm();
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, openFileDialog1.FileNames));
BuildAssetStructures();
}
@@ -171,12 +196,29 @@ namespace AssetStudioGUI
if (openFolderDialog.ShowDialog(this) == DialogResult.OK)
{
ResetForm();
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, openFolderDialog.Folder));
BuildAssetStructures();
}
}
private void specifyUnityVersion_Close(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(specifyUnityVersion.Text))
{
assetsManager.SpecifyUnityVersion = null;
return;
}
try
{
assetsManager.SpecifyUnityVersion = new UnityVersion(specifyUnityVersion.Text);
}
catch (Exception ex)
{
Logger.Error(ex.Message);
}
}
private async void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
@@ -218,17 +260,11 @@ namespace AssetStudioGUI
return;
}
(var productName, var treeNodeCollection) = await Task.Run(() => BuildAssetData());
var (productName, treeNodeCollection) = await Task.Run(() => BuildAssetData());
var typeMap = await Task.Run(() => BuildClassStructure());
productName = string.IsNullOrEmpty(productName) ? "no productName" : productName;
if (!string.IsNullOrEmpty(productName))
{
Text = $"{Application.ProductName} v{Application.ProductVersion} - {productName} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
}
else
{
Text = $"{Application.ProductName} v{Application.ProductVersion} - no productName - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
}
Text = $"{guiTitle} - {productName} - {assetsManager.assetsFileList[0].unityVersion} - {assetsManager.assetsFileList[0].m_TargetPlatform}";
assetListView.VirtualListSize = visibleAssets.Count;
@@ -266,9 +302,9 @@ namespace AssetStudioGUI
filterTypeToolStripMenuItem.DropDownItems.Add(typeItem);
}
allToolStripMenuItem.Checked = true;
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {assetListView.Items.Count} exportable assets";
var log = $"Finished loading {assetsManager.assetsFileList.Count} file(s) with {assetListView.Items.Count} exportable assets";
var unityVer = assetsManager.assetsFileList[0].version;
var m_ObjectsCount = unityVer[0] > 2020 ?
var m_ObjectsCount = unityVer > 2020 ?
assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y => y.classID != (int)ClassIDType.Shader)) :
assetsManager.assetsFileList.Sum(x => x.m_Objects.Count);
var objectsCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
@@ -329,7 +365,7 @@ namespace AssetStudioGUI
if (e.Control)
{
var need = false;
if (lastSelectedItem?.Type == ClassIDType.Texture2D)
if (lastSelectedItem?.Type == ClassIDType.Texture2D || lastSelectedItem?.Type == ClassIDType.Texture2DArrayImage)
{
switch (e.KeyCode)
{
@@ -421,12 +457,12 @@ namespace AssetStudioGUI
{
if (enablePreview.Checked && imageTexture != null)
{
previewPanel.BackgroundImage = imageTexture.Bitmap;
previewPanel.Image = imageTexture.Bitmap;
}
else
{
previewPanel.BackgroundImage = Properties.Resources.preview;
previewPanel.BackgroundImageLayout = ImageLayout.Center;
previewPanel.Image = Properties.Resources.preview;
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
}
}
break;
@@ -624,7 +660,7 @@ namespace AssetStudioGUI
enableFiltering = false;
listSearch.Text = " Filter ";
listSearch.ForeColor = SystemColors.GrayText;
listSearch.BackColor = System.Drawing.Color.White;
listSearch.BackColor = SystemColors.Window;
}
}
@@ -679,6 +715,8 @@ namespace AssetStudioGUI
sortColumn = e.Column;
assetListView.BeginUpdate();
assetListView.SelectedIndices.Clear();
selectedIndicesPrevList.Clear();
selectedAnimationAssetsList.Clear();
if (sortColumn == 4) //FullSize
{
visibleAssets.Sort((a, b) =>
@@ -721,8 +759,8 @@ namespace AssetStudioGUI
private void selectAsset(object sender, ListViewItemSelectionChangedEventArgs e)
{
previewPanel.BackgroundImage = Properties.Resources.preview;
previewPanel.BackgroundImageLayout = ImageLayout.Center;
previewPanel.Image = Properties.Resources.preview;
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
classTextBox.Visible = false;
assetInfoLabel.Visible = false;
assetInfoLabel.Text = null;
@@ -788,8 +826,12 @@ namespace AssetStudioGUI
switch (assetItem.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Texture2DArrayImage:
PreviewTexture2D(assetItem, assetItem.Asset as Texture2D);
break;
case ClassIDType.Texture2DArray:
PreviewTexture2DArray(assetItem, assetItem.Asset as Texture2DArray);
break;
case ClassIDType.AudioClip:
PreviewAudioClip(assetItem, assetItem.Asset as AudioClip);
break;
@@ -800,7 +842,16 @@ namespace AssetStudioGUI
PreviewTextAsset(assetItem.Asset as TextAsset);
break;
case ClassIDType.MonoBehaviour:
PreviewMonoBehaviour(assetItem.Asset as MonoBehaviour);
var m_MonoBehaviour = (MonoBehaviour)assetItem.Asset;
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
if (m_Script.m_ClassName == "CubismMoc")
{
PreviewMoc(assetItem, m_MonoBehaviour);
break;
}
}
PreviewMonoBehaviour(m_MonoBehaviour);
break;
case ClassIDType.Font:
PreviewFont(assetItem.Asset as Font);
@@ -839,6 +890,16 @@ namespace AssetStudioGUI
}
}
private void PreviewTexture2DArray(AssetItem assetItem, Texture2DArray m_Texture2DArray)
{
assetItem.InfoText =
$"Width: {m_Texture2DArray.m_Width}\n" +
$"Height: {m_Texture2DArray.m_Height}\n" +
$"Graphics format: {m_Texture2DArray.m_Format}\n" +
$"Texture format: {m_Texture2DArray.m_Format.ToTextureFormat()}\n" +
$"Texture count: {m_Texture2DArray.m_Depth}";
}
private void PreviewTexture2D(AssetItem assetItem, Texture2D m_Texture2D)
{
var image = m_Texture2D.ConvertToImage(true);
@@ -849,9 +910,9 @@ namespace AssetStudioGUI
assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}";
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
{
case 0: assetItem.InfoText += "\nFilter Mode: Point "; break;
case 1: assetItem.InfoText += "\nFilter Mode: Bilinear "; break;
case 2: assetItem.InfoText += "\nFilter Mode: Trilinear "; break;
case 0: assetItem.InfoText += "\nFilter mode: Point "; break;
case 1: assetItem.InfoText += "\nFilter mode: Bilinear "; break;
case 2: assetItem.InfoText += "\nFilter mode: Trilinear "; break;
}
assetItem.InfoText += $"\nAnisotropic level: {m_Texture2D.m_TextureSettings.m_Aniso}\nMip map bias: {m_Texture2D.m_TextureSettings.m_MipBias}";
switch (m_Texture2D.m_TextureSettings.m_WrapMode)
@@ -887,6 +948,8 @@ namespace AssetStudioGUI
}
}
}
var switchSwizzled = m_Texture2D.m_PlatformBlob.Length != 0;
assetItem.InfoText += assetItem.Asset.platform == BuildTarget.Switch ? $"\nUses texture swizzling: {switchSwizzled}" : "";
PreviewTexture(bitmap);
StatusStripUpdate("'Ctrl'+'R'/'G'/'B'/'A' for Channel Toggle");
@@ -901,12 +964,12 @@ namespace AssetStudioGUI
{
//Info
assetItem.InfoText = "Compression format: ";
if (m_AudioClip.version[0] < 5)
if (m_AudioClip.version < 5)
{
switch (m_AudioClip.m_Type)
{
case FMODSoundType.ACC:
assetItem.InfoText += "Acc";
case FMODSoundType.AAC:
assetItem.InfoText += "AAC";
break;
case FMODSoundType.AIFF:
assetItem.InfoText += "AIFF";
@@ -989,6 +1052,18 @@ namespace AssetStudioGUI
var m_AudioData = m_AudioClip.m_AudioData.GetData();
if (m_AudioData == null || m_AudioData.Length == 0)
return;
if (!m_AudioClip.IsConvertSupport())
{
assetItem.InfoText +=
$"\nLength: {m_AudioClip.m_Length:.0##}\n" +
$"Channel count: {m_AudioClip.m_Channels}\n" +
$"Sample rate: {m_AudioClip.m_Frequency}\n" +
$"Bit depth: {m_AudioClip.m_BitsPerSample}";
StatusStripUpdate("Preview is not available for non-fmod sounds. Try to export instead.");
return;
}
var exinfo = new FMOD.CREATESOUNDEXINFO();
exinfo.cbsize = Marshal.SizeOf(exinfo);
@@ -1061,6 +1136,27 @@ namespace AssetStudioGUI
PreviewText(str);
}
private void PreviewMoc(AssetItem assetItem, MonoBehaviour m_MonoBehaviour)
{
using (var cubismModel = new CubismModel(m_MonoBehaviour))
{
var sb = new StringBuilder();
sb.AppendLine($"SDK Version: {cubismModel.VersionDescription}");
if (cubismModel.Version > 0)
{
sb.AppendLine($"Canvas Width: {cubismModel.CanvasWidth}");
sb.AppendLine($"Canvas Height: {cubismModel.CanvasHeight}");
sb.AppendLine($"Center X: {cubismModel.CentralPosX}");
sb.AppendLine($"Center Y: {cubismModel.CentralPosY}");
sb.AppendLine($"Pixel Per Unit: {cubismModel.PixelPerUnit}");
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
sb.AppendLine($"Part Count: {cubismModel.PartCount}");
}
assetItem.InfoText = sb.ToString();
}
StatusStripUpdate("Can be exported as Live2D Cubism model.");
}
private void PreviewFont(Font m_Font)
{
if (m_Font.m_FontData != null)
@@ -1286,11 +1382,11 @@ namespace AssetStudioGUI
{
imageTexture?.Dispose();
imageTexture = bitmap;
previewPanel.BackgroundImage = imageTexture.Bitmap;
previewPanel.Image = imageTexture.Bitmap;
if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height)
previewPanel.BackgroundImageLayout = ImageLayout.Zoom;
previewPanel.SizeMode = PictureBoxSizeMode.Zoom;
else
previewPanel.BackgroundImageLayout = ImageLayout.Center;
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
}
private void PreviewText(string text)
@@ -1340,7 +1436,7 @@ namespace AssetStudioGUI
private void ResetForm()
{
Text = $"{Application.ProductName} v{Application.ProductVersion}";
Text = guiTitle;
assetsManager.Clear();
assemblyLoader.Clear();
exportableAssets.Clear();
@@ -1350,10 +1446,13 @@ namespace AssetStudioGUI
assetListView.Items.Clear();
classesListView.Items.Clear();
classesListView.Groups.Clear();
previewPanel.BackgroundImage = Properties.Resources.preview;
selectedAnimationAssetsList.Clear();
selectedIndicesPrevList.Clear();
cubismMocList.Clear();
previewPanel.Image = Properties.Resources.preview;
previewPanel.SizeMode = PictureBoxSizeMode.CenterImage;
imageTexture?.Dispose();
imageTexture = null;
previewPanel.BackgroundImageLayout = ImageLayout.Center;
assetInfoLabel.Visible = false;
assetInfoLabel.Text = null;
textPreviewBox.Visible = false;
@@ -1365,7 +1464,7 @@ namespace AssetStudioGUI
enableFiltering = false;
listSearch.Text = " Filter ";
listSearch.ForeColor = SystemColors.GrayText;
listSearch.BackColor = System.Drawing.Color.White;
listSearch.BackColor = SystemColors.Window;
if (tabControl1.SelectedIndex == 1)
assetListView.Select();
@@ -1393,7 +1492,11 @@ namespace AssetStudioGUI
{
goToSceneHierarchyToolStripMenuItem.Visible = false;
showOriginalFileToolStripMenuItem.Visible = false;
exportAnimatorwithselectedAnimationClipMenuItem.Visible = false;
exportAnimatorWithSelectedAnimationClipMenuItem.Visible = false;
exportAsLive2DModelToolStripMenuItem.Visible = false;
exportL2DWithFadeLstToolStripMenuItem.Visible = false;
exportL2DWithFadeToolStripMenuItem.Visible = false;
exportL2DWithClipsToolStripMenuItem.Visible = false;
if (assetListView.SelectedIndices.Count == 1)
{
@@ -1403,10 +1506,42 @@ namespace AssetStudioGUI
if (assetListView.SelectedIndices.Count >= 1)
{
var selectedAssets = GetSelectedAssets();
if (selectedAssets.Any(x => x.Type == ClassIDType.Animator) && selectedAssets.Any(x => x.Type == ClassIDType.AnimationClip))
var selectedTypes = (SelectedAssetType)0;
foreach (var asset in selectedAssets)
{
exportAnimatorwithselectedAnimationClipMenuItem.Visible = true;
switch (asset.Asset)
{
case MonoBehaviour m_MonoBehaviour:
if (Studio.cubismMocList.Count > 0 && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
if (m_Script.m_ClassName == "CubismMoc")
{
selectedTypes |= SelectedAssetType.MonoBehaviourMoc;
}
else if (m_Script.m_ClassName == "CubismFadeMotionData")
{
selectedTypes |= SelectedAssetType.MonoBehaviourFade;
}
else if (m_Script.m_ClassName == "CubismFadeMotionList")
{
selectedTypes |= SelectedAssetType.MonoBehaviourFadeLst;
}
}
break;
case AnimationClip _:
selectedTypes |= SelectedAssetType.AnimationClip;
break;
case Animator _:
selectedTypes |= SelectedAssetType.Animator;
break;
}
}
exportAnimatorWithSelectedAnimationClipMenuItem.Visible = (selectedTypes & SelectedAssetType.Animator) !=0 && (selectedTypes & SelectedAssetType.AnimationClip) != 0;
exportAsLive2DModelToolStripMenuItem.Visible = (selectedTypes & SelectedAssetType.MonoBehaviourMoc) != 0;
exportL2DWithFadeLstToolStripMenuItem.Visible = (selectedTypes & SelectedAssetType.MonoBehaviourMoc) !=0 && (selectedTypes & SelectedAssetType.MonoBehaviourFadeLst) != 0;
exportL2DWithFadeToolStripMenuItem.Visible = (selectedTypes & SelectedAssetType.MonoBehaviourMoc) != 0 && (selectedTypes & SelectedAssetType.MonoBehaviourFade) !=0;
exportL2DWithClipsToolStripMenuItem.Visible = (selectedTypes & SelectedAssetType.MonoBehaviourMoc) !=0 && (selectedTypes & SelectedAssetType.AnimationClip) != 0;
}
var selectedElement = assetListView.HitTest(new Point(e.X, e.Y));
@@ -1434,16 +1569,15 @@ namespace AssetStudioGUI
private void showOriginalFileToolStripMenuItem_Click(object sender, EventArgs e)
{
var selectasset = (AssetItem)assetListView.Items[assetListView.SelectedIndices[0]];
var args = $"/select, \"{selectasset.SourceFile.originalPath ?? selectasset.SourceFile.fullName}\"";
var selectAsset = (AssetItem)assetListView.Items[assetListView.SelectedIndices[0]];
var args = $"/select, \"{selectAsset.SourceFile.originalPath ?? selectAsset.SourceFile.fullName}\"";
var pfi = new ProcessStartInfo("explorer.exe", args);
Process.Start(pfi);
}
private void exportAnimatorwithAnimationClipMenuItem_Click(object sender, EventArgs e)
private void exportAnimatorWithAnimationClipMenuItem_Click(object sender, EventArgs e)
{
AssetItem animator = null;
List<AssetItem> animationList = new List<AssetItem>();
var selectedAssets = GetSelectedAssets();
foreach (var assetPreloadData in selectedAssets)
{
@@ -1451,10 +1585,6 @@ namespace AssetStudioGUI
{
animator = assetPreloadData;
}
else if (assetPreloadData.Type == ClassIDType.AnimationClip)
{
animationList.Add(assetPreloadData);
}
}
if (animator != null)
@@ -1465,7 +1595,7 @@ namespace AssetStudioGUI
{
saveDirectoryBackup = saveFolderDialog.Folder;
var exportPath = Path.Combine(saveFolderDialog.Folder, "Animator") + Path.DirectorySeparatorChar;
ExportAnimatorWithAnimationClip(animator, animationList, exportPath);
ExportAnimatorWithAnimationClip(animator, selectedAnimationAssetsList, exportPath);
}
}
}
@@ -1475,7 +1605,7 @@ namespace AssetStudioGUI
ExportObjects(false);
}
private void exportObjectswithAnimationClipMenuItem_Click(object sender, EventArgs e)
private void exportObjectsWithAnimationClipMenuItem_Click(object sender, EventArgs e)
{
ExportObjects(true);
}
@@ -1508,12 +1638,12 @@ namespace AssetStudioGUI
}
}
private void exportSelectedObjectsmergeToolStripMenuItem_Click(object sender, EventArgs e)
private void exportSelectedObjectsMergeToolStripMenuItem_Click(object sender, EventArgs e)
{
ExportMergeObjects(false);
}
private void exportSelectedObjectsmergeWithAnimationClipToolStripMenuItem_Click(object sender, EventArgs e)
private void exportSelectedObjectsMergeWithAnimationClipToolStripMenuItem_Click(object sender, EventArgs e)
{
ExportMergeObjects(true);
}
@@ -1556,10 +1686,10 @@ namespace AssetStudioGUI
private void goToSceneHierarchyToolStripMenuItem_Click(object sender, EventArgs e)
{
var selectasset = (AssetItem)assetListView.Items[assetListView.SelectedIndices[0]];
if (selectasset.TreeNode != null)
var selectAsset = (AssetItem)assetListView.Items[assetListView.SelectedIndices[0]];
if (selectAsset.TreeNode != null)
{
sceneTreeView.SelectedNode = selectasset.TreeNode;
sceneTreeView.SelectedNode = selectAsset.TreeNode;
tabControl1.SelectedTab = tabPage1;
}
}
@@ -1624,7 +1754,7 @@ namespace AssetStudioGUI
ExportAssetsList(ExportFilter.Filtered);
}
private void exportAllObjectssplitToolStripMenuItem1_Click(object sender, EventArgs e)
private void exportAllObjectsSplitToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (sceneTreeView.Nodes.Count > 0)
{
@@ -1645,14 +1775,44 @@ namespace AssetStudioGUI
private void assetListView_SelectedIndexChanged(object sender, EventArgs e)
{
if (assetListView.SelectedIndices.Count > 1)
StatusStripUpdate($"Selected {assetListView.SelectedIndices.Count} assets.");
ProcessSelectedItems();
}
private void assetListView_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
{
ProcessSelectedItems();
}
private void ProcessSelectedItems()
{
if (assetListView.SelectedIndices.Count > 1)
{
StatusStripUpdate($"Selected {assetListView.SelectedIndices.Count} assets.");
}
var selectedIndicesList = assetListView.SelectedIndices.Cast<int>().ToList();
var addedIndices = selectedIndicesList.Except(selectedIndicesPrevList).ToArray();
foreach (var itemIndex in addedIndices)
{
selectedIndicesPrevList.Add(itemIndex);
var selectedItem = (AssetItem)assetListView.Items[itemIndex];
if (selectedItem.Type == ClassIDType.AnimationClip)
{
selectedAnimationAssetsList.Add(selectedItem);
}
}
var removedIndices = selectedIndicesPrevList.Except(selectedIndicesList).ToArray();
foreach (var itemIndex in removedIndices)
{
selectedIndicesPrevList.Remove(itemIndex);
var unselectedItem = (AssetItem)assetListView.Items[itemIndex];
if (unselectedItem.Type == ClassIDType.AnimationClip)
{
selectedAnimationAssetsList.Remove(unselectedItem);
}
}
}
private List<AssetItem> GetSelectedAssets()
@@ -1722,16 +1882,16 @@ namespace AssetStudioGUI
{
visibleAssets = visibleAssets.FindAll(x => Regex.IsMatch(x.SubItems[1].Text, pattern, regexOptions));
}
listSearch.BackColor = System.Drawing.Color.PaleGreen;
listSearch.BackColor = SystemInformation.HighContrast ? listSearch.BackColor : System.Drawing.Color.PaleGreen;
}
catch (ArgumentException e)
{
listSearch.BackColor = System.Drawing.Color.FromArgb(255, 160, 160);
listSearch.BackColor = SystemInformation.HighContrast ? listSearch.BackColor : System.Drawing.Color.FromArgb(255, 160, 160);
StatusStripUpdate($"Regex error: {e.Message}");
}
catch (RegexMatchTimeoutException)
{
listSearch.BackColor = System.Drawing.Color.FromArgb(255, 160, 160);
listSearch.BackColor = SystemInformation.HighContrast ? listSearch.BackColor : System.Drawing.Color.FromArgb(255, 160, 160);
StatusStripUpdate($"Timeout error");
}
break;
@@ -1764,6 +1924,19 @@ namespace AssetStudioGUI
toExportAssets = visibleAssets;
break;
}
if (toExportAssets != null && filterTypeToolStripMenuItem.DropDownItems.ContainsKey("Texture2DArray"))
{
var tex2dArrayImgPathIdSet = toExportAssets.FindAll(x => x.Type == ClassIDType.Texture2DArrayImage).Select(x => x.m_PathID).ToHashSet();
foreach (var pathId in tex2dArrayImgPathIdSet)
{
toExportAssets = toExportAssets.Where(x =>
x.Type != ClassIDType.Texture2DArray
|| (x.Type == ClassIDType.Texture2DArray && x.m_PathID != pathId))
.ToList();
}
}
Studio.ExportAssets(saveFolderDialog.Folder, toExportAssets, exportType);
}
}
@@ -1809,7 +1982,7 @@ namespace AssetStudioGUI
private void toolStripMenuItem15_Click(object sender, EventArgs e)
{
logger.ShowErrorMessage = toolStripMenuItem15.Checked;
GUILogger.ShowDebugMessage = toolStripMenuItem15.Checked;
}
private void sceneTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
@@ -1832,7 +2005,7 @@ namespace AssetStudioGUI
private void clearSelectionToolStripMenuItem_Click(object sender, EventArgs e)
{
treeRecursionEnabled = false;
for(var i = 0; i < treeNodeSelectedList.Count; i++)
for (var i = 0; i < treeNodeSelectedList.Count; i++)
{
treeNodeSelectedList[i].Checked = false;
}
@@ -1875,7 +2048,7 @@ namespace AssetStudioGUI
private void listSearchFilterMode_SelectedIndexChanged(object sender, EventArgs e)
{
listSearch.BackColor = System.Drawing.Color.White;
listSearch.BackColor = SystemColors.Window;
if (listSearch.Text != " Filter ")
{
FilterAssetList();
@@ -1889,42 +2062,6 @@ namespace AssetStudioGUI
listSearch.SelectionStart = listSearch.Text.Length;
}
private void allLive2DModelsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (exportableAssets.Count > 0)
{
var cubismMocs = exportableAssets.Where(x =>
{
if (x.Type == ClassIDType.MonoBehaviour)
{
((MonoBehaviour)x.Asset).m_Script.TryGet(out var m_Script);
return m_Script?.m_ClassName == "CubismMoc";
}
return false;
}).Select(x => x.Asset).ToArray();
if (cubismMocs.Length == 0)
{
Logger.Info("Live2D Cubism models were not found.");
return;
}
var saveFolderDialog = new OpenFolderDialog();
saveFolderDialog.InitialFolder = saveDirectoryBackup;
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
timer.Stop();
saveDirectoryBackup = saveFolderDialog.Folder;
Progress.Reset();
BeginInvoke(new Action(() => { progressBar1.Style = ProgressBarStyle.Marquee; }));
Studio.ExportLive2D(cubismMocs, saveFolderDialog.Folder);
}
}
else
{
Logger.Info("No exportable assets loaded");
}
}
private void selectRelatedAsset(object sender, EventArgs e)
{
var selectedItem = (ToolStripMenuItem)sender;
@@ -1996,6 +2133,190 @@ namespace AssetStudioGUI
}
}
private void showConsoleToolStripMenuItem_Click(object sender, EventArgs e)
{
var showConsole = showConsoleToolStripMenuItem.Checked;
if (showConsole)
ConsoleWindow.ShowConsoleWindow();
else
ConsoleWindow.HideConsoleWindow();
Properties.Settings.Default.showConsole = showConsole;
Properties.Settings.Default.Save();
}
private void writeLogToFileToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
var useFileLogger = writeLogToFileToolStripMenuItem.Checked;
logger.UseFileLogger = useFileLogger;
Properties.Settings.Default.useFileLogger = useFileLogger;
Properties.Settings.Default.Save();
}
private void AssetStudioGUIForm_FormClosing(object sender, FormClosingEventArgs e)
{
Logger.Verbose("Closing AssetStudio");
}
private void buildTreeStructureToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.buildTreeStructure = buildTreeStructureToolStripMenuItem.Checked;
Properties.Settings.Default.Save();
}
private void exportAllL2D_Click(object sender, EventArgs e)
{
if (exportableAssets.Count > 0)
{
if (Studio.cubismMocList.Count == 0)
{
Logger.Info("Live2D Cubism models were not found.");
return;
}
Live2DExporter();
}
else
{
Logger.Info("No exportable assets loaded");
}
}
private void exportSelectedL2D_Click(object sender, EventArgs e)
{
ExportSelectedL2DModels(ExportL2DFilter.Selected);
}
private void exportSelectedL2DWithClips_Click(object sender, EventArgs e)
{
ExportSelectedL2DModels(ExportL2DFilter.SelectedWithClips);
}
private void exportSelectedL2DWithFadeMotions_Click(object sender, EventArgs e)
{
ExportSelectedL2DModels(ExportL2DFilter.SelectedWithFade);
}
private void exportSelectedL2DWithFadeList_Click(object sender, EventArgs e)
{
ExportSelectedL2DModels(ExportL2DFilter.SelectedWithFadeList);
}
private void ExportSelectedL2DModels(ExportL2DFilter l2dExportMode)
{
if (exportableAssets.Count == 0)
{
Logger.Info("No exportable assets loaded");
return;
}
if (Studio.cubismMocList.Count == 0)
{
Logger.Info("Live2D Cubism models were not found.");
return;
}
var selectedAssets = GetSelectedAssets();
if (selectedAssets.Count == 0)
return;
MonoBehaviour selectedFadeLst = null;
var selectedMocs = new List<MonoBehaviour>();
var selectedFadeMotions = new List<MonoBehaviour>();
var selectedClips = new List<AnimationClip>();
foreach (var assetItem in selectedAssets)
{
if (assetItem.Asset is MonoBehaviour m_MonoBehaviour && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
if (m_Script.m_ClassName == "CubismMoc")
{
selectedMocs.Add(m_MonoBehaviour);
}
else if (m_Script.m_ClassName == "CubismFadeMotionData")
{
selectedFadeMotions.Add(m_MonoBehaviour);
}
else if (m_Script.m_ClassName == "CubismFadeMotionList")
{
selectedFadeLst = m_MonoBehaviour;
}
}
else if (assetItem.Asset is AnimationClip m_AnimationClip)
{
selectedClips.Add(m_AnimationClip);
}
}
if (selectedMocs.Count == 0)
{
Logger.Info("Live2D Cubism models were not selected.");
return;
}
switch (l2dExportMode)
{
case ExportL2DFilter.Selected:
Live2DExporter(selectedMocs);
break;
case ExportL2DFilter.SelectedWithFadeList:
if (selectedFadeLst == null)
{
Logger.Info("Fade Motion List was not selected.");
return;
}
Live2DExporter(selectedMocs, selFadeLst: selectedFadeLst);
break;
case ExportL2DFilter.SelectedWithFade:
if (selectedFadeMotions.Count == 0)
{
Logger.Info("No Fade motions were selected.");
return;
}
Live2DExporter(selectedMocs, selFadeMotions: selectedFadeMotions);
break;
case ExportL2DFilter.SelectedWithClips:
if (selectedClips.Count == 0)
{
Logger.Info("No AnimationClips were selected.");
return;
}
Live2DExporter(selectedMocs, selectedClips);
break;
}
}
private void Live2DExporter(List<MonoBehaviour> selMocs = null, List<AnimationClip> selClipMotions = null, List<MonoBehaviour> selFadeMotions = null, MonoBehaviour selFadeLst = null)
{
var saveFolderDialog = new OpenFolderDialog();
saveFolderDialog.InitialFolder = saveDirectoryBackup;
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
{
timer.Stop();
saveDirectoryBackup = saveFolderDialog.Folder;
Progress.Reset();
BeginInvoke(new Action(() => { progressBar1.Style = ProgressBarStyle.Marquee; }));
Studio.ExportLive2D(saveFolderDialog.Folder, selMocs, selClipMotions, selFadeMotions, selFadeLst);
}
}
private void customCompressionZstd_CheckedChanged(object sender, EventArgs e)
{
customCompressionLZ4ToolStripMenuItem.Checked = !customCompressionZstdToolStripMenuItem.Checked;
assetsManager.ZstdEnabled = customCompressionZstdToolStripMenuItem.Checked;
}
private void customCompressionLZ4_CheckedChanged(object sender, EventArgs e)
{
customCompressionZstdToolStripMenuItem.Checked = !customCompressionLZ4ToolStripMenuItem.Checked;
assetsManager.ZstdEnabled = customCompressionZstdToolStripMenuItem.Checked;
}
private void useAssetLoadingViaTypetreeToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
var isEnabled = useAssetLoadingViaTypetreeToolStripMenuItem.Checked;
assetsManager.LoadingViaTypeTreeEnabled = isEnabled;
Properties.Settings.Default.useTypetreeLoading = isEnabled;
Properties.Settings.Default.Save();
}
#region FMOD
private void FMODinit()
{
@@ -2008,7 +2329,7 @@ namespace AssetStudioGUI
ERRCHECK(result);
if (version < FMOD.VERSION.number)
{
Logger.Error($"Error! You are using an old version of FMOD {version:X}. This program requires {FMOD.VERSION.number:X}.");
Logger.Error($"Error! You are using an old version of FMOD {version:X}. This program requires {FMOD.VERSION.number:X}.");
Application.Exit();
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Runtime.InteropServices;
using AssetStudio;
namespace AssetStudioGUI
{
internal static class ConsoleWindow
{
private enum CtrlSignalType
{
CTRL_C_EVENT,
CTRL_BREAK_EVENT,
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlSignalType ctrlSignal);
private static EventHandler eventHandler;
private static IntPtr ConsoleWindowHandle;
private static readonly int SW_HIDE = 0;
private static readonly int SW_SHOW = 5;
private static bool CloseEventHandler(CtrlSignalType ctrlSignal)
{
switch (ctrlSignal)
{
case CtrlSignalType.CTRL_C_EVENT:
case CtrlSignalType.CTRL_BREAK_EVENT:
return true;
default:
Logger.Verbose("Closing AssetStudio");
return false;
}
}
public static void RunConsole(bool showConsole)
{
AllocConsole();
ConsoleWindowHandle = GetConsoleWindow();
eventHandler += CloseEventHandler;
SetConsoleCtrlHandler(eventHandler, true);
if (!showConsole)
HideConsoleWindow();
}
public static void ShowConsoleWindow()
{
ShowWindow(ConsoleWindowHandle, SW_SHOW);
}
public static void HideConsoleWindow()
{
ShowWindow(ConsoleWindowHandle, SW_HIDE);
}
}
}

View File

@@ -0,0 +1,164 @@
// Shortcut (.lnk) file reader
// by aelurum
// Based on https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc
using AssetStudio;
using System;
using System.IO;
using System.Text;
namespace AssetStudioGUI
{
public static class LnkReader
{
[Flags]
private enum LnkDataFlags
{
//The LNK file contains a link target identifier
HasTargetIDList = 0x00000001,
//The LNK file contains location information
HasLinkInfo = 0x00000002,
}
[Flags]
private enum LnkLocFlags
{
//The linked file is on a volume
//If set the volume information and the local path contain data
VolumeIDAndLocalBasePath = 0x0001,
//The linked file is on a network share
//If set the network share information and common path contain data
CommonNetworkRelativeLinkAndPathSuffix = 0x0002
}
[Flags]
private enum PathTypeFlags
{
IsUnicodeLocalPath = 0x01,
IsUnicodeNetShareName = 0x02,
IsUnicodeCommonPath = 0x04
}
public static string GetLnkTarget(string filePath)
{
var targetPath = string.Empty;
var pathType = (PathTypeFlags)0;
Encoding sysEncoding;
try
{
sysEncoding = GetSysEncoding();
Logger.Debug($"System default text encoding: {sysEncoding.CodePage}");
}
catch (Exception ex)
{
Logger.Error("Text encoding error", ex);
return null;
}
using (var reader = new FileReader(filePath))
{
reader.Endian = EndianType.LittleEndian;
var headerSize = reader.ReadUInt32(); //76 bytes
reader.Position = 20; //skip LNK class identifier (GUID)
var dataFlags = (LnkDataFlags)reader.ReadUInt32();
if ((dataFlags & LnkDataFlags.HasLinkInfo) == 0)
{
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
return null;
}
reader.Position = headerSize;
//Skip the shell item ID list
if ((dataFlags & LnkDataFlags.HasTargetIDList) != 0)
{
var itemIDListSize = reader.ReadUInt16();
reader.Position += itemIDListSize;
}
//The offsets is relative to the start of the location information block
var locInfoPos = reader.Position;
var locInfoFullSize = reader.ReadUInt32();
if (locInfoFullSize == 0)
{
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
return null;
}
var locInfoHeaderSize = reader.ReadUInt32();
var locFlags = (LnkLocFlags)reader.ReadUInt32();
//Offset to the volume information block
var offsetVolumeInfo = reader.ReadUInt32();
//Offset to the ANSI local path
var offsetLocalPath = reader.ReadUInt32();
//Offset to the network share information block
var offsetNetInfo = reader.ReadUInt32();
//Offset to the ANSI common path. 0 if not available
var offsetCommonPath = reader.ReadUInt32();
if (locInfoHeaderSize > 28)
{
//Offset to the Unicode local path
offsetLocalPath = reader.ReadUInt32();
pathType |= PathTypeFlags.IsUnicodeLocalPath;
}
if (locInfoHeaderSize > 32)
{
//Offset to the Unicode common path
offsetCommonPath = reader.ReadUInt32();
pathType |= PathTypeFlags.IsUnicodeCommonPath;
}
//Read local path, if exist
if (offsetLocalPath > 0)
{
reader.Position = locInfoPos + offsetLocalPath;
targetPath = (pathType & PathTypeFlags.IsUnicodeLocalPath) != 0
? reader.ReadStringToNull(encoding: Encoding.Unicode)
: reader.ReadStringToNull(encoding: sysEncoding);
}
//Read network path, if exist
if (locFlags == LnkLocFlags.CommonNetworkRelativeLinkAndPathSuffix)
{
reader.Position = locInfoPos + offsetNetInfo;
var netInfoSize = reader.ReadUInt32();
var netInfoFlags = reader.ReadUInt32();
//Offset to the ANSI network share name. The offset is relative to the start of the network share information block
var offsetNetShareName = reader.ReadUInt32();
if (offsetNetShareName > 20)
{
reader.Position = locInfoPos + offsetNetInfo + 20;
//Offset to the Unicode network share name
offsetNetShareName = reader.ReadUInt32();
pathType |= PathTypeFlags.IsUnicodeNetShareName;
}
if (offsetNetShareName > 0)
{
reader.Position = locInfoPos + offsetNetInfo + offsetNetShareName;
targetPath = (pathType & PathTypeFlags.IsUnicodeNetShareName) != 0
? reader.ReadStringToNull(encoding: Encoding.Unicode)
: reader.ReadStringToNull(encoding: sysEncoding);
}
}
//Read common path, if exist
if (offsetCommonPath > 0)
{
reader.Position = locInfoPos + offsetCommonPath;
var commonPath = (pathType & PathTypeFlags.IsUnicodeCommonPath) != 0
? reader.ReadStringToNull(encoding: Encoding.Unicode)
: reader.ReadStringToNull(encoding: sysEncoding);
targetPath = Path.Combine(targetPath, commonPath);
}
}
return targetPath;
}
private static Encoding GetSysEncoding()
{
#if !NETFRAMEWORK
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
return Encoding.GetEncoding(0);
}
}
}

View File

@@ -43,6 +43,6 @@ namespace AssetStudioGUI
public Bitmap Bitmap => m_bitmap;
private Bitmap m_bitmap;
private readonly GCHandle m_handle;
private GCHandle m_handle;
}
}

View File

@@ -32,6 +32,8 @@
this.OKbutton = new System.Windows.Forms.Button();
this.Cancel = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.filenameFormatLabel = new System.Windows.Forms.Label();
this.filenameFormatComboBox = new System.Windows.Forms.ComboBox();
this.exportSpriteWithAlphaMask = new System.Windows.Forms.CheckBox();
this.openAfterExport = new System.Windows.Forms.CheckBox();
this.restoreExtensionName = new System.Windows.Forms.CheckBox();
@@ -45,6 +47,12 @@
this.topng = new System.Windows.Forms.RadioButton();
this.tobmp = new System.Windows.Forms.RadioButton();
this.converttexture = new System.Windows.Forms.CheckBox();
this.l2dGroupBox = new System.Windows.Forms.GroupBox();
this.l2dMotionExportMethodPanel = new System.Windows.Forms.Panel();
this.l2dMonoBehaviourRadioButton = new System.Windows.Forms.RadioButton();
this.l2dAnimationClipRadioButton = new System.Windows.Forms.RadioButton();
this.l2dMotionExportMethodLabel = new System.Windows.Forms.Label();
this.l2dForceBezierCheckBox = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.exportAllUvsAsDiffuseMaps = new System.Windows.Forms.CheckBox();
this.exportBlendShape = new System.Windows.Forms.CheckBox();
@@ -63,13 +71,19 @@
this.castToBone = new System.Windows.Forms.CheckBox();
this.exportAllNodes = new System.Windows.Forms.CheckBox();
this.eulerFilter = new System.Windows.Forms.CheckBox();
this.exportUvsTooltip = new System.Windows.Forms.ToolTip(this.components);
this.optionTooltip = new System.Windows.Forms.ToolTip(this.components);
this.parallelExportUpDown = new System.Windows.Forms.NumericUpDown();
this.parallelExportCheckBox = new System.Windows.Forms.CheckBox();
this.parallelExportMaxLabel = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
this.l2dGroupBox.SuspendLayout();
this.l2dMotionExportMethodPanel.SuspendLayout();
this.groupBox2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.boneSize)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.parallelExportUpDown)).BeginInit();
this.SuspendLayout();
//
// OKbutton
@@ -77,7 +91,7 @@
this.OKbutton.Location = new System.Drawing.Point(381, 380);
this.OKbutton.Name = "OKbutton";
this.OKbutton.Size = new System.Drawing.Size(75, 23);
this.OKbutton.TabIndex = 6;
this.OKbutton.TabIndex = 4;
this.OKbutton.Text = "OK";
this.OKbutton.UseVisualStyleBackColor = true;
this.OKbutton.Click += new System.EventHandler(this.OKbutton_Click);
@@ -88,7 +102,7 @@
this.Cancel.Location = new System.Drawing.Point(462, 380);
this.Cancel.Name = "Cancel";
this.Cancel.Size = new System.Drawing.Size(75, 23);
this.Cancel.TabIndex = 7;
this.Cancel.TabIndex = 5;
this.Cancel.Text = "Cancel";
this.Cancel.UseVisualStyleBackColor = true;
this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
@@ -96,6 +110,11 @@
// groupBox1
//
this.groupBox1.AutoSize = true;
this.groupBox1.Controls.Add(this.parallelExportMaxLabel);
this.groupBox1.Controls.Add(this.parallelExportCheckBox);
this.groupBox1.Controls.Add(this.parallelExportUpDown);
this.groupBox1.Controls.Add(this.filenameFormatLabel);
this.groupBox1.Controls.Add(this.filenameFormatComboBox);
this.groupBox1.Controls.Add(this.exportSpriteWithAlphaMask);
this.groupBox1.Controls.Add(this.openAfterExport);
this.groupBox1.Controls.Add(this.restoreExtensionName);
@@ -106,11 +125,33 @@
this.groupBox1.Controls.Add(this.converttexture);
this.groupBox1.Location = new System.Drawing.Point(12, 13);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(301, 362);
this.groupBox1.TabIndex = 9;
this.groupBox1.Size = new System.Drawing.Size(301, 272);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Export";
//
// filenameFormatLabel
//
this.filenameFormatLabel.AutoSize = true;
this.filenameFormatLabel.Location = new System.Drawing.Point(177, 18);
this.filenameFormatLabel.Name = "filenameFormatLabel";
this.filenameFormatLabel.Size = new System.Drawing.Size(84, 13);
this.filenameFormatLabel.TabIndex = 10;
this.filenameFormatLabel.Text = "File name format";
//
// filenameFormatComboBox
//
this.filenameFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.filenameFormatComboBox.FormattingEnabled = true;
this.filenameFormatComboBox.Items.AddRange(new object[] {
"assetName",
"assetName@pathID",
"pathID"});
this.filenameFormatComboBox.Location = new System.Drawing.Point(177, 35);
this.filenameFormatComboBox.Name = "filenameFormatComboBox";
this.filenameFormatComboBox.Size = new System.Drawing.Size(118, 21);
this.filenameFormatComboBox.TabIndex = 9;
//
// exportSpriteWithAlphaMask
//
this.exportSpriteWithAlphaMask.AutoSize = true;
@@ -119,7 +160,7 @@
this.exportSpriteWithAlphaMask.Location = new System.Drawing.Point(6, 150);
this.exportSpriteWithAlphaMask.Name = "exportSpriteWithAlphaMask";
this.exportSpriteWithAlphaMask.Size = new System.Drawing.Size(205, 17);
this.exportSpriteWithAlphaMask.TabIndex = 11;
this.exportSpriteWithAlphaMask.TabIndex = 6;
this.exportSpriteWithAlphaMask.Text = "Export sprites with alpha mask applied";
this.exportSpriteWithAlphaMask.UseVisualStyleBackColor = true;
//
@@ -131,7 +172,7 @@
this.openAfterExport.Location = new System.Drawing.Point(6, 196);
this.openAfterExport.Name = "openAfterExport";
this.openAfterExport.Size = new System.Drawing.Size(137, 17);
this.openAfterExport.TabIndex = 10;
this.openAfterExport.TabIndex = 8;
this.openAfterExport.Text = "Open folder after export";
this.openAfterExport.UseVisualStyleBackColor = true;
//
@@ -143,9 +184,9 @@
this.restoreExtensionName.Location = new System.Drawing.Point(6, 63);
this.restoreExtensionName.Name = "restoreExtensionName";
this.restoreExtensionName.Size = new System.Drawing.Size(275, 17);
this.restoreExtensionName.TabIndex = 9;
this.restoreExtensionName.TabIndex = 3;
this.restoreExtensionName.Text = "Try to restore/Use original TextAsset extension name";
this.exportUvsTooltip.SetToolTip(this.restoreExtensionName, "If not checked, AssetStudio will export all TextAssets with the \".txt\" extension");
this.optionTooltip.SetToolTip(this.restoreExtensionName, "If not checked, AssetStudio will export all TextAssets with the \".txt\" extension");
this.restoreExtensionName.UseVisualStyleBackColor = true;
//
// assetGroupOptions
@@ -157,11 +198,12 @@
"container path",
"container path full (with name)",
"source file name",
"scene hierarchy",
"do not group"});
this.assetGroupOptions.Location = new System.Drawing.Point(6, 35);
this.assetGroupOptions.Name = "assetGroupOptions";
this.assetGroupOptions.Size = new System.Drawing.Size(165, 21);
this.assetGroupOptions.TabIndex = 8;
this.assetGroupOptions.TabIndex = 2;
//
// label6
//
@@ -169,7 +211,7 @@
this.label6.Location = new System.Drawing.Point(6, 18);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(127, 13);
this.label6.TabIndex = 7;
this.label6.TabIndex = 1;
this.label6.Text = "Group exported assets by";
//
// convertAudio
@@ -179,9 +221,9 @@
this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
this.convertAudio.Location = new System.Drawing.Point(6, 173);
this.convertAudio.Name = "convertAudio";
this.convertAudio.Size = new System.Drawing.Size(179, 17);
this.convertAudio.TabIndex = 6;
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
this.convertAudio.Size = new System.Drawing.Size(213, 17);
this.convertAudio.TabIndex = 7;
this.convertAudio.Text = "Convert FMOD AudioClip to WAV(PCM)";
this.convertAudio.UseVisualStyleBackColor = true;
//
// panel1
@@ -202,8 +244,7 @@
this.towebp.Location = new System.Drawing.Point(201, 7);
this.towebp.Name = "towebp";
this.towebp.Size = new System.Drawing.Size(54, 17);
this.towebp.TabIndex = 5;
this.towebp.TabStop = true;
this.towebp.TabIndex = 4;
this.towebp.Text = "Webp";
this.towebp.UseVisualStyleBackColor = true;
//
@@ -213,7 +254,7 @@
this.totga.Location = new System.Drawing.Point(150, 7);
this.totga.Name = "totga";
this.totga.Size = new System.Drawing.Size(44, 17);
this.totga.TabIndex = 2;
this.totga.TabIndex = 3;
this.totga.Text = "Tga";
this.totga.UseVisualStyleBackColor = true;
//
@@ -223,7 +264,7 @@
this.tojpg.Location = new System.Drawing.Point(97, 7);
this.tojpg.Name = "tojpg";
this.tojpg.Size = new System.Drawing.Size(48, 17);
this.tojpg.TabIndex = 4;
this.tojpg.TabIndex = 2;
this.tojpg.Text = "Jpeg";
this.tojpg.UseVisualStyleBackColor = true;
//
@@ -234,7 +275,7 @@
this.topng.Location = new System.Drawing.Point(50, 7);
this.topng.Name = "topng";
this.topng.Size = new System.Drawing.Size(44, 17);
this.topng.TabIndex = 3;
this.topng.TabIndex = 1;
this.topng.TabStop = true;
this.topng.Text = "Png";
this.topng.UseVisualStyleBackColor = true;
@@ -245,7 +286,7 @@
this.tobmp.Location = new System.Drawing.Point(3, 7);
this.tobmp.Name = "tobmp";
this.tobmp.Size = new System.Drawing.Size(46, 17);
this.tobmp.TabIndex = 2;
this.tobmp.TabIndex = 0;
this.tobmp.Text = "Bmp";
this.tobmp.UseVisualStyleBackColor = true;
//
@@ -257,10 +298,76 @@
this.converttexture.Location = new System.Drawing.Point(6, 87);
this.converttexture.Name = "converttexture";
this.converttexture.Size = new System.Drawing.Size(116, 17);
this.converttexture.TabIndex = 1;
this.converttexture.TabIndex = 4;
this.converttexture.Text = "Convert Texture2D";
this.converttexture.UseVisualStyleBackColor = true;
//
// l2dGroupBox
//
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodPanel);
this.l2dGroupBox.Controls.Add(this.l2dMotionExportMethodLabel);
this.l2dGroupBox.Controls.Add(this.l2dForceBezierCheckBox);
this.l2dGroupBox.Location = new System.Drawing.Point(12, 275);
this.l2dGroupBox.Name = "l2dGroupBox";
this.l2dGroupBox.Size = new System.Drawing.Size(301, 100);
this.l2dGroupBox.TabIndex = 2;
this.l2dGroupBox.TabStop = false;
this.l2dGroupBox.Text = "Cubism Live2D";
//
// l2dMotionExportMethodPanel
//
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dMonoBehaviourRadioButton);
this.l2dMotionExportMethodPanel.Controls.Add(this.l2dAnimationClipRadioButton);
this.l2dMotionExportMethodPanel.Location = new System.Drawing.Point(18, 40);
this.l2dMotionExportMethodPanel.Name = "l2dMotionExportMethodPanel";
this.l2dMotionExportMethodPanel.Size = new System.Drawing.Size(263, 27);
this.l2dMotionExportMethodPanel.TabIndex = 2;
//
// l2dMonoBehaviourRadioButton
//
this.l2dMonoBehaviourRadioButton.AccessibleName = "MonoBehaviour";
this.l2dMonoBehaviourRadioButton.AutoSize = true;
this.l2dMonoBehaviourRadioButton.Checked = true;
this.l2dMonoBehaviourRadioButton.Location = new System.Drawing.Point(3, 5);
this.l2dMonoBehaviourRadioButton.Name = "l2dMonoBehaviourRadioButton";
this.l2dMonoBehaviourRadioButton.Size = new System.Drawing.Size(167, 17);
this.l2dMonoBehaviourRadioButton.TabIndex = 0;
this.l2dMonoBehaviourRadioButton.TabStop = true;
this.l2dMonoBehaviourRadioButton.Text = "MonoBehaviour (Fade motion)";
this.optionTooltip.SetToolTip(this.l2dMonoBehaviourRadioButton, "If no Fade motions are found, the AnimationClip method will be used");
this.l2dMonoBehaviourRadioButton.UseVisualStyleBackColor = true;
//
// l2dAnimationClipRadioButton
//
this.l2dAnimationClipRadioButton.AccessibleName = "AnimationClipV2";
this.l2dAnimationClipRadioButton.AutoSize = true;
this.l2dAnimationClipRadioButton.Location = new System.Drawing.Point(172, 5);
this.l2dAnimationClipRadioButton.Name = "l2dAnimationClipRadioButton";
this.l2dAnimationClipRadioButton.Size = new System.Drawing.Size(88, 17);
this.l2dAnimationClipRadioButton.TabIndex = 1;
this.l2dAnimationClipRadioButton.Text = "AnimationClip";
this.l2dAnimationClipRadioButton.UseVisualStyleBackColor = true;
//
// l2dMotionExportMethodLabel
//
this.l2dMotionExportMethodLabel.AutoSize = true;
this.l2dMotionExportMethodLabel.Location = new System.Drawing.Point(6, 21);
this.l2dMotionExportMethodLabel.Name = "l2dMotionExportMethodLabel";
this.l2dMotionExportMethodLabel.Size = new System.Drawing.Size(109, 13);
this.l2dMotionExportMethodLabel.TabIndex = 1;
this.l2dMotionExportMethodLabel.Text = "Motion export method";
//
// l2dForceBezierCheckBox
//
this.l2dForceBezierCheckBox.AutoSize = true;
this.l2dForceBezierCheckBox.Location = new System.Drawing.Point(6, 77);
this.l2dForceBezierCheckBox.Name = "l2dForceBezierCheckBox";
this.l2dForceBezierCheckBox.Size = new System.Drawing.Size(278, 17);
this.l2dForceBezierCheckBox.TabIndex = 3;
this.l2dForceBezierCheckBox.Text = "Calculate Linear motion segments as Bezier segments";
this.optionTooltip.SetToolTip(this.l2dForceBezierCheckBox, "May help if the exported motions look jerky/not smooth enough");
this.l2dForceBezierCheckBox.UseVisualStyleBackColor = true;
//
// groupBox2
//
this.groupBox2.AutoSize = true;
@@ -284,7 +391,7 @@
this.groupBox2.Location = new System.Drawing.Point(313, 13);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(224, 362);
this.groupBox2.TabIndex = 11;
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Fbx";
//
@@ -295,9 +402,9 @@
this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 185);
this.exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(168, 17);
this.exportAllUvsAsDiffuseMaps.TabIndex = 23;
this.exportAllUvsAsDiffuseMaps.TabIndex = 9;
this.exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
this.exportUvsTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
this.optionTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
"map.");
this.exportAllUvsAsDiffuseMaps.UseVisualStyleBackColor = true;
//
@@ -309,7 +416,7 @@
this.exportBlendShape.Location = new System.Drawing.Point(6, 138);
this.exportBlendShape.Name = "exportBlendShape";
this.exportBlendShape.Size = new System.Drawing.Size(114, 17);
this.exportBlendShape.TabIndex = 22;
this.exportBlendShape.TabIndex = 7;
this.exportBlendShape.Text = "Export blendshape";
this.exportBlendShape.UseVisualStyleBackColor = true;
//
@@ -321,7 +428,7 @@
this.exportAnimations.Location = new System.Drawing.Point(6, 114);
this.exportAnimations.Name = "exportAnimations";
this.exportAnimations.Size = new System.Drawing.Size(109, 17);
this.exportAnimations.TabIndex = 21;
this.exportAnimations.TabIndex = 6;
this.exportAnimations.Text = "Export animations";
this.exportAnimations.UseVisualStyleBackColor = true;
//
@@ -336,7 +443,7 @@
this.scaleFactor.Location = new System.Drawing.Point(83, 243);
this.scaleFactor.Name = "scaleFactor";
this.scaleFactor.Size = new System.Drawing.Size(60, 20);
this.scaleFactor.TabIndex = 20;
this.scaleFactor.TabIndex = 13;
this.scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.scaleFactor.Value = new decimal(new int[] {
1,
@@ -350,7 +457,7 @@
this.label5.Location = new System.Drawing.Point(6, 245);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(64, 13);
this.label5.TabIndex = 19;
this.label5.TabIndex = 12;
this.label5.Text = "ScaleFactor";
//
// fbxFormat
@@ -363,7 +470,7 @@
this.fbxFormat.Location = new System.Drawing.Point(77, 275);
this.fbxFormat.Name = "fbxFormat";
this.fbxFormat.Size = new System.Drawing.Size(61, 21);
this.fbxFormat.TabIndex = 18;
this.fbxFormat.TabIndex = 15;
//
// label4
//
@@ -371,7 +478,7 @@
this.label4.Location = new System.Drawing.Point(6, 280);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(59, 13);
this.label4.TabIndex = 17;
this.label4.TabIndex = 14;
this.label4.Text = "FBXFormat";
//
// fbxVersion
@@ -388,7 +495,7 @@
this.fbxVersion.Location = new System.Drawing.Point(77, 308);
this.fbxVersion.Name = "fbxVersion";
this.fbxVersion.Size = new System.Drawing.Size(47, 21);
this.fbxVersion.TabIndex = 16;
this.fbxVersion.TabIndex = 17;
//
// label3
//
@@ -396,7 +503,7 @@
this.label3.Location = new System.Drawing.Point(6, 311);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(62, 13);
this.label3.TabIndex = 15;
this.label3.TabIndex = 16;
this.label3.Text = "FBXVersion";
//
// boneSize
@@ -428,7 +535,7 @@
this.exportSkins.Location = new System.Drawing.Point(6, 90);
this.exportSkins.Name = "exportSkins";
this.exportSkins.Size = new System.Drawing.Size(83, 17);
this.exportSkins.TabIndex = 8;
this.exportSkins.TabIndex = 5;
this.exportSkins.Text = "Export skins";
this.exportSkins.UseVisualStyleBackColor = true;
//
@@ -438,7 +545,7 @@
this.label1.Location = new System.Drawing.Point(26, 42);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(72, 13);
this.label1.TabIndex = 7;
this.label1.TabIndex = 2;
this.label1.Text = "FilterPrecision";
//
// filterPrecision
@@ -452,7 +559,7 @@
this.filterPrecision.Location = new System.Drawing.Point(127, 40);
this.filterPrecision.Name = "filterPrecision";
this.filterPrecision.Size = new System.Drawing.Size(51, 20);
this.filterPrecision.TabIndex = 6;
this.filterPrecision.TabIndex = 3;
this.filterPrecision.Value = new decimal(new int[] {
25,
0,
@@ -465,7 +572,7 @@
this.castToBone.Location = new System.Drawing.Point(6, 161);
this.castToBone.Name = "castToBone";
this.castToBone.Size = new System.Drawing.Size(131, 17);
this.castToBone.TabIndex = 5;
this.castToBone.TabIndex = 8;
this.castToBone.Text = "All nodes cast to bone";
this.castToBone.UseVisualStyleBackColor = true;
//
@@ -489,10 +596,57 @@
this.eulerFilter.Location = new System.Drawing.Point(6, 22);
this.eulerFilter.Name = "eulerFilter";
this.eulerFilter.Size = new System.Drawing.Size(72, 17);
this.eulerFilter.TabIndex = 3;
this.eulerFilter.TabIndex = 1;
this.eulerFilter.Text = "EulerFilter";
this.eulerFilter.UseVisualStyleBackColor = true;
//
// parallelExportUpDown
//
this.parallelExportUpDown.Location = new System.Drawing.Point(209, 218);
this.parallelExportUpDown.Maximum = new decimal(new int[] {
8,
0,
0,
0});
this.parallelExportUpDown.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.parallelExportUpDown.Name = "parallelExportUpDown";
this.parallelExportUpDown.Size = new System.Drawing.Size(42, 20);
this.parallelExportUpDown.TabIndex = 13;
this.parallelExportUpDown.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// parallelExportCheckBox
//
this.parallelExportCheckBox.AutoSize = true;
this.parallelExportCheckBox.Checked = true;
this.parallelExportCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.parallelExportCheckBox.Location = new System.Drawing.Point(6, 219);
this.parallelExportCheckBox.Name = "parallelExportCheckBox";
this.parallelExportCheckBox.Size = new System.Drawing.Size(203, 17);
this.parallelExportCheckBox.TabIndex = 15;
this.parallelExportCheckBox.Text = "Export in parallel with number of tasks";
this.optionTooltip.SetToolTip(this.parallelExportCheckBox, "*Requires slightly more RAM than in single-task mode");
this.parallelExportCheckBox.UseVisualStyleBackColor = true;
this.parallelExportCheckBox.CheckedChanged += new System.EventHandler(this.parallelExportCheckBox_CheckedChanged);
//
// parallelExportMaxLabel
//
this.parallelExportMaxLabel.AutoSize = true;
this.parallelExportMaxLabel.ForeColor = System.Drawing.SystemColors.ControlDark;
this.parallelExportMaxLabel.Location = new System.Drawing.Point(256, 221);
this.parallelExportMaxLabel.Name = "parallelExportMaxLabel";
this.parallelExportMaxLabel.Size = new System.Drawing.Size(33, 13);
this.parallelExportMaxLabel.TabIndex = 16;
this.parallelExportMaxLabel.Text = "Max: ";
this.optionTooltip.SetToolTip(this.parallelExportMaxLabel, "*The maximum number matches the number of CPU cores");
//
// ExportOptions
//
this.AcceptButton = this.OKbutton;
@@ -500,6 +654,7 @@
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.Cancel;
this.ClientSize = new System.Drawing.Size(549, 416);
this.Controls.Add(this.l2dGroupBox);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.Cancel);
@@ -516,11 +671,16 @@
this.groupBox1.PerformLayout();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.l2dGroupBox.ResumeLayout(false);
this.l2dGroupBox.PerformLayout();
this.l2dMotionExportMethodPanel.ResumeLayout(false);
this.l2dMotionExportMethodPanel.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.boneSize)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.parallelExportUpDown)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@@ -559,8 +719,19 @@
private System.Windows.Forms.CheckBox restoreExtensionName;
private System.Windows.Forms.CheckBox openAfterExport;
private System.Windows.Forms.CheckBox exportAllUvsAsDiffuseMaps;
private System.Windows.Forms.ToolTip exportUvsTooltip;
private System.Windows.Forms.ToolTip optionTooltip;
private System.Windows.Forms.CheckBox exportSpriteWithAlphaMask;
private System.Windows.Forms.RadioButton towebp;
private System.Windows.Forms.GroupBox l2dGroupBox;
private System.Windows.Forms.CheckBox l2dForceBezierCheckBox;
private System.Windows.Forms.Label l2dMotionExportMethodLabel;
private System.Windows.Forms.RadioButton l2dAnimationClipRadioButton;
private System.Windows.Forms.RadioButton l2dMonoBehaviourRadioButton;
private System.Windows.Forms.Panel l2dMotionExportMethodPanel;
private System.Windows.Forms.ComboBox filenameFormatComboBox;
private System.Windows.Forms.Label filenameFormatLabel;
private System.Windows.Forms.NumericUpDown parallelExportUpDown;
private System.Windows.Forms.CheckBox parallelExportCheckBox;
private System.Windows.Forms.Label parallelExportMaxLabel;
}
}

View File

@@ -1,5 +1,6 @@
using AssetStudio;
using System;
using System.Linq;
using System.Windows.Forms;
namespace AssetStudioGUI
@@ -14,15 +15,8 @@ namespace AssetStudioGUI
converttexture.Checked = Properties.Settings.Default.convertTexture;
exportSpriteWithAlphaMask.Checked = Properties.Settings.Default.exportSpriteWithMask;
convertAudio.Checked = Properties.Settings.Default.convertAudio;
var str = Properties.Settings.Default.convertType.ToString();
foreach (Control c in panel1.Controls)
{
if (c.Text == str)
{
((RadioButton)c).Checked = true;
break;
}
}
var defaultImageType = Properties.Settings.Default.convertType.ToString();
((RadioButton)panel1.Controls.Cast<Control>().First(x => x.Text == defaultImageType)).Checked = true;
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
@@ -36,7 +30,16 @@ namespace AssetStudioGUI
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
var defaultMotionMode = Properties.Settings.Default.l2dMotionMode.ToString();
((RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => x.AccessibleName == defaultMotionMode)).Checked = true;
l2dForceBezierCheckBox.Checked = Properties.Settings.Default.l2dForceBezier;
filenameFormatComboBox.SelectedIndex = Properties.Settings.Default.filenameFormat;
var maxParallelTasks = Environment.ProcessorCount;
var taskCount = Properties.Settings.Default.parallelExportCount;
parallelExportUpDown.Maximum = maxParallelTasks;
parallelExportUpDown.Value = taskCount <= 0 ? maxParallelTasks : Math.Min(taskCount, maxParallelTasks);
parallelExportMaxLabel.Text += maxParallelTasks;
parallelExportCheckBox.Checked = Properties.Settings.Default.parallelExport;
}
private void OKbutton_Click(object sender, EventArgs e)
@@ -46,14 +49,8 @@ namespace AssetStudioGUI
Properties.Settings.Default.convertTexture = converttexture.Checked;
Properties.Settings.Default.exportSpriteWithMask = exportSpriteWithAlphaMask.Checked;
Properties.Settings.Default.convertAudio = convertAudio.Checked;
foreach (Control c in panel1.Controls)
{
if (((RadioButton)c).Checked)
{
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), c.Text);
break;
}
}
var checkedImageType = (RadioButton)panel1.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), checkedImageType.Text);
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
Properties.Settings.Default.eulerFilter = eulerFilter.Checked;
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
@@ -67,6 +64,12 @@ namespace AssetStudioGUI
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
var checkedMotionMode = (RadioButton)l2dMotionExportMethodPanel.Controls.Cast<Control>().First(x => ((RadioButton)x).Checked);
Properties.Settings.Default.l2dMotionMode = (CubismLive2DExtractor.Live2DMotionMode)Enum.Parse(typeof(CubismLive2DExtractor.Live2DMotionMode), checkedMotionMode.AccessibleName);
Properties.Settings.Default.l2dForceBezier = l2dForceBezierCheckBox.Checked;
Properties.Settings.Default.filenameFormat = filenameFormatComboBox.SelectedIndex;
Properties.Settings.Default.parallelExport = parallelExportCheckBox.Checked;
Properties.Settings.Default.parallelExportCount = (int)parallelExportUpDown.Value;
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
Close();
@@ -77,5 +80,10 @@ namespace AssetStudioGUI
DialogResult = DialogResult.Cancel;
Close();
}
private void parallelExportCheckBox_CheckedChanged(object sender, EventArgs e)
{
parallelExportUpDown.Enabled = parallelExportCheckBox.Checked;
}
}
}

View File

@@ -117,7 +117,13 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="optionTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@@ -9,60 +9,6 @@ namespace AssetStudioGUI
{
internal static class Exporter
{
public static bool ExportTexture2D(AssetItem item, string exportPath)
{
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
{
var type = Properties.Settings.Default.convertType;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = m_Texture2D.ConvertToImage(true);
if (image == null)
return false;
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
return true;
}
}
else
{
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
return true;
}
}
public static bool ExportAudioClip(AssetItem item, string exportPath)
{
var m_AudioClip = (AudioClip)item.Asset;
var m_AudioData = m_AudioClip.m_AudioData.GetData();
if (m_AudioData == null || m_AudioData.Length == 0)
return false;
var converter = new AudioClipConverter(m_AudioClip);
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
{
if (!TryExportFile(exportPath, item, ".wav", out var exportFullPath))
return false;
var buffer = converter.ConvertToWav(m_AudioData);
if (buffer == null)
return false;
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_AudioData);
}
return true;
}
public static bool ExportShader(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
@@ -237,50 +183,43 @@ namespace AssetStudioGUI
return true;
}
public static bool ExportSprite(AssetItem item, string exportPath)
{
var type = Properties.Settings.Default.convertType;
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = ((Sprite)item.Asset).GetImage(spriteMaskMode: spriteMaskMode);
if (image != null)
{
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
return true;
}
}
return false;
}
public static bool ExportRawFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath, mode: "ExportRaw"))
return false;
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
return true;
}
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
{
var fileName = FixFileName(item.Text);
var filenameFormatIndex = Properties.Settings.Default.filenameFormat;
switch (filenameFormatIndex)
{
case 1: //assetName@pathID
fileName = $"{fileName} @{item.m_PathID}";
break;
case 2: //pathID
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
if (filenameFormatIndex == 0) //assetName
{
Directory.CreateDirectory(dir);
return true;
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Warning($"{mode} failed. File \"{fullPath.Color(ColorConsole.BrightYellow)}\" already exist");
return false;
}
@@ -337,7 +276,7 @@ namespace AssetStudioGUI
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath, mode: "Dump"))
return false;
var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
@@ -345,6 +284,10 @@ namespace AssetStudioGUI
var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(m_Type);
}
if (string.IsNullOrEmpty(str))
{
str = item.Asset.DumpObject();
}
if (str != null)
{
File.WriteAllText(exportFullPath, str);
@@ -358,9 +301,11 @@ namespace AssetStudioGUI
switch (item.Type)
{
case ClassIDType.Texture2D:
return ExportTexture2D(item, exportPath);
case ClassIDType.Texture2DArrayImage:
case ClassIDType.Texture2DArray:
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath);
case ClassIDType.Sprite:
throw new System.NotImplementedException();
case ClassIDType.Shader:
return ExportShader(item, exportPath);
case ClassIDType.TextAsset:
@@ -375,8 +320,6 @@ namespace AssetStudioGUI
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
return ExportMovieTexture(item, exportPath);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath);
case ClassIDType.Animator:
return ExportAnimator(item, exportPath);
case ClassIDType.AnimationClip:
@@ -388,8 +331,9 @@ namespace AssetStudioGUI
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
return str.Length >= 260
? Path.GetRandomFileName()
: Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
}
}

View File

@@ -1,35 +1,181 @@
using AssetStudio;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AssetStudioGUI
{
class GUILogger : ILogger
{
public bool ShowErrorMessage = false;
public static bool ShowDebugMessage = false;
private bool isFileLoggerRunning = false;
private string loggerInitString;
private string fileLogName;
private string fileLogPath;
private Action<string> action;
private CancellationTokenSource tokenSource;
private BlockingCollection<string> consoleLogMessageCollection = new BlockingCollection<string>();
private BlockingCollection<string> fileLogMessageCollection = new BlockingCollection<string>();
private bool _useFileLogger = false;
public bool UseFileLogger
{
get => _useFileLogger;
set
{
_useFileLogger = value;
if (_useFileLogger && !isFileLoggerRunning)
{
var appAssembly = typeof(Program).Assembly.GetName();
fileLogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
fileLogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileLogName);
tokenSource = new CancellationTokenSource();
isFileLoggerRunning = true;
ConcurrentFileWriter(tokenSource.Token);
LogToFile(LoggerEvent.Verbose, $"# {loggerInitString} - Logger launched #");
}
else if (!_useFileLogger && isFileLoggerRunning)
{
LogToFile(LoggerEvent.Verbose, "# Logger closed #");
isFileLoggerRunning = false;
tokenSource.Cancel();
tokenSource.Dispose();
}
}
}
public GUILogger(Action<string> action)
{
this.action = action;
var appAssembly = typeof(Program).Assembly.GetName();
var arch = Environment.Is64BitProcess ? "x64" : "x32";
var frameworkName = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
loggerInitString = $"{appAssembly.Name} v{appAssembly.Version} [{arch}] [{frameworkName}]";
try
{
Console.Title = $"Console Logger - {appAssembly.Name} v{appAssembly.Version}";
Console.OutputEncoding = System.Text.Encoding.UTF8;
}
catch
{
// ignored
}
ConcurrentConsoleWriter();
Console.WriteLine($"# {loggerInitString}");
}
private static string ColorLogLevel(LoggerEvent logLevel)
{
var formattedLevel = $"[{logLevel}]";
switch (logLevel)
{
case LoggerEvent.Info:
return $"{formattedLevel.Color(ColorConsole.BrightCyan)}";
case LoggerEvent.Warning:
return $"{formattedLevel.Color(ColorConsole.BrightYellow)}";
case LoggerEvent.Error:
return $"{formattedLevel.Color(ColorConsole.BrightRed)}";
default:
return formattedLevel;
}
}
private static string FormatMessage(LoggerEvent logMsgLevel, string message, bool toConsole)
{
message = message.TrimEnd();
var multiLine = message.Contains("\n");
string formattedMessage;
if (toConsole)
{
var colorLogLevel = ColorLogLevel(logMsgLevel);
formattedMessage = $"{colorLogLevel} {message}";
if (multiLine)
{
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ") + $"\n{colorLogLevel}";
}
}
else
{
var curTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
message = Regex.Replace(message, @"\e\[[0-9;]*m(?:\e\[K)?", ""); //Delete ANSI colors
var logLevel = $"{logMsgLevel.ToString().ToUpper(),-7}";
formattedMessage = $"{curTime} | {logLevel} | {message}";
if (multiLine)
{
formattedMessage = formattedMessage.Replace("\n", $"\n{curTime} | {logLevel} | ") + $"\n{curTime} | {logLevel} |";
}
}
return formattedMessage;
}
private void ConcurrentFileWriter(CancellationToken token)
{
Task.Run(() =>
{
using (var sw = new StreamWriter(fileLogPath, append: true, System.Text.Encoding.UTF8))
{
sw.AutoFlush = true;
foreach (var msg in fileLogMessageCollection.GetConsumingEnumerable())
{
sw.WriteLine(msg);
if (token.IsCancellationRequested)
break;
}
}
}, token);
}
private void ConcurrentConsoleWriter()
{
Task.Run(() =>
{
foreach (var msg in consoleLogMessageCollection.GetConsumingEnumerable())
{
Console.WriteLine(msg);
}
});
}
private void LogToFile(LoggerEvent logMsgLevel, string message)
{
fileLogMessageCollection.Add(FormatMessage(logMsgLevel, message, toConsole: false));
}
private void LogToConsole(LoggerEvent logMsgLevel, string message)
{
consoleLogMessageCollection.Add(FormatMessage(logMsgLevel, message, toConsole: true));
}
public void Log(LoggerEvent loggerEvent, string message, bool ignoreLevel)
{
//File logger
if (_useFileLogger)
{
LogToFile(loggerEvent, message);
}
//Console logger
if (!ShowDebugMessage && loggerEvent == LoggerEvent.Debug)
return;
LogToConsole(loggerEvent, message);
//GUI logger
switch (loggerEvent)
{
case LoggerEvent.Error:
MessageBox.Show(message, "Error");
break;
case LoggerEvent.Warning:
if (ShowErrorMessage)
{
MessageBox.Show(message, "Warning");
}
else
{
action("An error has occurred. Turn on \"Show all error messages\" to see details next time.");
}
action("Some warnings occurred. See Console Logger for details.");
break;
case LoggerEvent.Debug:
break;

View File

@@ -0,0 +1,226 @@
using AssetStudio;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudioGUI
{
internal static class ParallelExporter
{
private static ConcurrentDictionary<string, bool> savePathHash = new ConcurrentDictionary<string, bool>();
public static bool ExportTexture2D(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
{
var type = Properties.Settings.Default.convertType;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
if (GUILogger.ShowDebugMessage)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_Texture2D.m_Name}\" to {type}..");
sb.AppendLine($"Width: {m_Texture2D.m_Width}");
sb.AppendLine($"Height: {m_Texture2D.m_Height}");
sb.AppendLine($"Format: {m_Texture2D.m_TextureFormat}");
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
{
case 0: sb.AppendLine("Filter Mode: Point "); break;
case 1: sb.AppendLine("Filter Mode: Bilinear "); break;
case 2: sb.AppendLine("Filter Mode: Trilinear "); break;
}
sb.AppendLine($"Anisotropic level: {m_Texture2D.m_TextureSettings.m_Aniso}");
sb.AppendLine($"Mip map bias: {m_Texture2D.m_TextureSettings.m_MipBias}");
switch (m_Texture2D.m_TextureSettings.m_WrapMode)
{
case 0: sb.AppendLine($"Wrap mode: Repeat"); break;
case 1: sb.AppendLine($"Wrap mode: Clamp"); break;
}
debugLog += sb.ToString();
}
var image = m_Texture2D.ConvertToImage(flip: true);
if (image == null)
{
Logger.Warning($"Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
return false;
}
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
else
{
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
public static bool ExportSprite(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
var type = Properties.Settings.Default.convertType;
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
var image = ((Sprite)item.Asset).GetImage(spriteMaskMode: spriteMaskMode);
if (image != null)
{
using (image)
{
using (var file = File.OpenWrite(exportFullPath))
{
image.WriteToStream(file, type);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
}
return false;
}
public static bool ExportAudioClip(AssetItem item, string exportPath, out string debugLog)
{
debugLog = "";
string exportFullPath;
var m_AudioClip = (AudioClip)item.Asset;
var m_AudioData = BigArrayPool<byte>.Shared.Rent(m_AudioClip.m_AudioData.Size);
try
{
m_AudioClip.m_AudioData.GetData(m_AudioData);
if (m_AudioData == null || m_AudioData.Length == 0)
{
Logger.Warning($"Failed to export \"{item.Text}\": AudioData was not found");
return false;
}
var converter = new AudioClipConverter(m_AudioClip);
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
{
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false;
if (GUILogger.ShowDebugMessage)
{
var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav..");
sb.AppendLine(m_AudioClip.version < 5
? $"AudioClip type: {m_AudioClip.m_Type}"
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
debugLog += sb.ToString();
}
var buffer = converter.ConvertToWav(m_AudioData, out var debugLogConverter);
debugLog += debugLogConverter;
if (buffer == null)
{
Logger.Warning($"{debugLog}Failed to export \"{item.Text}\": Failed to convert fmod audio to Wav");
return false;
}
File.WriteAllBytes(exportFullPath, buffer);
}
else
{
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out exportFullPath))
return false;
if (GUILogger.ShowDebugMessage)
{
var sb = new StringBuilder();
sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\"..");
sb.AppendLine(m_AudioClip.version < 5
? $"AudioClip type: {m_AudioClip.m_Type}"
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
debugLog += sb.ToString();
}
File.WriteAllBytes(exportFullPath, m_AudioData);
}
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
finally
{
BigArrayPool<byte>.Shared.Return(m_AudioData, clearArray: true);
}
}
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
{
var fileName = FixFileName(item.Text);
var filenameFormatIndex = Properties.Settings.Default.filenameFormat;
switch (filenameFormatIndex)
{
case 1: //assetName@pathID
fileName = $"{fileName} @{item.m_PathID}";
break;
case 2: //pathID
fileName = item.m_PathID.ToString();
break;
}
fullPath = Path.Combine(dir, fileName + extension);
if (savePathHash.TryAdd(fullPath.ToLower(), true) && !File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
if (filenameFormatIndex == 0) //assetName
{
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
}
Logger.Warning($"Export failed. File \"{fullPath.Color(ColorConsole.BrightYellow)}\" already exist");
return false;
}
public static bool ParallelExportConvertFile(AssetItem item, string exportPath, out string debugLog)
{
switch (item.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Texture2DArrayImage:
return ExportTexture2D(item, exportPath, out debugLog);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath, out debugLog);
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath, out debugLog);
default:
throw new NotImplementedException();
}
}
private static string FixFileName(string str)
{
return str.Length >= 260
? Path.GetRandomFileName()
: Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
public static void ClearHash()
{
savePathHash.Clear();
}
}
}

View File

@@ -12,7 +12,7 @@ namespace AssetStudioGUI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -286,5 +286,113 @@ namespace AssetStudioGUI.Properties {
this["exportSpriteWithMask"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("MonoBehaviour")]
public global::CubismLive2DExtractor.Live2DMotionMode l2dMotionMode {
get {
return ((global::CubismLive2DExtractor.Live2DMotionMode)(this["l2dMotionMode"]));
}
set {
this["l2dMotionMode"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool l2dForceBezier {
get {
return ((bool)(this["l2dForceBezier"]));
}
set {
this["l2dForceBezier"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool showConsole {
get {
return ((bool)(this["showConsole"]));
}
set {
this["showConsole"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool useFileLogger {
get {
return ((bool)(this["useFileLogger"]));
}
set {
this["useFileLogger"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool buildTreeStructure {
get {
return ((bool)(this["buildTreeStructure"]));
}
set {
this["buildTreeStructure"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int filenameFormat {
get {
return ((int)(this["filenameFormat"]));
}
set {
this["filenameFormat"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool parallelExport {
get {
return ((bool)(this["parallelExport"]));
}
set {
this["parallelExport"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("-1")]
public int parallelExportCount {
get {
return ((int)(this["parallelExportCount"]));
}
set {
this["parallelExportCount"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool useTypetreeLoading {
get {
return ((bool)(this["useTypetreeLoading"]));
}
set {
this["useTypetreeLoading"] = value;
}
}
}
}

View File

@@ -68,5 +68,32 @@
<Setting Name="exportSpriteWithMask" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="l2dMotionMode" Type="CubismLive2DExtractor.Live2DMotionMode" Scope="User">
<Value Profile="(Default)">MonoBehaviour</Value>
</Setting>
<Setting Name="l2dForceBezier" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="showConsole" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="useFileLogger" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="buildTreeStructure" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="filenameFormat" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="parallelExport" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="parallelExportCount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">-1</Value>
</Setting>
<Setting Name="useTypetreeLoading" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@@ -1,15 +1,17 @@
using AssetStudio;
using CubismLive2DExtractor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using static AssetStudioGUI.Exporter;
using static CubismLive2DExtractor.Live2DExtractor;
using Object = AssetStudio.Object;
namespace AssetStudioGUI
@@ -28,6 +30,15 @@ namespace AssetStudioGUI
Filtered
}
internal enum ExportL2DFilter
{
All,
Selected,
SelectedWithFadeList,
SelectedWithFade,
SelectedWithClips,
}
internal enum ExportListType
{
XML
@@ -38,7 +49,8 @@ namespace AssetStudioGUI
TypeName,
ContainerPath,
ContainerPathFull,
SourceFileName
SourceFileName,
SceneHierarchy,
}
internal enum ListSearchFilterMode
@@ -49,13 +61,24 @@ namespace AssetStudioGUI
RegexContainer,
}
[Flags]
internal enum SelectedAssetType
{
Animator = 0x01,
AnimationClip = 0x02,
MonoBehaviourMoc = 0x04,
MonoBehaviourFade = 0x08,
MonoBehaviourFadeLst = 0x10
}
internal static class Studio
{
public static AssetsManager assetsManager = new AssetsManager();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
public static List<AssetItem> exportableAssets = new List<AssetItem>();
public static List<AssetItem> visibleAssets = new List<AssetItem>();
private static Dictionary<Object, string> allContainers = new Dictionary<Object, string>();
public static List<MonoBehaviour> cubismMocList = new List<MonoBehaviour>();
private static Dictionary<Object, string> l2dResourceContainers = new Dictionary<Object, string>();
internal static Action<string> StatusStripUpdate = x => { };
public static int ExtractFolder(string path, string savePath)
@@ -103,7 +126,7 @@ namespace AssetStudioGUI
private static int ExtractBundleFile(FileReader reader, string savePath)
{
Logger.Info($"Decompressing {reader.FileName} ...");
var bundleFile = new BundleFile(reader, assetsManager.SpecifyUnityVersion);
var bundleFile = new BundleFile(reader, assetsManager.ZstdEnabled, assetsManager.SpecifyUnityVersion);
reader.Dispose();
if (bundleFile.fileList.Length > 0)
{
@@ -158,10 +181,14 @@ namespace AssetStudioGUI
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
var containers = new List<(PPtr<Object>, string)>();
int i = 0;
var tex2dArrayAssetList = new List<AssetItem>();
l2dResourceContainers.Clear();
var i = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var preloadTable = Array.Empty<PPtr<Object>>();
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
@@ -170,6 +197,9 @@ namespace AssetStudioGUI
var exportable = false;
switch (asset)
{
case PreloadData m_PreloadData:
preloadTable = m_PreloadData.m_Assets;
break;
case GameObject m_GameObject:
assetItem.Text = m_GameObject.m_Name;
break;
@@ -179,6 +209,13 @@ namespace AssetStudioGUI
assetItem.Text = m_Texture2D.m_Name;
exportable = true;
break;
case Texture2DArray m_Texture2DArray:
if (!string.IsNullOrEmpty(m_Texture2DArray.m_StreamData?.path))
assetItem.FullSize = asset.byteSize + m_Texture2DArray.m_StreamData.size;
assetItem.Text = m_Texture2DArray.m_Name;
tex2dArrayAssetList.Add(assetItem);
exportable = true;
break;
case AudioClip m_AudioClip:
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size;
@@ -187,7 +224,7 @@ namespace AssetStudioGUI
break;
case VideoClip m_VideoClip:
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_ExternalResources.m_Size;
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
assetItem.Text = m_VideoClip.m_Name;
exportable = true;
break;
@@ -212,31 +249,39 @@ namespace AssetStudioGUI
exportable = true;
break;
case MonoBehaviour m_MonoBehaviour:
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
var assetName = m_MonoBehaviour.m_Name;
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
assetItem.Text = m_Script.m_ClassName;
}
else
{
assetItem.Text = m_MonoBehaviour.m_Name;
assetName = assetName == "" ? m_Script.m_ClassName : assetName;
if (m_Script.m_ClassName == "CubismMoc")
{
cubismMocList.Add(m_MonoBehaviour);
}
}
assetItem.Text = assetName;
exportable = true;
break;
case PlayerSettings m_PlayerSettings:
productName = m_PlayerSettings.productName;
break;
case AssetBundle m_AssetBundle:
var isStreamedSceneAssetBundle = m_AssetBundle.m_IsStreamedSceneAssetBundle;
if (!isStreamedSceneAssetBundle)
{
preloadTable = m_AssetBundle.m_PreloadTable;
}
assetItem.Text = string.IsNullOrEmpty(m_AssetBundle.m_AssetBundleName) ? m_AssetBundle.m_Name : m_AssetBundle.m_AssetBundleName;
foreach (var m_Container in m_AssetBundle.m_Container)
{
var preloadIndex = m_Container.Value.preloadIndex;
var preloadSize = m_Container.Value.preloadSize;
var preloadSize = isStreamedSceneAssetBundle ? preloadTable.Length : m_Container.Value.preloadSize;
var preloadEnd = preloadIndex + preloadSize;
for (int k = preloadIndex; k < preloadEnd; k++)
for (var k = preloadIndex; k < preloadEnd; k++)
{
containers.Add((m_AssetBundle.m_PreloadTable[k], m_Container.Key));
containers.Add((preloadTable[k], m_Container.Key));
}
}
assetItem.Text = m_AssetBundle.m_Name;
break;
case ResourceManager m_ResourceManager:
foreach (var m_Container in m_ResourceManager.m_Container)
@@ -259,12 +304,36 @@ namespace AssetStudioGUI
Progress.Report(++i, objectCount);
}
}
foreach ((var pptr, var container) in containers)
foreach (var (pptr, container) in containers)
{
if (pptr.TryGet(out var obj))
{
objectAssetItemDic[obj].Container = container;
allContainers[obj] = container;
switch (obj)
{
case AnimationClip _:
case GameObject _:
case Texture2D _:
case MonoBehaviour _:
l2dResourceContainers[obj] = container;
break;
}
}
}
foreach (var tex2dAssetItem in tex2dArrayAssetList)
{
var m_Texture2DArray = (Texture2DArray)tex2dAssetItem.Asset;
for (var layer = 0; layer < m_Texture2DArray.m_Depth; layer++)
{
var fakeObj = new Texture2D(m_Texture2DArray, layer);
m_Texture2DArray.TextureList.Add(fakeObj);
var fakeItem = new AssetItem(fakeObj)
{
Text = fakeObj.m_Name,
Container = tex2dAssetItem.Container
};
exportableAssets.Add(fakeItem);
}
}
foreach (var tmp in exportableAssets)
@@ -272,15 +341,23 @@ namespace AssetStudioGUI
tmp.SetSubItems();
}
containers.Clear();
tex2dArrayAssetList.Clear();
visibleAssets = exportableAssets;
if (!Properties.Settings.Default.buildTreeStructure)
{
Logger.Info("Building tree structure step is skipped");
objectAssetItemDic.Clear();
return (productName, new List<TreeNode>());
}
Logger.Info("Building tree structure...");
var treeNodeCollection = new List<TreeNode>();
var treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
var assetsFileCount = assetsManager.assetsFileList.Count;
int j = 0;
var j = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
@@ -335,7 +412,6 @@ namespace AssetStudioGUI
}
}
}
parentNode.Nodes.Add(currentNode);
}
}
@@ -348,7 +424,6 @@ namespace AssetStudioGUI
Progress.Report(++j, assetsFileCount);
}
treeNodeDictionary.Clear();
objectAssetItemDic.Clear();
return (productName, treeNodeCollection);
@@ -386,7 +461,6 @@ namespace AssetStudioGUI
typeMap.Add(assetsFile.unityVersion, items);
}
}
return typeMap;
}
@@ -396,12 +470,21 @@ namespace AssetStudioGUI
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
int toExportCount = toExportAssets.Count;
int exportedCount = 0;
int i = 0;
Progress.Reset();
var groupOption = (AssetGroupOption)Properties.Settings.Default.assetGroupOption;
foreach (var asset in toExportAssets)
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
? Environment.ProcessorCount - 1
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
parallelExportCount = Properties.Settings.Default.parallelExport ? parallelExportCount : 1;
var toExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
var toParallelExportAssetDict = new ConcurrentDictionary<AssetItem, string>();
var exceptionMsgs = new ConcurrentDictionary<Exception, string>();
var mode = exportType == ExportType.Dump ? "Dump" : "Export";
var toExportCount = toExportAssets.Count;
var exportedCount = 0;
var i = 0;
Progress.Reset();
Parallel.ForEach(toExportAssets, asset =>
{
string exportPath;
switch (groupOption)
@@ -434,52 +517,146 @@ namespace AssetStudioGUI
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
}
break;
case AssetGroupOption.SceneHierarchy:
if (asset.TreeNode != null)
{
exportPath = Path.Combine(savePath, asset.TreeNode.FullPath);
}
else
{
exportPath = Path.Combine(savePath, "_sceneRoot", asset.TypeString);
}
break;
default:
exportPath = savePath;
break;
}
exportPath += Path.DirectorySeparatorChar;
Logger.Info($"[{exportedCount + 1}/{toExportCount}] Exporting {asset.TypeString}: {asset.Text}");
if (exportType == ExportType.Convert)
{
switch (asset.Type)
{
case ClassIDType.Texture2D:
case ClassIDType.Texture2DArrayImage:
case ClassIDType.Sprite:
case ClassIDType.AudioClip:
toParallelExportAssetDict.TryAdd(asset, exportPath);
break;
case ClassIDType.Texture2DArray:
var m_Texture2DArray = (Texture2DArray)asset.Asset;
toExportCount += m_Texture2DArray.TextureList.Count - 1;
foreach (var texture in m_Texture2DArray.TextureList)
{
var fakeItem = new AssetItem(texture)
{
Text = texture.m_Name,
Container = asset.Container,
};
toParallelExportAssetDict.TryAdd(fakeItem, exportPath);
}
break;
default:
toExportAssetDict.TryAdd(asset, exportPath);
break;
}
}
else
{
toExportAssetDict.TryAdd(asset, exportPath);
}
});
foreach (var toExportAsset in toExportAssetDict)
{
var asset = toExportAsset.Key;
var exportPath = toExportAsset.Value;
var isExported = false;
try
{
Logger.Info($"[{exportedCount + 1}/{toExportCount}] {mode}ing {asset.TypeString}: {asset.Text}");
switch (exportType)
{
case ExportType.Raw:
if (ExportRawFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportRawFile(asset, exportPath);
break;
case ExportType.Dump:
if (ExportDumpFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportDumpFile(asset, exportPath);
break;
case ExportType.Convert:
if (ExportConvertFile(asset, exportPath))
{
exportedCount++;
}
isExported = ExportConvertFile(asset, exportPath);
break;
}
}
catch (Exception ex)
{
Logger.Error($"Export {asset.Type}:{asset.Text} error", ex);
Logger.Error($"{mode} {asset.TypeString}: {asset.Text} error", ex);
}
if (isExported)
{
exportedCount++;
}
else
{
Logger.Warning($"Unable to {mode.ToLower()} {asset.TypeString}: {asset.Text}");
}
Progress.Report(++i, toExportCount);
}
var statusText = exportedCount == 0 ? "Nothing exported." : $"Finished exporting {exportedCount} assets.";
if (toExportCount > exportedCount)
Parallel.ForEach(toParallelExportAssetDict, new ParallelOptions { MaxDegreeOfParallelism = parallelExportCount }, (toExportAsset, loopState) =>
{
statusText += $" {toExportCount - exportedCount} assets skipped (not extractable or files already exist)";
var asset = toExportAsset.Key;
var exportPath = toExportAsset.Value;
try
{
if (ParallelExporter.ParallelExportConvertFile(asset, exportPath, out var debugLog))
{
Interlocked.Increment(ref exportedCount);
if (GUILogger.ShowDebugMessage)
{
Logger.Debug(debugLog);
StatusStripUpdate($"[{exportedCount}/{toExportCount}] Exporting {asset.TypeString}: {asset.Text}");
}
else
{
Logger.Info($"[{exportedCount}/{toExportCount}] Exporting {asset.TypeString}: {asset.Text}");
}
}
Interlocked.Increment(ref i);
Progress.Report(i, toExportCount);
}
catch (Exception ex)
{
if (parallelExportCount == 1)
{
Logger.Error($"{mode} {asset.TypeString}: {asset.Text} error", ex);
}
else
{
loopState.Break();
exceptionMsgs.TryAdd(ex, $"Exception occurred when exporting {asset.TypeString}: {asset.Text}\n{ex}\n");
}
}
});
ParallelExporter.ClearHash();
foreach (var ex in exceptionMsgs)
{
Logger.Error(ex.Value);
}
var statusText = exportedCount == 0 ? "Nothing exported." : $"Finished {mode.ToLower()}ing [{exportedCount}/{toExportCount}] assets.";
if (toExportCount > exportedCount)
{
statusText += exceptionMsgs.IsEmpty
? $" {toExportCount - exportedCount} assets skipped (not extractable or files already exist)."
: " Export process was stopped because one or more exceptions occurred.";
Progress.Report(toExportCount, toExportCount);
}
Logger.Info(statusText);
exceptionMsgs.Clear();
if (Properties.Settings.Default.openAfterExport && exportedCount > 0)
{
@@ -511,6 +688,7 @@ namespace AssetStudioGUI
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString),
new XElement("PathID", asset.m_PathID),
new XElement("Source", asset.SourceFile.fullName),
new XElement("TreeNode", asset.TreeNode != null ? asset.TreeNode.FullPath : ""),
new XElement("Size", asset.FullSize)
)
)
@@ -522,11 +700,11 @@ namespace AssetStudioGUI
break;
}
var statusText = $"Finished exporting asset list with {toExportAssets.Count()} items.";
var statusText = $"Finished exporting asset list with {toExportAssets.Count} items.";
Logger.Info(statusText);
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count() > 0)
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count > 0)
{
OpenFolderInExplorer(savePath);
}
@@ -609,6 +787,7 @@ namespace AssetStudioGUI
{
Progress.Reset();
Logger.Info($"Exporting {animator.Text}");
Logger.Debug($"Selected AnimationClip(s):\n\"{string.Join("\"\n\"", animationList.Select(x => x.Text))}\"");
try
{
ExportAnimator(animator, exportPath, animationList);
@@ -707,6 +886,12 @@ namespace AssetStudioGUI
}
public static TypeTree MonoBehaviourToTypeTree(MonoBehaviour m_MonoBehaviour)
{
SelectAssemblyFolder();
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
}
private static void SelectAssemblyFolder()
{
if (!assemblyLoader.Loaded)
{
@@ -721,7 +906,6 @@ namespace AssetStudioGUI
assemblyLoader.Loaded = true;
}
}
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
}
public static string DumpAsset(Object obj)
@@ -732,6 +916,10 @@ namespace AssetStudioGUI
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(type);
}
if (string.IsNullOrEmpty(str))
{
str = obj.DumpObject();
}
return str;
}
@@ -742,59 +930,105 @@ namespace AssetStudioGUI
Process.Start(info);
}
public static void ExportLive2D(Object[] cubismMocs, string exportPath)
public static void ExportLive2D(string exportPath, List<MonoBehaviour> selMocs = null, List<AnimationClip> selClipMotions = null, List<MonoBehaviour> selFadeMotions = null, MonoBehaviour selFadeLst = null)
{
var baseDestPath = Path.Combine(exportPath, "Live2DOutput");
var forceBezier = Properties.Settings.Default.l2dForceBezier;
var mocList = selMocs ?? cubismMocList;
var motionMode = Properties.Settings.Default.l2dMotionMode;
if (selClipMotions != null)
motionMode = Live2DMotionMode.AnimationClipV2;
else if (selFadeMotions != null || selFadeLst != null)
motionMode = Live2DMotionMode.MonoBehaviour;
ThreadPool.QueueUserWorkItem(state =>
{
Logger.Info($"Searching for Live2D files...");
var useFullContainerPath = false;
if (cubismMocs.Length > 1)
var mocPathDict = new Dictionary<MonoBehaviour, (string, string)>();
var mocPathList = new List<string>();
foreach (var mocMonoBehaviour in cubismMocList)
{
var basePathSet = cubismMocs.Select(x => allContainers[x].Substring(0, allContainers[x].LastIndexOf("/"))).ToHashSet();
if (!l2dResourceContainers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
continue;
if (basePathSet.Count != cubismMocs.Length)
{
useFullContainerPath = true;
}
var pathSepIndex = fullContainerPath.LastIndexOf('/');
var basePath = pathSepIndex > 0
? fullContainerPath.Substring(0, pathSepIndex)
: fullContainerPath;
mocPathDict.Add(mocMonoBehaviour, (fullContainerPath, basePath));
}
var basePathList = useFullContainerPath ?
cubismMocs.Select(x => allContainers[x]).ToList() :
cubismMocs.Select(x => allContainers[x].Substring(0, allContainers[x].LastIndexOf("/"))).ToList();
var lookup = allContainers.ToLookup(
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
if (mocPathDict.Count == 0)
{
Logger.Error("Live2D Cubism export error\r\nCannot find any model related files");
StatusStripUpdate("Live2D export canceled");
Progress.Reset();
return;
}
var basePathSet = mocPathDict.Values.Select(x => x.Item2).ToHashSet();
var useFullContainerPath = mocPathDict.Count != basePathSet.Count;
foreach (var moc in mocList)
{
var mocPath = useFullContainerPath
? mocPathDict[moc].Item1 //fullContainerPath
: mocPathDict[moc].Item2; //basePath
mocPathList.Add(mocPath);
}
mocPathDict.Clear();
var lookup = l2dResourceContainers.AsParallel().ToLookup(
x => mocPathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
x => x.Key
);
if (mocList[0].serializedType?.m_Type == null && !assemblyLoader.Loaded)
{
Logger.Warning("Specifying the assembly folder may be needed for proper extraction");
SelectAssemblyFolder();
}
var totalModelCount = lookup.LongCount(x => x.Key != null);
var name = "";
var modelCounter = 0;
var parallelExportCount = Properties.Settings.Default.parallelExportCount <= 0
? Environment.ProcessorCount - 1
: Math.Min(Properties.Settings.Default.parallelExportCount, Environment.ProcessorCount - 1);
parallelExportCount = Properties.Settings.Default.parallelExport ? parallelExportCount : 1;
foreach (var assets in lookup)
{
var container = assets.Key;
if (container == null)
var srcContainer = assets.Key;
if (srcContainer == null)
continue;
name = container;
var container = srcContainer;
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{container}\"...");
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{srcContainer}\"...");
try
{
var modelName = useFullContainerPath ? Path.GetFileNameWithoutExtension(container) : container.Substring(container.LastIndexOf('/') + 1);
container = Path.HasExtension(container) ? container.Replace(Path.GetExtension(container), "") : container;
var modelName = useFullContainerPath
? Path.GetFileNameWithoutExtension(container)
: container.Substring(container.LastIndexOf('/') + 1);
container = Path.HasExtension(container)
? container.Replace(Path.GetExtension(container), "")
: container;
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
ExtractLive2D(assets, destPath, modelName, assemblyLoader);
var modelExtractor = new Live2DExtractor(assets, selClipMotions, selFadeMotions, selFadeLst);
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelExportCount);
modelCounter++;
}
catch (Exception ex)
{
Logger.Error($"Live2D model export error: \"{name}\"", ex);
Logger.Error($"Live2D model export error: \"{srcContainer}\"", ex);
}
Progress.Report(modelCounter, (int)totalModelCount);
}
Logger.Info($"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s).");
if (modelCounter < totalModelCount)
{
var total = (int)totalModelCount;
Progress.Report(total, total);
}
if (Properties.Settings.Default.openAfterExport && modelCounter > 0)
{
OpenFolderInExplorer(exportPath);

View File

@@ -33,7 +33,12 @@ namespace AssetStudio
public TypeDefinition GetTypeDefinition(string assemblyName, string fullName)
{
if (moduleDic.TryGetValue(assemblyName, out var module))
moduleDic.TryGetValue(assemblyName, out var module);
if (module == null && !assemblyName.Contains(".dll"))
{
moduleDic.TryGetValue(assemblyName + ".dll", out module);
}
if (module != null)
{
var typeDef = module.GetType(fullName);
if (typeDef == null && assemblyName == "UnityEngine.dll")

View File

@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
<Version>0.18.0.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023-2024</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
@@ -22,7 +22,7 @@
<PackageReference Include="Kyaru.Texture2DDecoder">
<Version>0.17.0</Version>
</PackageReference>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">

View File

@@ -7,25 +7,37 @@ namespace AssetStudio
{
public class AudioClipConverter
{
public bool IsSupport => m_AudioClip.IsConvertSupport();
private AudioClip m_AudioClip;
private static FMOD.System system;
static AudioClipConverter()
{
var result = Factory.System_Create(out system);
if (result != RESULT.OK)
{
Logger.Error($"FMOD error! {result} - {Error.String(result)}");
}
result = system.init(1, INITFLAGS.NORMAL, IntPtr.Zero);
if (result != RESULT.OK)
{
Logger.Error($"FMOD error! {result} - {Error.String(result)}");
}
}
public AudioClipConverter(AudioClip audioClip)
{
m_AudioClip = audioClip;
}
public byte[] ConvertToWav(byte[] m_AudioData)
public byte[] ConvertToWav(byte[] m_AudioData, out string debugLog)
{
debugLog = "";
var exinfo = new CREATESOUNDEXINFO();
var result = Factory.System_Create(out var system);
if (result != RESULT.OK)
return null;
result = system.init(1, INITFLAGS.NORMAL, IntPtr.Zero);
if (result != RESULT.OK)
return null;
exinfo.cbsize = Marshal.SizeOf(exinfo);
exinfo.length = (uint)m_AudioClip.m_Size;
result = system.createSound(m_AudioData, MODE.OPENMEMORY, ref exinfo, out var sound);
var result = system.createSound(m_AudioData, MODE.OPENMEMORY, ref exinfo, out var sound);
if (result != RESULT.OK)
return null;
result = sound.getNumSubSounds(out var numsubsounds);
@@ -37,28 +49,29 @@ namespace AssetStudio
result = sound.getSubSound(0, out var subsound);
if (result != RESULT.OK)
return null;
buff = SoundToWav(subsound);
buff = SoundToWav(subsound, out debugLog);
subsound.release();
subsound.clearHandle();
}
else
{
buff = SoundToWav(sound);
buff = SoundToWav(sound, out debugLog);
}
sound.release();
system.release();
sound.clearHandle();
return buff;
}
public byte[] SoundToWav(Sound sound)
public byte[] SoundToWav(Sound sound, out string debugLog)
{
Logger.Debug($"[Fmod] Detecting sound format..\n");
debugLog = "[Fmod] Detecting sound format..\n";
var result = sound.getFormat(out SOUND_TYPE soundType, out SOUND_FORMAT soundFormat, out int channels, out int bits);
if (result != RESULT.OK)
return null;
Logger.Debug($"Detected sound type: {soundType}\n" +
$"Detected sound format: {soundFormat}\n" +
$"Detected channels: {channels}\n" +
$"Detected bit depth: {bits}");
debugLog += $"Detected sound type: {soundType}\n" +
$"Detected sound format: {soundFormat}\n" +
$"Detected channels: {channels}\n" +
$"Detected bit depth: {bits}\n";
result = sound.getDefaults(out var frequency, out _);
if (result != RESULT.OK)
return null;
@@ -69,11 +82,11 @@ namespace AssetStudio
result = sound.@lock(0, length, out var ptr1, out var ptr2, out var len1, out var len2);
if (result != RESULT.OK)
return null;
byte[] buffer = new byte[len1 + 44];
var buffer = new byte[len1 + 44];
//添加wav头
Encoding.UTF8.GetBytes("RIFF").CopyTo(buffer, 0);
Encoding.ASCII.GetBytes("RIFF").CopyTo(buffer, 0);
BitConverter.GetBytes(len1 + 36).CopyTo(buffer, 4);
Encoding.UTF8.GetBytes("WAVEfmt ").CopyTo(buffer, 8);
Encoding.ASCII.GetBytes("WAVEfmt ").CopyTo(buffer, 8);
BitConverter.GetBytes(16).CopyTo(buffer, 16);
BitConverter.GetBytes((short)1).CopyTo(buffer, 20);
BitConverter.GetBytes((short)channels).CopyTo(buffer, 22);
@@ -81,7 +94,7 @@ namespace AssetStudio
BitConverter.GetBytes(sampleRate * channels * bits / 8).CopyTo(buffer, 28);
BitConverter.GetBytes((short)(channels * bits / 8)).CopyTo(buffer, 32);
BitConverter.GetBytes((short)bits).CopyTo(buffer, 34);
Encoding.UTF8.GetBytes("data").CopyTo(buffer, 36);
Encoding.ASCII.GetBytes("data").CopyTo(buffer, 36);
BitConverter.GetBytes(len1).CopyTo(buffer, 40);
Marshal.Copy(ptr1, buffer, 44, (int)len1);
result = sound.unlock(ptr1, ptr2, len1, len2);
@@ -92,11 +105,11 @@ namespace AssetStudio
public string GetExtensionName()
{
if (m_AudioClip.version[0] < 5)
if (m_AudioClip.version < 5)
{
switch (m_AudioClip.m_Type)
{
case FMODSoundType.ACC:
case FMODSoundType.AAC:
return ".m4a";
case FMODSoundType.AIFF:
return ".aif";
@@ -149,43 +162,42 @@ namespace AssetStudio
return ".fsb";
}
}
return ".AudioClip";
}
}
public bool IsSupport
public static class AudioClipExtension
{
public static bool IsConvertSupport(this AudioClip m_AudioClip)
{
get
if (m_AudioClip.version < 5)
{
if (m_AudioClip.version[0] < 5)
switch (m_AudioClip.m_Type)
{
switch (m_AudioClip.m_Type)
{
case FMODSoundType.AIFF:
case FMODSoundType.IT:
case FMODSoundType.MOD:
case FMODSoundType.S3M:
case FMODSoundType.XM:
case FMODSoundType.XMA:
case FMODSoundType.AUDIOQUEUE:
return true;
default:
return false;
}
case FMODSoundType.AIFF:
case FMODSoundType.IT:
case FMODSoundType.MOD:
case FMODSoundType.S3M:
case FMODSoundType.XM:
case FMODSoundType.XMA:
case FMODSoundType.AUDIOQUEUE:
return true;
default:
return false;
}
else
}
else
{
switch (m_AudioClip.m_CompressionFormat)
{
switch (m_AudioClip.m_CompressionFormat)
{
case AudioCompressionFormat.PCM:
case AudioCompressionFormat.Vorbis:
case AudioCompressionFormat.ADPCM:
case AudioCompressionFormat.MP3:
case AudioCompressionFormat.XMA:
return true;
default:
return false;
}
case AudioCompressionFormat.PCM:
case AudioCompressionFormat.Vorbis:
case AudioCompressionFormat.ADPCM:
case AudioCompressionFormat.MP3:
case AudioCompressionFormat.XMA:
return true;
default:
return false;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace CubismLive2DExtractor
{
public class CubismCdi3Json
{
public int Version { get; set; }
public ParamGroupArray[] Parameters { get; set; }
public ParamGroupArray[] ParameterGroups { get; set; }
public PartArray[] Parts { get; set; }
public class ParamGroupArray : IComparable
{
public string Id { get; set; }
public string GroupId { get; set; }
public string Name { get; set; }
public int CompareTo(object obj)
{
return string.Compare(Id, ((ParamGroupArray)obj).Id, StringComparison.OrdinalIgnoreCase);
}
}
public class PartArray : IComparable
{
public string Id { get; set; }
public string Name { get; set; }
public int CompareTo(object obj)
{
return string.Compare(Id, ((PartArray)obj).Id, StringComparison.OrdinalIgnoreCase);
}
}
}
}

View File

@@ -1,5 +1,12 @@
namespace CubismLive2DExtractor
{
public enum BlendType
{
Add,
Multiply,
Overwrite,
}
public class CubismExpression3Json
{
public string Type;
@@ -11,7 +18,7 @@
{
public string Id;
public float Value;
public int Blend;
public BlendType Blend;
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
namespace CubismLive2DExtractor
{
public sealed class AnimationCurve
{
public CubismKeyframeData[] m_Curve { get; set; }
public int m_PreInfinity { get; set; }
public int m_PostInfinity { get; set; }
public int m_RotationOrder { get; set; }
}
public sealed class CubismFadeMotion
{
public string m_Name { get; set; }
public string MotionName { get; set; }
public float FadeInTime { get; set; }
public float FadeOutTime { get; set; }
public string[] ParameterIds { get; set; }
public AnimationCurve[] ParameterCurves { get; set; }
public float[] ParameterFadeInTimes { get; set; }
public float[] ParameterFadeOutTimes { get; set; }
public float MotionLength { get; set; }
public CubismFadeMotion()
{
ParameterIds = Array.Empty<string>();
}
}
}

View File

@@ -0,0 +1,26 @@
namespace CubismLive2DExtractor
{
public class CubismKeyframeData
{
public float time { get; set; }
public float value { get; set; }
public float inSlope { get; set; }
public float outSlope { get; set; }
public int weightedMode { get; set; }
public float inWeight { get; set; }
public float outWeight { get; set; }
public CubismKeyframeData() { }
public CubismKeyframeData(ImportedKeyframe<float> keyframe)
{
time = keyframe.time;
value = keyframe.value;
inSlope = keyframe.inSlope;
outSlope = keyframe.outSlope;
weightedMode = 0;
inWeight = 0;
outWeight = 0;
}
}
}

View File

@@ -13,6 +13,7 @@ namespace CubismLive2DExtractor
{
public string Moc;
public string[] Textures;
public string DisplayInfo;
public string Physics;
public JObject Motions;
public JArray Expressions;

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AssetStudio;
@@ -8,26 +7,35 @@ namespace CubismLive2DExtractor
{
class CubismMotion3Converter
{
private SerializedFile assetsFile;
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
public CubismMotion3Converter(GameObject rootGameObject, AnimationClip[] animationClips)
public CubismMotion3Converter(GameObject rootGameObject, List<AnimationClip> animationClips)
{
var rootTransform = GetTransform(rootGameObject);
CreateBonePathHash(rootTransform);
ConvertAnimations(animationClips);
}
private void ConvertAnimations(AnimationClip[] animationClips)
public CubismMotion3Converter(List<AnimationClip> animationClips, HashSet<string> partIds, HashSet<string> parameterIds)
{
CreateBonePathHash(partIds, pathType: "Parts/");
CreateBonePathHash(parameterIds, pathType: "Parameters/");
ConvertAnimations(animationClips);
}
private void ConvertAnimations(List<AnimationClip> animationClips)
{
foreach (var animationClip in animationClips)
{
var iAnim = new ImportedKeyframedAnimation();
assetsFile = animationClip.assetsFile;
AnimationList.Add(iAnim);
iAnim.Name = animationClip.m_Name;
iAnim.SampleRate = animationClip.m_SampleRate;
iAnim.Duration = animationClip.m_MuscleClip.m_StopTime;
var m_Clip = animationClip.m_MuscleClip.m_Clip;
var m_Clip = animationClip.m_MuscleClip.m_Clip.data;
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
var m_ClipBindingConstant = animationClip.m_ClipBindingConstant;
for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++)
@@ -73,7 +81,7 @@ namespace CubismLive2DExtractor
if (iAnim.TrackList.Count == 0 || iAnim.Events.Count == 0)
{
Logger.Warning($"[Motion Converter] {iAnim.Name} has {iAnim.TrackList.Count} tracks and {iAnim.Events.Count} event!.");
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" has {iAnim.TrackList.Count} tracks and {iAnim.Events.Count} event!.");
}
}
}
@@ -84,7 +92,7 @@ namespace CubismLive2DExtractor
GetLive2dPath(binding, out var target, out var boneName);
if (string.IsNullOrEmpty(boneName))
{
Logger.Warning($"[Motion Converter] {iAnim.Name} read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
return;
}
@@ -99,7 +107,7 @@ namespace CubismLive2DExtractor
GetLive2dPath(binding, out var target, out var boneName);
if (string.IsNullOrEmpty(boneName))
{
Logger.Warning($"[Motion Converter] {iAnim.Name} read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
Logger.Warning($"[Motion Converter] \"{iAnim.Name}\" read fail on binding {Array.IndexOf(m_ClipBindingConstant.genericBindings, binding)}");
return;
}
@@ -128,7 +136,7 @@ namespace CubismLive2DExtractor
target = "PartOpacity";
}
}
else if (binding.script.TryGet(out MonoScript script))
else if (binding.script.TryGet(out MonoScript script, assetsFile))
{
switch (script.m_ClassName)
{
@@ -161,21 +169,30 @@ namespace CubismLive2DExtractor
return null;
}
private void CreateBonePathHash(HashSet<string> ids, string pathType)
{
foreach (var id in ids)
{
var name = pathType + id;;
bonePathHash[GetCRC(name)] = name;
int index;
while ((index = name.IndexOf("/", StringComparison.Ordinal)) >= 0)
{
name = name.Substring(index + 1);
bonePathHash[GetCRC(name)] = name;
}
}
}
private void CreateBonePathHash(Transform m_Transform)
{
var name = GetTransformPath(m_Transform);
var crc = new SevenZip.CRC();
var bytes = Encoding.UTF8.GetBytes(name);
crc.Update(bytes, 0, (uint)bytes.Length);
bonePathHash[crc.GetDigest()] = name;
bonePathHash[GetCRC(name)] = name;
int index;
while ((index = name.IndexOf("/", StringComparison.Ordinal)) >= 0)
{
name = name.Substring(index + 1);
crc = new SevenZip.CRC();
bytes = Encoding.UTF8.GetBytes(name);
crc.Update(bytes, 0, (uint)bytes.Length);
bonePathHash[crc.GetDigest()] = name;
bonePathHash[GetCRC(name)] = name;
}
foreach (var pptr in m_Transform.m_Children)
{
@@ -184,7 +201,13 @@ namespace CubismLive2DExtractor
}
}
private string GetTransformPath(Transform transform)
private static uint GetCRC(string name)
{
var bytes = Encoding.UTF8.GetBytes(name);
return SevenZip.CRC.CalculateDigest(bytes, 0, (uint)bytes.Length);
}
private static string GetTransformPath(Transform transform)
{
transform.m_GameObject.TryGet(out var m_GameObject);
if (transform.m_Father.TryGet(out var father))

View File

@@ -1,7 +1,9 @@
using System;
// File Format Specifications
// https://github.com/Live2D/CubismSpecs/blob/master/FileFormats/motion3.json.md
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CubismLive2DExtractor
{
@@ -18,24 +20,238 @@ namespace CubismLive2DExtractor
public float Fps;
public bool Loop;
public bool AreBeziersRestricted;
public float FadeInTime;
public float FadeOutTime;
public int CurveCount;
public int TotalSegmentCount;
public int TotalPointCount;
public int UserDataCount;
public int TotalUserDataSize;
};
}
public class SerializableCurve
{
public string Target;
public string Id;
public float FadeInTime;
public float FadeOutTime;
public List<float> Segments;
};
}
public class SerializableUserData
{
public float Time;
public string Value;
}
private static void AddSegments(
CubismKeyframeData curve,
CubismKeyframeData preCurve,
CubismKeyframeData nextCurve,
SerializableCurve cubismCurve,
bool forceBezier,
ref int totalPointCount,
ref int totalSegmentCount,
ref int j
)
{
if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) // InverseSteppedSegment
{
if (nextCurve.value == curve.value)
{
cubismCurve.Segments.Add(3f); // Segment ID
cubismCurve.Segments.Add(nextCurve.time);
cubismCurve.Segments.Add(nextCurve.value);
j += 1;
totalPointCount += 1;
totalSegmentCount++;
return;
}
}
if (float.IsPositiveInfinity(curve.inSlope)) // SteppedSegment
{
cubismCurve.Segments.Add(2f); // Segment ID
cubismCurve.Segments.Add(curve.time);
cubismCurve.Segments.Add(curve.value);
totalPointCount += 1;
}
else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f && !forceBezier) // LinearSegment
{
cubismCurve.Segments.Add(0f); // Segment ID
cubismCurve.Segments.Add(curve.time);
cubismCurve.Segments.Add(curve.value);
totalPointCount += 1;
}
else // BezierSegment
{
var tangentLength = (curve.time - preCurve.time) / 3f;
cubismCurve.Segments.Add(1f); // Segment ID
cubismCurve.Segments.Add(preCurve.time + tangentLength);
cubismCurve.Segments.Add(preCurve.outSlope * tangentLength + preCurve.value);
cubismCurve.Segments.Add(curve.time - tangentLength);
cubismCurve.Segments.Add(curve.value - curve.inSlope * tangentLength);
cubismCurve.Segments.Add(curve.time);
cubismCurve.Segments.Add(curve.value);
totalPointCount += 3;
}
totalSegmentCount++;
}
public CubismMotion3Json(CubismFadeMotion fadeMotion, HashSet<string> paramNames, HashSet<string> partNames, bool forceBezier)
{
Version = 3;
Meta = new SerializableMeta
{
// Duration of the motion in seconds.
Duration = fadeMotion.MotionLength,
// Framerate of the motion in seconds.
Fps = 30,
// [Optional] Status of the looping of the motion.
Loop = true,
// [Optional] Status of the restriction of Bezier handles'X translations.
AreBeziersRestricted = true,
// [Optional] Time of the overall Fade-In for easing in seconds.
FadeInTime = fadeMotion.FadeInTime,
// [Optional] Time of the overall Fade-Out for easing in seconds.
FadeOutTime = fadeMotion.FadeOutTime,
// The total number of curves.
CurveCount = (int)fadeMotion.ParameterCurves.LongCount(x => x.m_Curve.Length > 0),
// [Optional] The total number of UserData.
UserDataCount = 0
};
// Motion curves.
Curves = new SerializableCurve[Meta.CurveCount];
var totalSegmentCount = 1;
var totalPointCount = 1;
var actualCurveCount = 0;
for (var i = 0; i < fadeMotion.ParameterCurves.Length; i++)
{
if (fadeMotion.ParameterCurves[i].m_Curve.Length == 0)
continue;
string target;
string paramId = fadeMotion.ParameterIds[i];
switch (paramId)
{
case "Opacity":
case "EyeBlink":
case "LipSync":
target = "Model";
break;
default:
if (paramNames.Contains(paramId))
{
target = "Parameter";
}
else if (partNames.Contains(paramId))
{
target = "PartOpacity";
}
else
{
target = paramId.ToLower().Contains("part") ? "PartOpacity" : "Parameter";
AssetStudio.Logger.Warning($"[{fadeMotion.m_Name}] Binding error: Unable to find \"{paramId}\" among the model parts/parameters");
}
break;
}
Curves[actualCurveCount] = new SerializableCurve
{
// Target type.
Target = target,
// Identifier for mapping curve to target.
Id = paramId,
// [Optional] Time of the Fade - In for easing in seconds.
FadeInTime = fadeMotion.ParameterFadeInTimes[i],
// [Optional] Time of the Fade - Out for easing in seconds.
FadeOutTime = fadeMotion.ParameterFadeOutTimes[i],
// Flattened segments.
Segments = new List<float>
{
// First point
fadeMotion.ParameterCurves[i].m_Curve[0].time,
fadeMotion.ParameterCurves[i].m_Curve[0].value
}
};
for (var j = 1; j < fadeMotion.ParameterCurves[i].m_Curve.Length; j++)
{
var curve = fadeMotion.ParameterCurves[i].m_Curve[j];
var preCurve = fadeMotion.ParameterCurves[i].m_Curve[j - 1];
var next = fadeMotion.ParameterCurves[i].m_Curve.ElementAtOrDefault(j + 1);
var nextCurve = next ?? new CubismKeyframeData();
AddSegments(curve, preCurve, nextCurve, Curves[actualCurveCount], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
}
actualCurveCount++;
}
// The total number of segments (from all curves).
Meta.TotalSegmentCount = totalSegmentCount;
// The total number of points (from all segments of all curves).
Meta.TotalPointCount = totalPointCount;
UserData = Array.Empty<SerializableUserData>();
// [Optional] The total size of UserData in bytes.
Meta.TotalUserDataSize = 0;
}
public CubismMotion3Json(ImportedKeyframedAnimation animation, bool forceBezier)
{
Version = 3;
Meta = new SerializableMeta
{
Duration = animation.Duration,
Fps = animation.SampleRate,
Loop = true,
AreBeziersRestricted = true,
FadeInTime = 0,
FadeOutTime = 0,
CurveCount = animation.TrackList.Count,
UserDataCount = animation.Events.Count
};
Curves = new SerializableCurve[Meta.CurveCount];
var totalSegmentCount = 1;
var totalPointCount = 1;
for (var i = 0; i < Meta.CurveCount; i++)
{
var track = animation.TrackList[i];
Curves[i] = new SerializableCurve
{
Target = track.Target,
Id = track.Name,
FadeInTime = -1,
FadeOutTime = -1,
Segments = new List<float>
{
0f,
track.Curve[0].value
}
};
for (var j = 1; j < track.Curve.Count; j++)
{
var curve = new CubismKeyframeData(track.Curve[j]);
var preCurve = new CubismKeyframeData(track.Curve[j - 1]);
var next = track.Curve.ElementAtOrDefault(j + 1);
var nextCurve = next != null ? new CubismKeyframeData(next) : new CubismKeyframeData();
AddSegments(curve, preCurve, nextCurve, Curves[i], forceBezier, ref totalPointCount, ref totalSegmentCount, ref j);
}
}
Meta.TotalSegmentCount = totalSegmentCount;
Meta.TotalPointCount = totalPointCount;
UserData = new SerializableUserData[Meta.UserDataCount];
var totalUserDataSize = 0;
for (var i = 0; i < Meta.UserDataCount; i++)
{
var @event = animation.Events[i];
UserData[i] = new SerializableUserData
{
Time = @event.time,
Value = @event.value
};
totalUserDataSize += @event.value.Length;
}
Meta.TotalUserDataSize = totalUserDataSize;
}
}
}

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Linq;
using AssetStudio;
namespace CubismLive2DExtractor
{
public sealed class CubismObjectList
{
public static SerializedFile AssetsFile { get; set; }
public HashSet<ObjectData> CubismExpressionObjects { get; set; }
public HashSet<ObjectData> CubismFadeMotionObjects { get; set; }
public class ObjectData
{
private long _pathID;
public Object Asset { get; set; }
public int m_FileID { get; set; }
public long m_PathID
{
get => _pathID;
set
{
_pathID = value;
Asset = GetObjByPathID(_pathID);
}
}
public override bool Equals(object obj)
{
return obj is ObjectData objectData && _pathID == objectData.m_PathID;
}
public override int GetHashCode()
{
return _pathID.GetHashCode();
}
}
public List<MonoBehaviour> GetFadeMotionAssetList()
{
return CubismFadeMotionObjects?.Where(x => x.Asset != null).Select(x => (MonoBehaviour)x.Asset).ToList();
}
public List<MonoBehaviour> GetExpressionList()
{
return CubismExpressionObjects?.Where(x => x.Asset != null).Select(x => (MonoBehaviour)x.Asset).ToList();
}
private static Object GetObjByPathID(long pathID)
{
var assetFileList = AssetsFile.assetsManager.assetsFileList;
foreach (var assetFile in assetFileList)
{
if (assetFile.ObjectsDic.TryGetValue(pathID, out var obj))
{
return obj;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.Collections.Specialized;
using System.Linq;
using AssetStudio;
using Newtonsoft.Json;
namespace CubismLive2DExtractor
{
public static class CubismParsers
{
public enum CubismMonoBehaviourType
{
FadeMotionList,
FadeMotion,
Expression,
Physics,
DisplayInfo,
}
public static string ParsePhysics(OrderedDictionary physicsDict)
{
var cubismPhysicsRig = JsonConvert.DeserializeObject<CubismPhysics>(JsonConvert.SerializeObject(physicsDict))._rig;
var physicsSettings = new CubismPhysics3Json.SerializablePhysicsSettings[cubismPhysicsRig.SubRigs.Length];
for (int i = 0; i < physicsSettings.Length; i++)
{
var subRigs = cubismPhysicsRig.SubRigs[i];
physicsSettings[i] = new CubismPhysics3Json.SerializablePhysicsSettings
{
Id = $"PhysicsSetting{i + 1}",
Input = new CubismPhysics3Json.SerializableInput[subRigs.Input.Length],
Output = new CubismPhysics3Json.SerializableOutput[subRigs.Output.Length],
Vertices = new CubismPhysics3Json.SerializableVertex[subRigs.Particles.Length],
Normalization = new CubismPhysics3Json.SerializableNormalization
{
Position = new CubismPhysics3Json.SerializableNormalizationValue
{
Minimum = subRigs.Normalization.Position.Minimum,
Default = subRigs.Normalization.Position.Default,
Maximum = subRigs.Normalization.Position.Maximum
},
Angle = new CubismPhysics3Json.SerializableNormalizationValue
{
Minimum = subRigs.Normalization.Angle.Minimum,
Default = subRigs.Normalization.Angle.Default,
Maximum = subRigs.Normalization.Angle.Maximum
}
}
};
for (int j = 0; j < subRigs.Input.Length; j++)
{
var input = subRigs.Input[j];
physicsSettings[i].Input[j] = new CubismPhysics3Json.SerializableInput
{
Source = new CubismPhysics3Json.SerializableParameter
{
Target = "Parameter", //同名GameObject父节点的名称
Id = input.SourceId
},
Weight = input.Weight,
Type = Enum.GetName(typeof(CubismPhysicsSourceComponent), input.SourceComponent),
Reflect = input.IsInverted
};
}
for (int j = 0; j < subRigs.Output.Length; j++)
{
var output = subRigs.Output[j];
physicsSettings[i].Output[j] = new CubismPhysics3Json.SerializableOutput
{
Destination = new CubismPhysics3Json.SerializableParameter
{
Target = "Parameter", //同名GameObject父节点的名称
Id = output.DestinationId
},
VertexIndex = output.ParticleIndex,
Scale = output.AngleScale,
Weight = output.Weight,
Type = Enum.GetName(typeof(CubismPhysicsSourceComponent), output.SourceComponent),
Reflect = output.IsInverted
};
}
for (int j = 0; j < subRigs.Particles.Length; j++)
{
var particles = subRigs.Particles[j];
physicsSettings[i].Vertices[j] = new CubismPhysics3Json.SerializableVertex
{
Position = particles.InitialPosition,
Mobility = particles.Mobility,
Delay = particles.Delay,
Acceleration = particles.Acceleration,
Radius = particles.Radius
};
}
}
var physicsDictionary = new CubismPhysics3Json.SerializablePhysicsDictionary[physicsSettings.Length];
for (int i = 0; i < physicsSettings.Length; i++)
{
physicsDictionary[i] = new CubismPhysics3Json.SerializablePhysicsDictionary
{
Id = $"PhysicsSetting{i + 1}",
Name = $"Dummy{i + 1}"
};
}
var physicsJson = new CubismPhysics3Json
{
Version = 3,
Meta = new CubismPhysics3Json.SerializableMeta
{
PhysicsSettingCount = cubismPhysicsRig.SubRigs.Length,
TotalInputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Input.Length),
TotalOutputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Output.Length),
VertexCount = cubismPhysicsRig.SubRigs.Sum(x => x.Particles.Length),
EffectiveForces = new CubismPhysics3Json.SerializableEffectiveForces
{
Gravity = cubismPhysicsRig.Gravity,
Wind = cubismPhysicsRig.Wind
},
PhysicsDictionary = physicsDictionary
},
PhysicsSettings = physicsSettings
};
return JsonConvert.SerializeObject(physicsJson, Formatting.Indented, new MyJsonConverter2());
}
public static OrderedDictionary ParseMonoBehaviour(MonoBehaviour m_MonoBehaviour, CubismMonoBehaviourType cubismMonoBehaviourType, AssemblyLoader assemblyLoader)
{
var orderedDict = m_MonoBehaviour.ToType();
if (orderedDict != null)
return orderedDict;
var fieldName = "";
var m_Type = m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
switch (cubismMonoBehaviourType)
{
case CubismMonoBehaviourType.FadeMotionList:
fieldName = "cubismfademotionobjects";
break;
case CubismMonoBehaviourType.FadeMotion:
fieldName = "parameterids";
break;
case CubismMonoBehaviourType.Expression:
fieldName = "parameters";
break;
case CubismMonoBehaviourType.Physics:
fieldName = "_rig";
break;
case CubismMonoBehaviourType.DisplayInfo:
fieldName = "name";
break;
}
if (m_Type.m_Nodes.FindIndex(x => x.m_Name.ToLower() == fieldName) < 0)
{
m_MonoBehaviour.m_Script.TryGet(out var m_MonoScript);
var assetName = m_MonoBehaviour.m_Name != "" ? m_MonoBehaviour.m_Name : m_MonoScript.m_ClassName;
Logger.Warning($"{cubismMonoBehaviourType} asset \"{assetName}\" is not readable");
return null;
}
orderedDict = m_MonoBehaviour.ToType(m_Type);
return orderedDict;
}
}
}

View File

@@ -1,301 +1,405 @@
////
// Based on UnityLive2DExtractorMod by aelurum
// https://github.com/aelurum/UnityLive2DExtractor
//
// Original version - by Perfare
// Based on UnityLive2DExtractor by Perfare
// https://github.com/Perfare/UnityLive2DExtractor
////
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AssetStudio;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static CubismLive2DExtractor.CubismParsers;
namespace CubismLive2DExtractor
{
public static class Live2DExtractor
public sealed class Live2DExtractor
{
public static void ExtractLive2D(IGrouping<string, AssetStudio.Object> assets, string destPath, string modelName, AssemblyLoader assemblyLoader)
{
var destTexturePath = Path.Combine(destPath, "textures") + Path.DirectorySeparatorChar;
var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar;
var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar;
Directory.CreateDirectory(destPath);
Directory.CreateDirectory(destTexturePath);
private List<MonoBehaviour> Expressions { get; set; }
private List<MonoBehaviour> FadeMotions { get; set; }
private List<GameObject> GameObjects { get; set; }
private List<AnimationClip> AnimationClips { get; set; }
private List<Texture2D> Texture2Ds { get; set; }
private HashSet<string> EyeBlinkParameters { get; set; }
private HashSet<string> LipSyncParameters { get; set; }
private HashSet<string> ParameterNames { get; set; }
private HashSet<string> PartNames { get; set; }
private MonoBehaviour MocMono { get; set; }
private MonoBehaviour PhysicsMono { get; set; }
private MonoBehaviour FadeMotionLst { get; set; }
private List<MonoBehaviour> ParametersCdi { get; set; }
private List<MonoBehaviour> PartsCdi { get; set; }
var monoBehaviours = new List<MonoBehaviour>();
var texture2Ds = new List<Texture2D>();
var gameObjects = new List<GameObject>();
var animationClips = new List<AnimationClip>();
public Live2DExtractor(IGrouping<string, AssetStudio.Object> assets, List<AnimationClip> inClipMotions = null, List<MonoBehaviour> inFadeMotions = null, MonoBehaviour inFadeMotionLst = null)
{
Expressions = new List<MonoBehaviour>();
FadeMotions = inFadeMotions ?? new List<MonoBehaviour>();
AnimationClips = inClipMotions ?? new List<AnimationClip>();
GameObjects = new List<GameObject>();
Texture2Ds = new List<Texture2D>();
EyeBlinkParameters = new HashSet<string>();
LipSyncParameters = new HashSet<string>();
ParameterNames = new HashSet<string>();
PartNames = new HashSet<string>();
FadeMotionLst = inFadeMotionLst;
ParametersCdi = new List<MonoBehaviour>();
PartsCdi = new List<MonoBehaviour>();
Logger.Debug("Sorting model assets..");
foreach (var asset in assets)
{
switch (asset)
{
case MonoBehaviour m_MonoBehaviour:
monoBehaviours.Add(m_MonoBehaviour);
break;
case Texture2D m_Texture2D:
texture2Ds.Add(m_Texture2D);
break;
case GameObject m_GameObject:
gameObjects.Add(m_GameObject);
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{
switch (m_Script.m_ClassName)
{
case "CubismMoc":
MocMono = m_MonoBehaviour;
break;
case "CubismPhysicsController":
PhysicsMono = m_MonoBehaviour;
break;
case "CubismExpressionData":
Expressions.Add(m_MonoBehaviour);
break;
case "CubismFadeMotionData":
if (inFadeMotions == null && inFadeMotionLst == null)
{
FadeMotions.Add(m_MonoBehaviour);
}
break;
case "CubismFadeMotionList":
if (inFadeMotions == null && inFadeMotionLst == null)
{
FadeMotionLst = m_MonoBehaviour;
}
break;
case "CubismEyeBlinkParameter":
if (m_MonoBehaviour.m_GameObject.TryGet(out var blinkGameObject))
{
EyeBlinkParameters.Add(blinkGameObject.m_Name);
}
break;
case "CubismMouthParameter":
if (m_MonoBehaviour.m_GameObject.TryGet(out var mouthGameObject))
{
LipSyncParameters.Add(mouthGameObject.m_Name);
}
break;
case "CubismParameter":
if (m_MonoBehaviour.m_GameObject.TryGet(out var paramGameObject))
{
ParameterNames.Add(paramGameObject.m_Name);
}
break;
case "CubismPart":
if (m_MonoBehaviour.m_GameObject.TryGet(out var partGameObject))
{
PartNames.Add(partGameObject.m_Name);
}
break;
case "CubismDisplayInfoParameterName":
if (m_MonoBehaviour.m_GameObject.TryGet(out _))
{
ParametersCdi.Add(m_MonoBehaviour);
}
break;
case "CubismDisplayInfoPartName":
if (m_MonoBehaviour.m_GameObject.TryGet(out _))
{
PartsCdi.Add(m_MonoBehaviour);
}
break;
}
}
break;
case AnimationClip m_AnimationClip:
animationClips.Add(m_AnimationClip);
if (inClipMotions == null)
{
AnimationClips.Add(m_AnimationClip);
}
break;
case GameObject m_GameObject:
GameObjects.Add(m_GameObject);
break;
case Texture2D m_Texture2D:
Texture2Ds.Add(m_Texture2D);
break;
}
}
}
//physics
var physics = monoBehaviours.FirstOrDefault(x =>
public void ExtractCubismModel(string destPath, string modelName, Live2DMotionMode motionMode, AssemblyLoader assemblyLoader, bool forceBezier = false, int parallelTaskCount = 1)
{
Directory.CreateDirectory(destPath);
#region moc3
using (var cubismModel = new CubismModel(MocMono))
{
if (x.m_Script.TryGet(out var m_Script))
var sb = new StringBuilder();
sb.AppendLine("Model Stats:");
sb.AppendLine($"SDK Version: {cubismModel.VersionDescription}");
if (cubismModel.Version > 0)
{
return m_Script.m_ClassName == "CubismPhysicsController";
sb.AppendLine($"Canvas Width: {cubismModel.CanvasWidth}");
sb.AppendLine($"Canvas Height: {cubismModel.CanvasHeight}");
sb.AppendLine($"Center X: {cubismModel.CentralPosX}");
sb.AppendLine($"Center Y: {cubismModel.CentralPosY}");
sb.AppendLine($"Pixel Per Unit: {cubismModel.PixelPerUnit}");
sb.AppendLine($"Part Count: {cubismModel.PartCount}");
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
Logger.Debug(sb.ToString());
ParameterNames = cubismModel.ParamNames;
PartNames = cubismModel.PartNames;
}
return false;
});
if (physics != null)
cubismModel.SaveMoc3($"{destPath}{modelName}.moc3");
}
#endregion
#region textures
var textures = new SortedSet<string>();
var destTexturePath = Path.Combine(destPath, "textures") + Path.DirectorySeparatorChar;
if (Texture2Ds.Count == 0)
{
try
{
var buff = ParsePhysics(physics, assemblyLoader);
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
}
catch (Exception e)
{
Logger.Warning($"Error in parsing physics data: {e.Message}");
physics = null;
}
Logger.Warning($"No textures found for \"{modelName}\" model");
}
else
{
Directory.CreateDirectory(destTexturePath);
}
//moc
var moc = monoBehaviours.First(x =>
var textureBag = new ConcurrentBag<string>();
var savePathHash = new ConcurrentDictionary<string, bool>();
Parallel.ForEach(Texture2Ds, new ParallelOptions { MaxDegreeOfParallelism = parallelTaskCount }, texture2D =>
{
if (x.m_Script.TryGet(out var m_Script))
{
return m_Script.m_ClassName == "CubismMoc";
}
return false;
});
File.WriteAllBytes($"{destPath}{modelName}.moc3", ParseMoc(moc));
var savePath = $"{destTexturePath}{texture2D.m_Name}.png";
if (!savePathHash.TryAdd(savePath, true))
return;
//texture
var textures = new SortedSet<string>();
foreach (var texture2D in texture2Ds)
{
using (var image = texture2D.ConvertToImage(flip: true))
{
textures.Add($"textures/{texture2D.m_Name}.png");
using (var file = File.OpenWrite($"{destTexturePath}{texture2D.m_Name}.png"))
using (var file = File.OpenWrite(savePath))
{
image.WriteToStream(file, ImageFormat.Png);
}
textureBag.Add($"textures/{texture2D.m_Name}.png");
}
}
});
textures.UnionWith(textureBag);
#endregion
//motion
var motions = new SortedDictionary<string, JArray>();
if (gameObjects.Count > 0)
#region physics3.json
if (PhysicsMono != null)
{
var rootTransform = gameObjects[0].m_Transform;
while (rootTransform.m_Father.TryGet(out var m_Father))
var physicsDict = ParseMonoBehaviour(PhysicsMono, CubismMonoBehaviourType.Physics, assemblyLoader);
if (physicsDict != null)
{
rootTransform = m_Father;
}
rootTransform.m_GameObject.TryGet(out var rootGameObject);
var converter = new CubismMotion3Converter(rootGameObject, animationClips.ToArray());
if (converter.AnimationList.Count > 0)
{
Directory.CreateDirectory(destMotionPath);
}
foreach (ImportedKeyframedAnimation animation in converter.AnimationList)
{
var json = new CubismMotion3Json
try
{
Version = 3,
Meta = new CubismMotion3Json.SerializableMeta
{
Duration = animation.Duration,
Fps = animation.SampleRate,
Loop = true,
AreBeziersRestricted = true,
CurveCount = animation.TrackList.Count,
UserDataCount = animation.Events.Count
},
Curves = new CubismMotion3Json.SerializableCurve[animation.TrackList.Count]
};
int totalSegmentCount = 1;
int totalPointCount = 1;
for (int i = 0; i < animation.TrackList.Count; i++)
{
var track = animation.TrackList[i];
json.Curves[i] = new CubismMotion3Json.SerializableCurve
{
Target = track.Target,
Id = track.Name,
Segments = new List<float> { 0f, track.Curve[0].value }
};
for (var j = 1; j < track.Curve.Count; j++)
{
var curve = track.Curve[j];
var preCurve = track.Curve[j - 1];
if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) //InverseSteppedSegment
{
var nextCurve = track.Curve[j + 1];
if (nextCurve.value == curve.value)
{
json.Curves[i].Segments.Add(3f);
json.Curves[i].Segments.Add(nextCurve.time);
json.Curves[i].Segments.Add(nextCurve.value);
j += 1;
totalPointCount += 1;
totalSegmentCount++;
continue;
}
}
if (float.IsPositiveInfinity(curve.inSlope)) //SteppedSegment
{
json.Curves[i].Segments.Add(2f);
json.Curves[i].Segments.Add(curve.time);
json.Curves[i].Segments.Add(curve.value);
totalPointCount += 1;
}
else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f) //LinearSegment
{
json.Curves[i].Segments.Add(0f);
json.Curves[i].Segments.Add(curve.time);
json.Curves[i].Segments.Add(curve.value);
totalPointCount += 1;
}
else //BezierSegment
{
var tangentLength = (curve.time - preCurve.time) / 3f;
json.Curves[i].Segments.Add(1f);
json.Curves[i].Segments.Add(preCurve.time + tangentLength);
json.Curves[i].Segments.Add(preCurve.outSlope * tangentLength + preCurve.value);
json.Curves[i].Segments.Add(curve.time - tangentLength);
json.Curves[i].Segments.Add(curve.value - curve.inSlope * tangentLength);
json.Curves[i].Segments.Add(curve.time);
json.Curves[i].Segments.Add(curve.value);
totalPointCount += 3;
}
totalSegmentCount++;
}
var buff = ParsePhysics(physicsDict);
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
}
json.Meta.TotalSegmentCount = totalSegmentCount;
json.Meta.TotalPointCount = totalPointCount;
json.UserData = new CubismMotion3Json.SerializableUserData[animation.Events.Count];
var totalUserDataSize = 0;
for (var i = 0; i < animation.Events.Count; i++)
catch (Exception e)
{
var @event = animation.Events[i];
json.UserData[i] = new CubismMotion3Json.SerializableUserData
{
Time = @event.time,
Value = @event.value
};
totalUserDataSize += @event.value.Length;
Logger.Warning($"Error in parsing physics data: {e.Message}");
PhysicsMono = null;
}
json.Meta.TotalUserDataSize = totalUserDataSize;
var motionPath = new JObject(new JProperty("File", $"motions/{animation.Name}.motion3.json"));
motions.Add(animation.Name, new JArray(motionPath));
File.WriteAllText($"{destMotionPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter()));
}
else
{
PhysicsMono = null;
}
}
#endregion
//expression
#region cdi3.json
var isCdiParsed = false;
if (ParametersCdi.Count > 0 || PartsCdi.Count > 0)
{
var cdiJson = new CubismCdi3Json
{
Version = 3,
ParameterGroups = Array.Empty<CubismCdi3Json.ParamGroupArray>()
};
var parameters = new SortedSet<CubismCdi3Json.ParamGroupArray>();
foreach (var paramMono in ParametersCdi)
{
var displayName = GetDisplayName(paramMono, assemblyLoader);
if (displayName == null)
break;
paramMono.m_GameObject.TryGet(out var paramGameObject);
var paramId = paramGameObject.m_Name;
parameters.Add(new CubismCdi3Json.ParamGroupArray
{
Id = paramId,
GroupId = "",
Name = displayName
});
}
cdiJson.Parameters = parameters.ToArray();
var parts = new SortedSet<CubismCdi3Json.PartArray>();
foreach (var partMono in PartsCdi)
{
var displayName = GetDisplayName(partMono, assemblyLoader);
if (displayName == null)
break;
partMono.m_GameObject.TryGet(out var partGameObject);
var paramId = partGameObject.m_Name;
parts.Add(new CubismCdi3Json.PartArray
{
Id = paramId,
Name = displayName
});
}
cdiJson.Parts = parts.ToArray();
if (parts.Count > 0 || parameters.Count > 0)
{
File.WriteAllText($"{destPath}{modelName}.cdi3.json", JsonConvert.SerializeObject(cdiJson, Formatting.Indented));
isCdiParsed = true;
}
}
#endregion
#region motion3.json
var motions = new SortedDictionary<string, JArray>();
var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar;
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotionLst != null) //Fade motions from Fade Motion List
{
Logger.Debug("Motion export method: MonoBehaviour (Fade motion)");
var fadeMotionLstDict = ParseMonoBehaviour(FadeMotionLst, CubismMonoBehaviourType.FadeMotionList, assemblyLoader);
if (fadeMotionLstDict != null)
{
CubismObjectList.AssetsFile = FadeMotionLst.assetsFile;
var fadeMotionAssetList = JsonConvert.DeserializeObject<CubismObjectList>(JsonConvert.SerializeObject(fadeMotionLstDict)).GetFadeMotionAssetList();
if (fadeMotionAssetList?.Count > 0)
{
FadeMotions = fadeMotionAssetList;
Logger.Debug($"\"{FadeMotionLst.m_Name}\": found {fadeMotionAssetList.Count} motion(s)");
}
}
}
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotions.Count > 0) //motion from MonoBehaviour
{
ExportFadeMotions(destMotionPath, assemblyLoader, forceBezier, motions);
}
if (motions.Count == 0) //motion from AnimationClip
{
CubismMotion3Converter converter = null;
var exportMethod = "AnimationClip";
if (motionMode != Live2DMotionMode.AnimationClipV1) //AnimationClipV2
{
exportMethod += "V2";
converter = new CubismMotion3Converter(AnimationClips, PartNames, ParameterNames);
}
else if (GameObjects.Count > 0) //AnimationClipV1
{
exportMethod += "V1";
var rootTransform = GameObjects[0].m_Transform;
while (rootTransform.m_Father.TryGet(out var m_Father))
{
rootTransform = m_Father;
}
rootTransform.m_GameObject.TryGet(out var rootGameObject);
converter = new CubismMotion3Converter(rootGameObject, AnimationClips);
}
if (motionMode == Live2DMotionMode.MonoBehaviour)
{
exportMethod = FadeMotions.Count > 0
? exportMethod + " (unable to export motions using Fade motion method)"
: exportMethod + " (no Fade motions found)";
}
Logger.Debug($"Motion export method: {exportMethod}");
ExportClipMotions(destMotionPath, converter, forceBezier, motions);
}
if (motions.Count == 0)
{
Logger.Warning($"No exportable motions found for \"{modelName}\" model");
}
else
{
Logger.Info($"Exported {motions.Count} motion(s)");
}
#endregion
#region exp3.json
var expressions = new JArray();
var monoBehaviourArray = monoBehaviours.Where(x => x.m_Name.EndsWith(".exp3")).ToArray();
if (monoBehaviourArray.Length > 0)
var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar;
if (Expressions.Count > 0)
{
Directory.CreateDirectory(destExpressionPath);
}
foreach (var monoBehaviour in monoBehaviourArray)
foreach (var monoBehaviour in Expressions)
{
var fullName = monoBehaviour.m_Name;
var expressionName = fullName.Replace(".exp3", "");
var expressionObj = monoBehaviour.ToType();
if (expressionObj == null)
{
var m_Type = monoBehaviour.ConvertToTypeTree(assemblyLoader);
expressionObj = monoBehaviour.ToType(m_Type);
if (expressionObj == null)
{
Logger.Warning($"Expression \"{expressionName}\" is not readable.");
continue;
}
}
var expression = JsonConvert.DeserializeObject<CubismExpression3Json>(JsonConvert.SerializeObject(expressionObj));
var expressionName = monoBehaviour.m_Name.Replace(".exp3", "");
var expressionDict = ParseMonoBehaviour(monoBehaviour, CubismMonoBehaviourType.Expression, assemblyLoader);
if (expressionDict == null)
continue;
var expression = JsonConvert.DeserializeObject<CubismExpression3Json>(JsonConvert.SerializeObject(expressionDict));
expressions.Add(new JObject
{
{ "Name", expressionName },
{ "File", $"expressions/{fullName}.json" }
});
File.WriteAllText($"{destExpressionPath}{fullName}.json", JsonConvert.SerializeObject(expression, Formatting.Indented));
{
{ "Name", expressionName },
{ "File", $"expressions/{expressionName}.exp3.json" }
});
File.WriteAllText($"{destExpressionPath}{expressionName}.exp3.json", JsonConvert.SerializeObject(expression, Formatting.Indented));
}
#endregion
//model
#region model3.json
var groups = new List<CubismModel3Json.SerializableGroup>();
var eyeBlinkParameters = monoBehaviours.Where(x =>
//Try looking for group IDs among the parameter names manually
if (EyeBlinkParameters.Count == 0)
{
x.m_Script.TryGet(out var m_Script);
return m_Script?.m_ClassName == "CubismEyeBlinkParameter";
}).Select(x =>
{
x.m_GameObject.TryGet(out var m_GameObject);
return m_GameObject?.m_Name;
}).ToHashSet();
if (eyeBlinkParameters.Count == 0)
{
eyeBlinkParameters = gameObjects.Where(x =>
{
return x.m_Name.ToLower().Contains("eye")
&& x.m_Name.ToLower().Contains("open")
&& (x.m_Name.ToLower().Contains('l') || x.m_Name.ToLower().Contains('r'));
}).Select(x => x.m_Name).ToHashSet();
EyeBlinkParameters = ParameterNames.Where(x =>
x.ToLower().Contains("eye")
&& x.ToLower().Contains("open")
&& (x.ToLower().Contains('l') || x.ToLower().Contains('r'))
).ToHashSet();
}
if (LipSyncParameters.Count == 0)
{
LipSyncParameters = ParameterNames.Where(x =>
x.ToLower().Contains("mouth")
&& x.ToLower().Contains("open")
&& x.ToLower().Contains('y')
).ToHashSet();
}
groups.Add(new CubismModel3Json.SerializableGroup
{
Target = "Parameter",
Name = "EyeBlink",
Ids = eyeBlinkParameters.ToArray()
Ids = EyeBlinkParameters.ToArray()
});
var lipSyncParameters = monoBehaviours.Where(x =>
{
x.m_Script.TryGet(out var m_Script);
return m_Script?.m_ClassName == "CubismMouthParameter";
}).Select(x =>
{
x.m_GameObject.TryGet(out var m_GameObject);
return m_GameObject?.m_Name;
}).ToHashSet();
if (lipSyncParameters.Count == 0)
{
lipSyncParameters = gameObjects.Where(x =>
{
return x.m_Name.ToLower().Contains("mouth")
&& x.m_Name.ToLower().Contains("open")
&& x.m_Name.ToLower().Contains('y');
}).Select(x => x.m_Name).ToHashSet();
}
groups.Add(new CubismModel3Json.SerializableGroup
{
Target = "Parameter",
Name = "LipSync",
Ids = lipSyncParameters.ToArray()
Ids = LipSyncParameters.ToArray()
});
var model3 = new CubismModel3Json
{
Version = 3,
@@ -304,140 +408,90 @@ namespace CubismLive2DExtractor
{
Moc = $"{modelName}.moc3",
Textures = textures.ToArray(),
DisplayInfo = isCdiParsed ? $"{modelName}.cdi3.json" : null,
Physics = PhysicsMono != null ? $"{modelName}.physics3.json" : null,
Motions = JObject.FromObject(motions),
Expressions = expressions,
},
Groups = groups.ToArray()
};
if (physics != null)
{
model3.FileReferences.Physics = $"{modelName}.physics3.json";
}
File.WriteAllText($"{destPath}{modelName}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented));
#endregion
}
private static string ParsePhysics(MonoBehaviour physics, AssemblyLoader assemblyLoader)
private void ExportFadeMotions(string destMotionPath, AssemblyLoader assemblyLoader, bool forceBezier, SortedDictionary<string, JArray> motions)
{
var physicsObj = physics.ToType();
if (physicsObj == null)
Directory.CreateDirectory(destMotionPath);
foreach (var fadeMotionMono in FadeMotions)
{
var m_Type = physics.ConvertToTypeTree(assemblyLoader);
physicsObj = physics.ToType(m_Type);
if (physicsObj == null)
{
throw new Exception("MonoBehaviour is not readable.");
}
}
var cubismPhysicsRig = JsonConvert.DeserializeObject<CubismPhysics>(JsonConvert.SerializeObject(physicsObj))._rig;
var fadeMotionDict = ParseMonoBehaviour(fadeMotionMono, CubismMonoBehaviourType.FadeMotion, assemblyLoader);
if (fadeMotionDict == null)
continue;
var fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotion>(JsonConvert.SerializeObject(fadeMotionDict));
if (fadeMotion.ParameterIds.Length == 0)
continue;
var physicsSettings = new CubismPhysics3Json.SerializablePhysicsSettings[cubismPhysicsRig.SubRigs.Length];
for (int i = 0; i < physicsSettings.Length; i++)
{
var subRigs = cubismPhysicsRig.SubRigs[i];
physicsSettings[i] = new CubismPhysics3Json.SerializablePhysicsSettings
var motionJson = new CubismMotion3Json(fadeMotion, ParameterNames, PartNames, forceBezier);
var animName = Path.GetFileNameWithoutExtension(fadeMotion.m_Name);
if (motions.ContainsKey(animName))
{
Id = $"PhysicsSetting{i + 1}",
Input = new CubismPhysics3Json.SerializableInput[subRigs.Input.Length],
Output = new CubismPhysics3Json.SerializableOutput[subRigs.Output.Length],
Vertices = new CubismPhysics3Json.SerializableVertex[subRigs.Particles.Length],
Normalization = new CubismPhysics3Json.SerializableNormalization
{
Position = new CubismPhysics3Json.SerializableNormalizationValue
{
Minimum = subRigs.Normalization.Position.Minimum,
Default = subRigs.Normalization.Position.Default,
Maximum = subRigs.Normalization.Position.Maximum
},
Angle = new CubismPhysics3Json.SerializableNormalizationValue
{
Minimum = subRigs.Normalization.Angle.Minimum,
Default = subRigs.Normalization.Angle.Default,
Maximum = subRigs.Normalization.Angle.Maximum
}
}
};
for (int j = 0; j < subRigs.Input.Length; j++)
{
var input = subRigs.Input[j];
physicsSettings[i].Input[j] = new CubismPhysics3Json.SerializableInput
{
Source = new CubismPhysics3Json.SerializableParameter
{
Target = "Parameter", //同名GameObject父节点的名称
Id = input.SourceId
},
Weight = input.Weight,
Type = Enum.GetName(typeof(CubismPhysicsSourceComponent), input.SourceComponent),
Reflect = input.IsInverted
};
}
for (int j = 0; j < subRigs.Output.Length; j++)
{
var output = subRigs.Output[j];
physicsSettings[i].Output[j] = new CubismPhysics3Json.SerializableOutput
{
Destination = new CubismPhysics3Json.SerializableParameter
{
Target = "Parameter", //同名GameObject父节点的名称
Id = output.DestinationId
},
VertexIndex = output.ParticleIndex,
Scale = output.AngleScale,
Weight = output.Weight,
Type = Enum.GetName(typeof(CubismPhysicsSourceComponent), output.SourceComponent),
Reflect = output.IsInverted
};
}
for (int j = 0; j < subRigs.Particles.Length; j++)
{
var particles = subRigs.Particles[j];
physicsSettings[i].Vertices[j] = new CubismPhysics3Json.SerializableVertex
{
Position = particles.InitialPosition,
Mobility = particles.Mobility,
Delay = particles.Delay,
Acceleration = particles.Acceleration,
Radius = particles.Radius
};
animName = $"{animName}_{fadeMotion.GetHashCode()}";
if (motions.ContainsKey(animName))
continue;
}
var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json"));
motions.Add(animName, new JArray(motionPath));
File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter()));
}
var physicsDictionary = new CubismPhysics3Json.SerializablePhysicsDictionary[physicsSettings.Length];
for (int i = 0; i < physicsSettings.Length; i++)
{
physicsDictionary[i] = new CubismPhysics3Json.SerializablePhysicsDictionary
{
Id = $"PhysicsSetting{i + 1}",
Name = $"Dummy{i + 1}"
};
}
var physicsJson = new CubismPhysics3Json
{
Version = 3,
Meta = new CubismPhysics3Json.SerializableMeta
{
PhysicsSettingCount = cubismPhysicsRig.SubRigs.Length,
TotalInputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Input.Length),
TotalOutputCount = cubismPhysicsRig.SubRigs.Sum(x => x.Output.Length),
VertexCount = cubismPhysicsRig.SubRigs.Sum(x => x.Particles.Length),
EffectiveForces = new CubismPhysics3Json.SerializableEffectiveForces
{
Gravity = cubismPhysicsRig.Gravity,
Wind = cubismPhysicsRig.Wind
},
PhysicsDictionary = physicsDictionary
},
PhysicsSettings = physicsSettings
};
return JsonConvert.SerializeObject(physicsJson, Formatting.Indented, new MyJsonConverter2());
}
private static byte[] ParseMoc(MonoBehaviour moc)
private static void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, bool forceBezier, SortedDictionary<string, JArray> motions)
{
var reader = moc.reader;
reader.Reset();
reader.Position += 28; //PPtr<GameObject> m_GameObject, m_Enabled, PPtr<MonoScript>
reader.ReadAlignedString(); //m_Name
return reader.ReadBytes(reader.ReadInt32());
if (converter == null)
return;
if (converter.AnimationList.Count > 0)
{
Directory.CreateDirectory(destMotionPath);
}
foreach (var animation in converter.AnimationList)
{
var animName = animation.Name;
if (animation.TrackList.Count == 0)
{
Logger.Warning($"Motion \"{animName}\" is empty. Export skipped");
continue;
}
var motionJson = new CubismMotion3Json(animation, forceBezier);
if (motions.ContainsKey(animName))
{
animName = $"{animName}_{animation.GetHashCode()}";
if (motions.ContainsKey(animName))
continue;
}
var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json"));
motions.Add(animName, new JArray(motionPath));
File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter()));
}
}
private static string GetDisplayName(MonoBehaviour cdiMono, AssemblyLoader assemblyLoader)
{
var dict = ParseMonoBehaviour(cdiMono, CubismMonoBehaviourType.DisplayInfo, assemblyLoader);
if (dict == null)
return null;
var name = (string)dict["Name"];
if (dict.Contains("DisplayName"))
{
var displayName = (string)dict["DisplayName"];
name = displayName != "" ? displayName : name;
}
return name;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace CubismLive2DExtractor
{
public enum Live2DMotionMode
{
MonoBehaviour,
AnimationClipV1,
AnimationClipV2,
}
}

View File

@@ -16,7 +16,7 @@ namespace AssetStudio
private ImageFormat imageFormat;
private Avatar avatar;
private HashSet<AnimationClip> animationClipHashSet = new HashSet<AnimationClip>();
private AnimationClip[] animationClipUniqArray = Array.Empty<AnimationClip>(); //TODO: a proper AnimationClip equality comparer
private Dictionary<AnimationClip, string> boundAnimationPathDic = new Dictionary<AnimationClip, string>();
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
private Dictionary<Texture2D, string> textureNameDictionary = new Dictionary<Texture2D, string>();
@@ -40,10 +40,7 @@ namespace AssetStudio
}
if (animationList != null)
{
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
animationClipUniqArray = animationList.Distinct().ToArray();
}
ConvertAnimations();
}
@@ -70,10 +67,7 @@ namespace AssetStudio
}
if (animationList != null)
{
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
animationClipUniqArray = animationList.Distinct().ToArray();
}
ConvertAnimations();
}
@@ -88,10 +82,7 @@ namespace AssetStudio
}
else
{
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
animationClipUniqArray = animationList.Distinct().ToArray();
}
ConvertAnimations();
}
@@ -160,6 +151,7 @@ namespace AssetStudio
if (m_GameObject.m_Animation != null)
{
var animationList = new List<AnimationClip>();
foreach (var animation in m_GameObject.m_Animation.m_Animations)
{
if (animation.TryGet(out var animationClip))
@@ -168,9 +160,10 @@ namespace AssetStudio
{
boundAnimationPathDic.Add(animationClip, GetTransformPath(m_Transform));
}
animationClipHashSet.Add(animationClip);
animationList.Add(animationClip);
}
}
animationClipUniqArray = animationList.Distinct().ToArray();
}
foreach (var pptr in m_Transform.m_Children)
@@ -184,6 +177,7 @@ namespace AssetStudio
{
if (m_Animator.m_Controller.TryGet(out var m_Controller))
{
var animationList = new List<AnimationClip>();
switch (m_Controller)
{
case AnimatorOverrideController m_AnimatorOverrideController:
@@ -194,7 +188,7 @@ namespace AssetStudio
{
if (pptr.TryGet(out var m_AnimationClip))
{
animationClipHashSet.Add(m_AnimationClip);
animationList.Add(m_AnimationClip);
}
}
}
@@ -207,12 +201,13 @@ namespace AssetStudio
{
if (pptr.TryGet(out var m_AnimationClip))
{
animationClipHashSet.Add(m_AnimationClip);
animationList.Add(m_AnimationClip);
}
}
break;
}
}
animationClipUniqArray = animationList.Distinct().ToArray();
}
}
@@ -371,6 +366,7 @@ namespace AssetStudio
{
if (iMesh.hasUV[uv])
{
c = 4;
var m_UV = mesh.GetUV(uv);
if (m_UV.Length == mesh.m_VertexCount * 2)
{
@@ -769,7 +765,7 @@ namespace AssetStudio
private void ConvertAnimations()
{
foreach (var animationClip in animationClipHashSet)
foreach (var animationClip in animationClipUniqArray)
{
var iAnim = new ImportedKeyframedAnimation();
var name = animationClip.m_Name;
@@ -877,7 +873,7 @@ namespace AssetStudio
}
else
{
var m_Clip = animationClip.m_MuscleClip.m_Clip;
var m_Clip = animationClip.m_MuscleClip.m_Clip.data;
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
var m_ClipBindingConstant = animationClip.m_ClipBindingConstant ?? m_Clip.ConvertValueArrayToGenericBinding();
for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++)
@@ -1016,18 +1012,16 @@ namespace AssetStudio
private void CreateBonePathHash(Transform m_Transform)
{
var name = GetTransformPathByFather(m_Transform);
var crc = new SevenZip.CRC();
var bytes = Encoding.UTF8.GetBytes(name);
crc.Update(bytes, 0, (uint)bytes.Length);
bonePathHash[crc.GetDigest()] = name;
var crc = SevenZip.CRC.CalculateDigest(bytes, 0, (uint)bytes.Length);
bonePathHash[crc] = name;
int index;
while ((index = name.IndexOf("/", StringComparison.Ordinal)) >= 0)
{
name = name.Substring(index + 1);
crc = new SevenZip.CRC();
bytes = Encoding.UTF8.GetBytes(name);
crc.Update(bytes, 0, (uint)bytes.Length);
bonePathHash[crc.GetDigest()] = name;
crc = SevenZip.CRC.CalculateDigest(bytes, 0, (uint)bytes.Length);
bonePathHash[crc] = name;
}
foreach (var pptr in m_Transform.m_Children)
{
@@ -1102,10 +1096,7 @@ namespace AssetStudio
{
return name;
}
else
{
return null;
}
return null;
}
}
}

View File

@@ -4,9 +4,9 @@ namespace AssetStudio
{
public class SerializedTypeHelper
{
private readonly int[] version;
private readonly UnityVersion version;
public SerializedTypeHelper(int[] version)
public SerializedTypeHelper(UnityVersion version)
{
this.version = version;
}
@@ -24,7 +24,7 @@ namespace AssetStudio
{
nodes.Add(new TypeTreeNode($"PPtr<{type}>", name, indent, false));
nodes.Add(new TypeTreeNode("int", "m_FileID", indent + 1, false));
if (version[0] >= 5) //5.0 and up
if (version >= 5) //5.0 and up
{
nodes.Add(new TypeTreeNode("SInt64", "m_PathID", indent + 1, false));
}
@@ -58,7 +58,7 @@ namespace AssetStudio
nodes.Add(new TypeTreeNode("float", "value", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "inSlope", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "outSlope", indent + 4, false));
if (version[0] >= 2018) //2018 and up
if (version >= 2018) //2018 and up
{
nodes.Add(new TypeTreeNode("int", "weightedMode", indent + 4, false));
nodes.Add(new TypeTreeNode("float", "inWeight", indent + 4, false));
@@ -66,7 +66,7 @@ namespace AssetStudio
}
nodes.Add(new TypeTreeNode("int", "m_PreInfinity", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_PostInfinity", indent + 1, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up
if (version >= (5, 3)) //5.3 and up
{
nodes.Add(new TypeTreeNode("int", "m_RotationOrder", indent + 1, false));
}
@@ -75,7 +75,7 @@ namespace AssetStudio
public void AddGradient(List<TypeTreeNode> nodes, string name, int indent)
{
nodes.Add(new TypeTreeNode("Gradient", name, indent, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
if (version >= (5, 6)) //5.6 and up
{
AddColorRGBA(nodes, "key0", indent + 1);
AddColorRGBA(nodes, "key1", indent + 1);
@@ -113,7 +113,7 @@ namespace AssetStudio
nodes.Add(new TypeTreeNode("UInt16", "atime5", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime6", indent + 1, false));
nodes.Add(new TypeTreeNode("UInt16", "atime7", indent + 1, false));
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
if (version >= (5, 5)) //5.5 and up
{
nodes.Add(new TypeTreeNode("int", "m_Mode", indent + 1, false));
}
@@ -134,7 +134,7 @@ namespace AssetStudio
AddGUIStyleState(nodes, "m_OnActive", indent + 1);
AddGUIStyleState(nodes, "m_OnFocused", indent + 1);
AddRectOffset(nodes, "m_Border", indent + 1);
if (version[0] >= 4) //4 and up
if (version >= 4) //4 and up
{
AddRectOffset(nodes, "m_Margin", indent + 1);
AddRectOffset(nodes, "m_Padding", indent + 1);
@@ -146,7 +146,7 @@ namespace AssetStudio
}
AddRectOffset(nodes, "m_Overflow", indent + 1);
AddPPtr(nodes, "Font", "m_Font", indent + 1);
if (version[0] >= 4) //4 and up
if (version >= 4) //4 and up
{
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));
@@ -171,7 +171,7 @@ namespace AssetStudio
AddVector2f(nodes, "m_ClipOffset", indent + 1);
nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false));
nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false));
if (version[0] >= 3) //3 and up
if (version >= 3) //3 and up
{
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));

Some files were not shown because too many files have changed in this diff Show More