Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb7accd04d | ||
|
|
5120999026 | ||
|
|
1fc504e587 | ||
|
|
4e991d85fb | ||
|
|
29b4bb59a0 | ||
|
|
9750f486d5 | ||
|
|
97bbfe8fbb | ||
|
|
684bf5a874 | ||
|
|
3cc6bed844 | ||
|
|
c9e9bc840c | ||
|
|
cadcf0b492 | ||
|
|
1e8085da2d | ||
|
|
770d7e7532 | ||
|
|
d0d8a35f67 | ||
|
|
3f004f74d1 | ||
|
|
3effd06e64 | ||
|
|
4f0afffeba | ||
|
|
9b69b5607c | ||
|
|
9b16ea8d41 | ||
|
|
ae4548f1c3 | ||
|
|
4cd246592b | ||
|
|
f54cc004bd | ||
|
|
afdc81bca8 | ||
|
|
045f6c0ff4 | ||
|
|
bc9380b8be | ||
|
|
46f8023756 | ||
|
|
0f9afa60d7 | ||
|
|
ec7f2c393d | ||
|
|
3ec8169b08 | ||
|
|
5c24183d18 | ||
|
|
c68eaa5e3c | ||
|
|
8460ecef8d | ||
|
|
f90c0ecc00 | ||
|
|
535153be6b | ||
|
|
d4162161be | ||
|
|
6fe12d274f | ||
|
|
70213e3012 | ||
|
|
2f6d9ec77f | ||
|
|
0d2aebc1f4 | ||
|
|
115074fdc0 | ||
|
|
c2d3b8c5f9 | ||
|
|
67a74fd395 |
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>0.18.0.0</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,25 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<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>
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,15 +70,10 @@ namespace AssetStudio
|
||||
{
|
||||
filteredAssetTypesList.Add(ClassIDType.MonoScript);
|
||||
}
|
||||
if (classIDTypes.Contains(ClassIDType.Sprite) || classIDTypes.Contains(ClassIDType.AkPortraitSprite))
|
||||
if (classIDTypes.Contains(ClassIDType.Sprite))
|
||||
{
|
||||
filteredAssetTypesList.UnionWith(new HashSet<ClassIDType>
|
||||
{
|
||||
ClassIDType.Texture2D,
|
||||
ClassIDType.SpriteAtlas,
|
||||
ClassIDType.MonoBehaviour,
|
||||
ClassIDType.MonoScript
|
||||
});
|
||||
filteredAssetTypesList.Add(ClassIDType.Texture2D);
|
||||
filteredAssetTypesList.Add(ClassIDType.SpriteAtlas);
|
||||
}
|
||||
|
||||
filteredAssetTypesList.UnionWith(classIDTypes);
|
||||
@@ -58,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)
|
||||
@@ -118,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();
|
||||
@@ -131,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)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(reader);
|
||||
break;
|
||||
return LoadAssetsFile(reader);
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(reader);
|
||||
break;
|
||||
return LoadBundleFile(reader);
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(reader);
|
||||
break;
|
||||
@@ -160,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))
|
||||
{
|
||||
@@ -170,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);
|
||||
@@ -180,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];
|
||||
@@ -208,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();
|
||||
}
|
||||
}
|
||||
@@ -220,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))
|
||||
{
|
||||
@@ -230,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)
|
||||
{
|
||||
@@ -285,6 +328,7 @@ namespace AssetStudio
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
}
|
||||
Logger.Warning($"{str}\r\n{e}");
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -409,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);
|
||||
}
|
||||
@@ -433,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);
|
||||
}
|
||||
@@ -488,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);
|
||||
@@ -545,7 +591,7 @@ namespace AssetStudio
|
||||
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:
|
||||
@@ -561,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);
|
||||
@@ -577,7 +630,9 @@ namespace AssetStudio
|
||||
break;
|
||||
}
|
||||
if (obj != null)
|
||||
{
|
||||
assetsFile.AddObject(obj);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,16 +102,26 @@ 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;
|
||||
}
|
||||
@@ -120,20 +132,24 @@ namespace AssetStudio
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -3,7 +3,6 @@ namespace AssetStudio
|
||||
{
|
||||
public enum ClassIDType
|
||||
{
|
||||
AkPortraitSprite = -2,
|
||||
UnknownType = -1,
|
||||
Object = 0,
|
||||
GameObject = 1,
|
||||
@@ -146,6 +145,7 @@ namespace AssetStudio
|
||||
ProceduralMaterial = 185,
|
||||
ProceduralTexture = 186,
|
||||
Texture2DArray = 187,
|
||||
Texture2DArrayImage = -187, //fake type
|
||||
CubemapArray = 188,
|
||||
OffMeshLink = 191,
|
||||
OcclusionArea = 192,
|
||||
|
||||
@@ -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,13 +17,15 @@ namespace AssetStudio
|
||||
public T inWeight;
|
||||
public T outWeight;
|
||||
|
||||
public Keyframe() { }
|
||||
|
||||
public Keyframe(ObjectReader reader, Func<T> readerFunc)
|
||||
{
|
||||
time = reader.ReadSingle();
|
||||
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();
|
||||
@@ -37,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;
|
||||
@@ -49,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();
|
||||
}
|
||||
@@ -61,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);
|
||||
@@ -76,6 +84,8 @@ namespace AssetStudio
|
||||
public byte[] m_Data;
|
||||
public byte m_BitSize;
|
||||
|
||||
public PackedFloatVector() { }
|
||||
|
||||
public PackedFloatVector(ObjectReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
@@ -135,6 +145,8 @@ namespace AssetStudio
|
||||
public byte[] m_Data;
|
||||
public byte m_BitSize;
|
||||
|
||||
public PackedIntVector() { }
|
||||
|
||||
public PackedIntVector(ObjectReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
@@ -179,6 +191,8 @@ namespace AssetStudio
|
||||
public uint m_NumItems;
|
||||
public byte[] m_Data;
|
||||
|
||||
public PackedQuatVector() { }
|
||||
|
||||
public PackedQuatVector(ObjectReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
@@ -263,6 +277,8 @@ namespace AssetStudio
|
||||
public int m_PreInfinity;
|
||||
public int m_PostInfinity;
|
||||
|
||||
public CompressedAnimationCurve() { }
|
||||
|
||||
public CompressedAnimationCurve(ObjectReader reader)
|
||||
{
|
||||
m_Path = reader.ReadAlignedString();
|
||||
@@ -279,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);
|
||||
@@ -295,6 +313,8 @@ namespace AssetStudio
|
||||
public PPtr<MonoScript> script;
|
||||
public int flags;
|
||||
|
||||
public FloatCurve() { }
|
||||
|
||||
public FloatCurve(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
@@ -303,7 +323,7 @@ namespace AssetStudio
|
||||
path = reader.ReadAlignedString();
|
||||
classID = (ClassIDType)reader.ReadInt32();
|
||||
script = new PPtr<MonoScript>(reader);
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
if (version >= (2022, 2)) //2022.2 and up
|
||||
{
|
||||
flags = reader.ReadInt32();
|
||||
}
|
||||
@@ -315,6 +335,8 @@ namespace AssetStudio
|
||||
public float time;
|
||||
public PPtr<Object> value;
|
||||
|
||||
public PPtrKeyframe() { }
|
||||
|
||||
public PPtrKeyframe(ObjectReader reader)
|
||||
{
|
||||
time = reader.ReadSingle();
|
||||
@@ -331,6 +353,8 @@ namespace AssetStudio
|
||||
public PPtr<MonoScript> script;
|
||||
public int flags;
|
||||
|
||||
public PPtrCurve() { }
|
||||
|
||||
public PPtrCurve(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
@@ -345,7 +369,7 @@ namespace AssetStudio
|
||||
path = reader.ReadAlignedString();
|
||||
classID = reader.ReadInt32();
|
||||
script = new PPtr<MonoScript>(reader);
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
if (version >= (2022, 2)) //2022.2 and up
|
||||
{
|
||||
flags = reader.ReadInt32();
|
||||
}
|
||||
@@ -357,6 +381,8 @@ namespace AssetStudio
|
||||
public Vector3 m_Center;
|
||||
public Vector3 m_Extent;
|
||||
|
||||
public AABB() { }
|
||||
|
||||
public AABB(ObjectReader reader)
|
||||
{
|
||||
m_Center = reader.ReadVector3();
|
||||
@@ -370,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,6 +416,8 @@ namespace AssetStudio
|
||||
public float m_InOut;
|
||||
public float m_Grab;
|
||||
|
||||
public HandPose() { }
|
||||
|
||||
public HandPose(ObjectReader reader)
|
||||
{
|
||||
m_GrabX = new xform(reader);
|
||||
@@ -407,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();
|
||||
}
|
||||
}
|
||||
@@ -432,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();
|
||||
@@ -451,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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,6 +502,8 @@ namespace AssetStudio
|
||||
public uint[] data;
|
||||
public uint curveCount;
|
||||
|
||||
public StreamedClip() { }
|
||||
|
||||
public StreamedClip(ObjectReader reader)
|
||||
{
|
||||
data = reader.ReadUInt32Array();
|
||||
@@ -483,6 +519,8 @@ namespace AssetStudio
|
||||
public float outSlope;
|
||||
public float inSlope;
|
||||
|
||||
public StreamedCurveKey() { }
|
||||
|
||||
public StreamedCurveKey(BinaryReader reader)
|
||||
{
|
||||
index = reader.ReadInt32();
|
||||
@@ -514,6 +552,8 @@ namespace AssetStudio
|
||||
public float time;
|
||||
public StreamedCurveKey[] keyList;
|
||||
|
||||
public StreamedFrame() { }
|
||||
|
||||
public StreamedFrame(BinaryReader reader)
|
||||
{
|
||||
time = reader.ReadSingle();
|
||||
@@ -569,6 +609,8 @@ namespace AssetStudio
|
||||
public float m_BeginTime;
|
||||
public float[] m_SampleArray;
|
||||
|
||||
public DenseClip() { }
|
||||
|
||||
public DenseClip(ObjectReader reader)
|
||||
{
|
||||
m_FrameCount = reader.ReadInt32();
|
||||
@@ -583,6 +625,8 @@ namespace AssetStudio
|
||||
{
|
||||
public float[] data;
|
||||
|
||||
public ConstantClip() { }
|
||||
|
||||
public ConstantClip(ObjectReader reader)
|
||||
{
|
||||
data = reader.ReadSingleArray();
|
||||
@@ -596,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();
|
||||
}
|
||||
@@ -613,6 +659,8 @@ namespace AssetStudio
|
||||
{
|
||||
public ValueConstant[] m_ValueArray;
|
||||
|
||||
public ValueArrayConstant() { }
|
||||
|
||||
public ValueArrayConstant(ObjectReader reader)
|
||||
{
|
||||
int numVals = reader.ReadInt32();
|
||||
@@ -624,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;
|
||||
@@ -631,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);
|
||||
}
|
||||
@@ -696,6 +758,8 @@ namespace AssetStudio
|
||||
public float m_Start;
|
||||
public float m_Stop;
|
||||
|
||||
public ValueDelta() { }
|
||||
|
||||
public ValueDelta(ObjectReader reader)
|
||||
{
|
||||
m_Start = reader.ReadSingle();
|
||||
@@ -713,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;
|
||||
@@ -735,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();
|
||||
@@ -761,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();
|
||||
}
|
||||
@@ -771,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();
|
||||
}
|
||||
@@ -785,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();
|
||||
}
|
||||
@@ -815,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();
|
||||
}
|
||||
@@ -825,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();
|
||||
}
|
||||
@@ -903,6 +969,8 @@ namespace AssetStudio
|
||||
public int intParameter;
|
||||
public int messageOptions;
|
||||
|
||||
public AnimationEvent() { }
|
||||
|
||||
public AnimationEvent(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
@@ -912,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();
|
||||
}
|
||||
@@ -948,13 +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)
|
||||
@@ -965,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();
|
||||
}
|
||||
@@ -984,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];
|
||||
@@ -1015,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];
|
||||
@@ -1027,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();
|
||||
@@ -1052,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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -42,12 +42,22 @@ namespace AssetStudio
|
||||
|
||||
var m_MainAsset = new AssetInfo(reader);
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
|
||||
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[0] >= 5) //5.0 and up
|
||||
if (version >= 5) //5.0 and up
|
||||
{
|
||||
m_AssetBundleName = reader.ReadAlignedString();
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace AssetStudio
|
||||
{
|
||||
public abstract class EditorExtension : Object
|
||||
{
|
||||
protected EditorExtension() { }
|
||||
|
||||
protected EditorExtension(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (platform == BuildTarget.NoTarget)
|
||||
|
||||
@@ -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();
|
||||
|
||||
31
AssetStudio/Classes/GLTextureSettings.cs
Normal file
31
AssetStudio/Classes/GLTextureSettings.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
711
AssetStudio/Classes/GraphicsFormat.cs
Normal file
711
AssetStudio/Classes/GraphicsFormat.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace AssetStudio
|
||||
{
|
||||
public string m_Name;
|
||||
|
||||
protected NamedObject() { }
|
||||
|
||||
protected NamedObject(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Name = reader.ReadAlignedString();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -182,13 +182,6 @@ namespace AssetStudio
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
public Rectf(float x, float y, float w, float h) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
public Rectf(BinaryReader reader)
|
||||
{
|
||||
x = reader.ReadSingle();
|
||||
@@ -212,34 +205,31 @@ namespace AssetStudio
|
||||
public PPtr<SpriteAtlas> m_SpriteAtlas;
|
||||
public SpriteRenderData m_RD;
|
||||
public Vector2[][] m_PhysicsShape;
|
||||
public bool akSplitAlpha;
|
||||
|
||||
public Sprite(ObjectReader reader) : base(reader)
|
||||
{
|
||||
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();
|
||||
@@ -252,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][];
|
||||
@@ -262,8 +252,6 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
akSplitAlpha = false;
|
||||
|
||||
//vector m_Bones 2018 and up
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
27
AssetStudio/Classes/StreamingInfo.cs
Normal file
27
AssetStudio/Classes/StreamingInfo.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,152 +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
|
||||
{
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
if (version >= (2022, 2)) //2022.2 and up
|
||||
{
|
||||
var m_IgnoreMipmapLimit = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
if (version[0] >= 3) //3.0.0 - 5.4
|
||||
if (version.IsInRange(3, (5, 5))) //3.0.0 - 5.4
|
||||
{
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
|
||||
{
|
||||
var m_ReadAllowed = reader.ReadBoolean();
|
||||
}
|
||||
var m_ReadAllowed = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 2)) //2022.2 and up
|
||||
if (version >= (2022, 2)) //2022.2 and up
|
||||
{
|
||||
var m_MipmapLimitGroupName = reader.ReadAlignedString();
|
||||
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_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
|
||||
}
|
||||
}
|
||||
73
AssetStudio/Classes/Texture2DArray.cs
Normal file
73
AssetStudio/Classes/Texture2DArray.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
282
AssetStudio/Classes/TextureFormat.cs
Normal file
282
AssetStudio/Classes/TextureFormat.cs
Normal 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,
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
149
AssetStudio/CubismModel.cs
Normal file
149
AssetStudio/CubismModel.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
AssetStudio/EndianSpanReader.cs
Normal file
29
AssetStudio/EndianSpanReader.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace AssetStudio
|
||||
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
|
||||
return reader.ReadUnicodeStringToNull(maxLength * 2);
|
||||
|
||||
var bytes = new List<byte>();
|
||||
Span<byte> bytes = stackalloc byte[maxLength];
|
||||
var count = 0;
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||
{
|
||||
@@ -49,9 +49,10 @@ namespace AssetStudio
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes.Add(b);
|
||||
bytes[count] = b;
|
||||
count++;
|
||||
}
|
||||
bytes = bytes.Slice(0, count);
|
||||
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
449
AssetStudio/UnityVersion.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
|
||||
<AssemblyName>ArknightsStudioCLI</AssemblyName>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
|
||||
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
|
||||
<AssemblyName>AssetStudioModCLI</AssemblyName>
|
||||
<Version>0.18.0.0</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2023-2024</Copyright>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -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,21 +17,29 @@ 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)}");
|
||||
}
|
||||
@@ -55,7 +64,7 @@ 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)
|
||||
@@ -64,7 +73,7 @@ namespace AssetStudioCLI
|
||||
formattedMessage = $"{colorLogLevel} {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ");
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ") + $"\n{colorLogLevel}";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -74,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;
|
||||
@@ -88,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)
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
using Arknights.PortraitSpriteMono;
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI;
|
||||
using AssetStudioCLI.Options;
|
||||
using Newtonsoft.Json;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal static class AkSpriteHelper
|
||||
{
|
||||
public static Texture2D TryFindAlphaTex(AssetItem assetItem, AvgSprite avgSprite, bool isAvgSprite)
|
||||
{
|
||||
Sprite m_Sprite = (Sprite)assetItem.Asset;
|
||||
var imgType = "arts/characters";
|
||||
if (m_Sprite.m_RD.alphaTexture.m_PathID == 0)
|
||||
{
|
||||
if (isAvgSprite)
|
||||
{
|
||||
if (avgSprite?.FullAlphaTexture != null)
|
||||
return avgSprite.FullAlphaTexture;
|
||||
|
||||
imgType = "avg/characters"; //since the avg hub was not found for some reason, let's try to find alpha tex by name
|
||||
}
|
||||
var spriteFullName = Path.GetFileNameWithoutExtension(assetItem.Container);
|
||||
foreach (var item in Studio.loadedAssetsList)
|
||||
{
|
||||
if (item.Type == ClassIDType.Texture2D)
|
||||
{
|
||||
if (item.Container.Contains(imgType) && item.Container.Contains($"illust_{m_Sprite.m_Name}_material") && item.Text.Contains("[alpha]"))
|
||||
return (Texture2D)item.Asset;
|
||||
if (item.Container.Contains(imgType) && item.Container.Contains(spriteFullName) && item.Text == $"{m_Sprite.m_Name}[alpha]")
|
||||
return (Texture2D)item.Asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Image<Bgra32> AkGetImage(this Sprite m_Sprite, AvgSprite avgSprite = null, SpriteMaskMode spriteMaskMode = SpriteMaskMode.On)
|
||||
{
|
||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
|
||||
{
|
||||
Image<Bgra32> tex;
|
||||
Image<Bgra32> alphaTex;
|
||||
|
||||
if (avgSprite != null && avgSprite.IsHubParsed)
|
||||
{
|
||||
alphaTex = m_AlphaTexture2D.ConvertToImage(true);
|
||||
if (avgSprite.IsFaceSprite)
|
||||
{
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var faceAlpha = avgSprite.FaceSpriteAlphaTexture.ConvertToImage(true);
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
faceAlpha.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, avgSprite.FacePos, opacity: 1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
tex = m_Texture2D.ConvertToImage(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tex = CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
alphaTex = CutImage(m_AlphaTexture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
}
|
||||
tex.ApplyRGBMask(alphaTex);
|
||||
return tex;
|
||||
}
|
||||
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D) && avgSprite != null && avgSprite.IsHubParsed)
|
||||
{
|
||||
if (!avgSprite.IsFaceSprite)
|
||||
{
|
||||
return m_Texture2D.ConvertToImage(true);
|
||||
}
|
||||
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
|
||||
return tex;
|
||||
}
|
||||
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D))
|
||||
{
|
||||
return CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Image<Bgra32> AkGetImage(this PortraitSprite portraitSprite, SpriteMaskMode spriteMaskMode = SpriteMaskMode.On)
|
||||
{
|
||||
if (portraitSprite.Texture != null && portraitSprite.AlphaTexture != null)
|
||||
{
|
||||
var tex = CutImage(portraitSprite.Texture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||
|
||||
if (spriteMaskMode == SpriteMaskMode.Off)
|
||||
{
|
||||
return tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
var alphaTex = CutImage(portraitSprite.AlphaTexture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||
tex.ApplyRGBMask(alphaTex);
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<PortraitSprite> GeneratePortraits(AssetItem asset)
|
||||
{
|
||||
var portraits = new List<PortraitSprite>();
|
||||
|
||||
var portraitsDict = ((MonoBehaviour)asset.Asset).ToType();
|
||||
if (portraitsDict == null)
|
||||
{
|
||||
Logger.Warning("Portraits MonoBehaviour is not readable.");
|
||||
return portraits;
|
||||
}
|
||||
var portraitsJson = JsonConvert.SerializeObject(portraitsDict);
|
||||
var portraitsData = JsonConvert.DeserializeObject<PortraitSpriteConfig>(portraitsJson);
|
||||
|
||||
var atlasTex = (Texture2D)Studio.loadedAssetsList.Find(x => x.m_PathID == portraitsData._atlas.Texture.m_PathID).Asset;
|
||||
var atlasAlpha = (Texture2D)Studio.loadedAssetsList.Find(x => x.m_PathID == portraitsData._atlas.Alpha.m_PathID).Asset;
|
||||
|
||||
foreach (var portraitData in portraitsData._sprites)
|
||||
{
|
||||
var portraitSprite = new PortraitSprite()
|
||||
{
|
||||
Name = portraitData.Name,
|
||||
AssetsFile = atlasTex.assetsFile,
|
||||
Container = asset.Container,
|
||||
Texture = atlasTex,
|
||||
AlphaTexture = atlasAlpha,
|
||||
TextureRect = new Rectf(portraitData.Rect.X, portraitData.Rect.Y, portraitData.Rect.W, portraitData.Rect.H),
|
||||
Rotate = portraitData.Rotate,
|
||||
};
|
||||
portraits.Add(portraitSprite);
|
||||
}
|
||||
|
||||
return portraits;
|
||||
}
|
||||
|
||||
private static void ApplyRGBMask(this Image<Bgra32> tex, Image<Bgra32> texMask)
|
||||
{
|
||||
using (texMask)
|
||||
{
|
||||
bool resized = false;
|
||||
if (tex.Width != texMask.Width || tex.Height != texMask.Height)
|
||||
{
|
||||
texMask.Mutate(x => x.Resize(tex.Width, tex.Height, CLIOptions.o_akAlphaTexResampler.Value));
|
||||
resized = true;
|
||||
}
|
||||
|
||||
var invGamma = 1.0 / (1.0 + CLIOptions.o_akShadowGamma.Value / 10.0);
|
||||
if (CLIOptions.akResizedOnly && !resized)
|
||||
{
|
||||
invGamma = 1.0;
|
||||
}
|
||||
|
||||
tex.ProcessPixelRows(texMask, (sourceTex, targetTexMask) =>
|
||||
{
|
||||
for (int y = 0; y < texMask.Height; y++)
|
||||
{
|
||||
var texRow = sourceTex.GetRowSpan(y);
|
||||
var maskRow = targetTexMask.GetRowSpan(y);
|
||||
for (int x = 0; x < maskRow.Length; x++)
|
||||
{
|
||||
var grayscale = (maskRow[x].R + maskRow[x].G + maskRow[x].B) / 3.0;
|
||||
if (invGamma != 1.0)
|
||||
{
|
||||
grayscale = 255 - Math.Pow((255 - grayscale) / 255, invGamma) * 255;
|
||||
}
|
||||
texRow[x].A = (byte)grayscale;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Image<Bgra32> CutImage(Image<Bgra32> originalImage, Rectf textureRect, float downscaleMultiplier, bool rotate = false)
|
||||
{
|
||||
if (originalImage != null)
|
||||
{
|
||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||
{
|
||||
var newSize = (Size)(new Size(originalImage.Width, originalImage.Height) / downscaleMultiplier);
|
||||
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
||||
}
|
||||
var rectX = (int)Math.Floor(textureRect.x);
|
||||
var rectY = (int)Math.Floor(textureRect.y);
|
||||
var rectRight = (int)Math.Ceiling(textureRect.x + textureRect.width);
|
||||
var rectBottom = (int)Math.Ceiling(textureRect.y + textureRect.height);
|
||||
rectRight = Math.Min(rectRight, originalImage.Width);
|
||||
rectBottom = Math.Min(rectBottom, originalImage.Height);
|
||||
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
|
||||
var spriteImage = originalImage.Clone(x => x.Crop(rect));
|
||||
originalImage.Dispose();
|
||||
if (rotate)
|
||||
{
|
||||
spriteImage.Mutate(x => x.Rotate(RotateMode.Rotate270));
|
||||
}
|
||||
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
|
||||
return spriteImage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using Arknights.AvgCharHubMono;
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI;
|
||||
using SixLabors.ImageSharp;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal class AvgSprite
|
||||
{
|
||||
public Texture2D FaceSpriteAlphaTexture { get; }
|
||||
public Texture2D FullTexture { get; }
|
||||
public Texture2D FullAlphaTexture { get; }
|
||||
public Point FacePos { get; }
|
||||
public Size FaceSize { get; }
|
||||
public string Alias { get; }
|
||||
public bool IsWholeBodySprite { get; }
|
||||
public bool IsFaceSprite { get; }
|
||||
public bool IsHubParsed { get; }
|
||||
|
||||
private AvgSpriteConfig GetCurSpriteGroup(AvgSpriteConfigGroup spriteHubDataGrouped, long spriteItemID, string spriteName)
|
||||
{
|
||||
if (spriteHubDataGrouped.SpriteGroups.Length > 1)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(spriteName))
|
||||
{
|
||||
var groupFromName = int.TryParse(spriteName?.Substring(spriteName.IndexOf('$') + 1, 1), out int groupIndex);
|
||||
if (groupFromName)
|
||||
{
|
||||
return spriteHubDataGrouped.SpriteGroups[groupIndex - 1];
|
||||
}
|
||||
}
|
||||
return spriteHubDataGrouped.SpriteGroups.FirstOrDefault(x => x.Sprites.Any(y => y.Sprite.m_PathID == spriteItemID));
|
||||
}
|
||||
else
|
||||
{
|
||||
return spriteHubDataGrouped.SpriteGroups[0];
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetSpriteHub(AssetItem assetItem, out AvgSpriteConfig spriteHubData)
|
||||
{
|
||||
spriteHubData = null;
|
||||
var avgSpriteHubItem = Studio.loadedAssetsList.Find(x =>
|
||||
x.Type == ClassIDType.MonoBehaviour
|
||||
&& x.Container == assetItem.Container
|
||||
&& x.Text.IndexOf("AVGCharacterSpriteHub", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
);
|
||||
if (avgSpriteHubItem == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub was not found.");
|
||||
return false;
|
||||
}
|
||||
var spriteHubDict = ((MonoBehaviour)avgSpriteHubItem.Asset).ToType();
|
||||
if (spriteHubDict == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub is not readable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var spriteHubJson = JsonConvert.SerializeObject(spriteHubDict);
|
||||
if (avgSpriteHubItem.Text.ToLower().Contains("hubgroup"))
|
||||
{
|
||||
var groupedSpriteHub = JsonConvert.DeserializeObject<AvgSpriteConfigGroup>(spriteHubJson);
|
||||
spriteHubData = GetCurSpriteGroup(groupedSpriteHub, assetItem.m_PathID, assetItem.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteHubData = JsonConvert.DeserializeObject<AvgSpriteConfig>(spriteHubJson);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public AvgSprite(AssetItem assetItem)
|
||||
{
|
||||
if (TryGetSpriteHub(assetItem, out var spriteHubData))
|
||||
{
|
||||
IsHubParsed = spriteHubData?.Sprites.Length > 0;
|
||||
}
|
||||
if (IsHubParsed)
|
||||
{
|
||||
var curSpriteData = spriteHubData.Sprites.FirstOrDefault(x => x.Sprite.m_PathID == assetItem.m_PathID);
|
||||
|
||||
if (curSpriteData == null)
|
||||
{
|
||||
Logger.Warning($"Sprite \"{assetItem.Text}\" was not found in the avg sprite hub");
|
||||
return;
|
||||
}
|
||||
|
||||
Alias = curSpriteData.Alias;
|
||||
IsWholeBodySprite = curSpriteData.IsWholeBody;
|
||||
|
||||
if (spriteHubData.FaceSize.X > 0 && spriteHubData.FaceSize.Y > 0) //If face data exist
|
||||
{
|
||||
var fullTexSpriteData = spriteHubData.Sprites.Last(); //Last sprite item in the list usually contains PathID of Sprite with full texture
|
||||
|
||||
var curSprite = (Sprite)assetItem.Asset;
|
||||
IsFaceSprite = curSprite.m_Rect.width <= 256 && curSprite.m_Rect.height <= 256 && curSprite.m_PathID != fullTexSpriteData.Sprite.m_PathID;
|
||||
|
||||
var curSpriteAlphaID = curSpriteData.AlphaTex.m_PathID;
|
||||
var curSpriteAlphaTex = (Texture2D)Studio.loadedAssetsList.Find(x => x.m_PathID == curSpriteAlphaID)?.Asset;
|
||||
if (curSpriteAlphaTex != null)
|
||||
{
|
||||
FaceSpriteAlphaTexture = IsFaceSprite ? curSpriteAlphaTex : null;
|
||||
fullTexSpriteData = IsFaceSprite ? fullTexSpriteData : curSpriteData;
|
||||
}
|
||||
var fullTexSpriteID = fullTexSpriteData.Sprite.m_PathID;
|
||||
var fullTexAlphaID = fullTexSpriteData.AlphaTex.m_PathID;
|
||||
var fullTexSprite = (Sprite)Studio.loadedAssetsList.Find(x => x.m_PathID == fullTexSpriteID).Asset;
|
||||
|
||||
FullTexture = fullTexSprite.m_RD.texture.TryGet(out var fullTex) ? fullTex : null;
|
||||
FullAlphaTexture = (Texture2D)Studio.loadedAssetsList.Find(x => x.m_PathID == fullTexAlphaID)?.Asset;
|
||||
FacePos = new Point((int)Math.Round(spriteHubData.FacePos.X), (int)Math.Round(spriteHubData.FacePos.Y));
|
||||
FaceSize = new Size((int)Math.Round(spriteHubData.FaceSize.X), (int)Math.Round(spriteHubData.FaceSize.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
FullAlphaTexture = (Texture2D)Studio.loadedAssetsList.Find(x => x.m_PathID == curSpriteData.AlphaTex.m_PathID).Asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using AssetStudio;
|
||||
|
||||
namespace Arknights.AvgCharHubMono
|
||||
{
|
||||
internal class AvgAssetIDs
|
||||
{
|
||||
public int m_FileID { get; set; }
|
||||
public long m_PathID { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteData
|
||||
{
|
||||
public AvgAssetIDs Sprite { get; set; }
|
||||
public AvgAssetIDs AlphaTex { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public bool IsWholeBody { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteConfig
|
||||
{
|
||||
public AvgSpriteData[] Sprites { get; set; }
|
||||
public Vector2 FaceSize { get; set; }
|
||||
public Vector3 FacePos { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteConfigGroup
|
||||
{
|
||||
public AvgSpriteConfig[] SpriteGroups { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using AssetStudio;
|
||||
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal class PortraitSprite
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ClassIDType Type { get; }
|
||||
public SerializedFile AssetsFile { get; set; }
|
||||
public string Container { get; set; }
|
||||
public Texture2D Texture { get; set; }
|
||||
public Texture2D AlphaTexture { get; set; }
|
||||
public Rectf TextureRect { get; set; }
|
||||
public bool Rotate { get; set; }
|
||||
public float DownscaleMultiplier { get; }
|
||||
|
||||
public PortraitSprite()
|
||||
{
|
||||
Type = ClassIDType.AkPortraitSprite;
|
||||
DownscaleMultiplier = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
namespace Arknights.PortraitSpriteMono
|
||||
{
|
||||
internal class PortraitRect
|
||||
{
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float W { get; set; }
|
||||
public float H { get; set; }
|
||||
}
|
||||
|
||||
internal class AtlasSprite
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Guid { get; set; }
|
||||
public int Atlas { get; set; }
|
||||
public PortraitRect Rect { get; set; }
|
||||
public bool Rotate { get; set; }
|
||||
}
|
||||
|
||||
internal class TextureIDs
|
||||
{
|
||||
public int m_FileID { get; set; }
|
||||
public long m_PathID { get; set; }
|
||||
}
|
||||
|
||||
internal class AtlasInfo
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public TextureIDs Texture { get; set; }
|
||||
public TextureIDs Alpha { get; set; }
|
||||
public int Size { get; set; }
|
||||
}
|
||||
|
||||
internal class PortraitSpriteConfig
|
||||
{
|
||||
public string m_Name { get; set; }
|
||||
public AtlasSprite[] _sprites { get; set; }
|
||||
public AtlasInfo _atlas { get; set; }
|
||||
public int _index { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Arknights;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
@@ -15,7 +14,6 @@ namespace AssetStudioCLI
|
||||
public string Text;
|
||||
public string UniqueID;
|
||||
public GameObjectNode Node;
|
||||
public PortraitSprite AkPortraitSprite;
|
||||
|
||||
public AssetItem(Object asset)
|
||||
{
|
||||
@@ -26,17 +24,5 @@ namespace AssetStudioCLI
|
||||
m_PathID = asset.m_PathID;
|
||||
FullSize = asset.byteSize;
|
||||
}
|
||||
|
||||
public AssetItem(PortraitSprite akPortraitSprite)
|
||||
{
|
||||
Asset = null;
|
||||
SourceFile = akPortraitSprite.AssetsFile;
|
||||
Container = akPortraitSprite.Container;
|
||||
Type = akPortraitSprite.Type;
|
||||
TypeString = Type.ToString();
|
||||
Text = akPortraitSprite.Name;
|
||||
m_PathID = -1;
|
||||
AkPortraitSprite = akPortraitSprite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using AssetStudio;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
@@ -6,11 +5,12 @@ namespace AssetStudioCLI
|
||||
internal class BaseNode
|
||||
{
|
||||
public List<BaseNode> nodes = new List<BaseNode>();
|
||||
public string FullPath = "";
|
||||
public readonly string Text;
|
||||
|
||||
public BaseNode()
|
||||
public BaseNode(string name)
|
||||
{
|
||||
|
||||
Text = name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using AssetStudio;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
@@ -7,10 +6,9 @@ namespace AssetStudioCLI
|
||||
{
|
||||
public GameObject gameObject;
|
||||
|
||||
public GameObjectNode(GameObject gameObject)
|
||||
public GameObjectNode(GameObject gameObject) : base(gameObject.m_Name)
|
||||
{
|
||||
this.gameObject = gameObject;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,123 +1,15 @@
|
||||
using Arknights;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using Newtonsoft.Json;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
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;
|
||||
@@ -237,112 +129,6 @@ namespace AssetStudioCLI
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportSprite(AssetItem item, string exportPath)
|
||||
{
|
||||
Image<Bgra32> image;
|
||||
AvgSprite avgSprite = null;
|
||||
var alias = "";
|
||||
var m_Sprite = (Sprite)item.Asset;
|
||||
var type = CLIOptions.o_imageFormat.Value;
|
||||
var spriteMaskMode = CLIOptions.o_akSpriteAlphaMode.Value != AkSpriteAlphaMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
||||
var isCharAvgSprite = item.Container.Contains("avg/characters");
|
||||
var isCharArt = item.Container.Contains("arts/characters");
|
||||
|
||||
if (isCharAvgSprite)
|
||||
{
|
||||
avgSprite = new AvgSprite(item);
|
||||
|
||||
if (CLIOptions.f_akAddAliases.Value && !string.IsNullOrEmpty(avgSprite.Alias))
|
||||
{
|
||||
alias = $"_{avgSprite.Alias}";
|
||||
}
|
||||
|
||||
if (!CLIOptions.f_akOriginalAvgNames.Value)
|
||||
{
|
||||
var groupedPattern = new Regex(@"^\d{1,2}\$\d{1,2}$"); // "spriteIndex$groupIndex"
|
||||
var notGroupedPattern = new Regex(@"^\d{1,2}$"); // "spriteIndex"
|
||||
if (groupedPattern.IsMatch(m_Sprite.m_Name) || notGroupedPattern.IsMatch(m_Sprite.m_Name))
|
||||
{
|
||||
var fullName = Path.GetFileNameWithoutExtension(item.Container);
|
||||
item.Text = $"{fullName}#{m_Sprite.m_Name}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath, alias))
|
||||
return false;
|
||||
|
||||
if (CLIOptions.o_akSpriteAlphaMode.Value == AkSpriteAlphaMode.SearchExternal && (isCharAvgSprite || isCharArt))
|
||||
{
|
||||
if (m_Sprite.m_RD.alphaTexture.IsNull)
|
||||
{
|
||||
var charAlphaAtlas = AkSpriteHelper.TryFindAlphaTex(item, avgSprite, isCharAvgSprite);
|
||||
if (charAlphaAtlas != null)
|
||||
{
|
||||
m_Sprite.m_RD.alphaTexture.Set(charAlphaAtlas);
|
||||
m_Sprite.akSplitAlpha = true;
|
||||
}
|
||||
}
|
||||
image = m_Sprite.AkGetImage(avgSprite, spriteMaskMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = m_Sprite.GetImage(spriteMaskMode);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static bool ExportPortraitSprite(AssetItem item, string exportPath)
|
||||
{
|
||||
var type = CLIOptions.o_imageFormat.Value;
|
||||
var spriteMaskMode = CLIOptions.o_akSpriteAlphaMode.Value != AkSpriteAlphaMode.None ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
|
||||
var image = item.AkPortraitSprite.AkGetImage(spriteMaskMode: spriteMaskMode);
|
||||
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;
|
||||
}
|
||||
|
||||
public static bool ExportRawFile(AssetItem item, string exportPath)
|
||||
{
|
||||
if (item.Asset == null)
|
||||
{
|
||||
Logger.Warning($"Raw export is not supported for \"{item.Text}\" ({item.TypeString}) file");
|
||||
return false;
|
||||
}
|
||||
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
|
||||
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
|
||||
{
|
||||
var convert = animationList != null
|
||||
@@ -355,7 +141,7 @@ namespace AssetStudioCLI
|
||||
private static void ExportFbx(IImported convert, string exportPath)
|
||||
{
|
||||
var eulerFilter = true;
|
||||
var filterPrecision = (float)0.25f;
|
||||
var filterPrecision = 0.25f;
|
||||
var exportAllNodes = true;
|
||||
var exportSkins = true;
|
||||
var exportAnimations = true;
|
||||
@@ -370,14 +156,19 @@ namespace AssetStudioCLI
|
||||
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, mode: "ExportRaw"))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
|
||||
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
||||
{
|
||||
if (item.Asset == null)
|
||||
{
|
||||
Logger.Warning($"Dump is not supported for \"{item.Text}\" ({item.TypeString}) file");
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
@@ -385,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);
|
||||
@@ -394,22 +189,35 @@ namespace AssetStudioCLI
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string alias = "")
|
||||
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
|
||||
{
|
||||
var fileName = FixFileName(item.Text) + alias;
|
||||
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(ColorConsole.BrightRed)}\" already exist");
|
||||
Logger.Error($"{mode} error. File \"{fullPath.Color(ColorConsole.BrightRed)}\" already exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -515,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:
|
||||
@@ -530,10 +339,6 @@ namespace AssetStudioCLI
|
||||
return ExportMonoBehaviour(item, exportPath);
|
||||
case ClassIDType.Font:
|
||||
return ExportFont(item, exportPath);
|
||||
case ClassIDType.Sprite:
|
||||
return ExportSprite(item, exportPath);
|
||||
case ClassIDType.AkPortraitSprite:
|
||||
return ExportPortraitSprite(item, exportPath);
|
||||
case ClassIDType.Mesh:
|
||||
return ExportMesh(item, exportPath);
|
||||
default:
|
||||
@@ -543,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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
223
AssetStudioCLI/ParallelExporter.cs
Normal file
223
AssetStudioCLI/ParallelExporter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace AssetStudioCLI
|
||||
case WorkMode.Info:
|
||||
Studio.ShowExportableAssetsInfo();
|
||||
break;
|
||||
case WorkMode.ExportLive2D:
|
||||
case WorkMode.Live2D:
|
||||
Studio.ExportLive2D();
|
||||
break;
|
||||
case WorkMode.SplitObjects:
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
## ArknightsStudioCLI
|
||||
CLI version of ArknightsStudio.
|
||||
- Supported asset types for export: `Texture2D`, `Sprite`, `AkPortraitSprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip`, `Mesh`.
|
||||
## AssetStudioModCLI
|
||||
CLI version of AssetStudioMod.
|
||||
- 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
|
||||
```
|
||||
ArknightsStudioCLI <input path to asset file/folder> [-m, --mode <value>]
|
||||
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>]
|
||||
[--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>]
|
||||
[--spritealpha-mode <value>] [--alphatex-resampler <value>]
|
||||
[--shadow-gamma <value>] [--original-avg-names]
|
||||
[--add-aliases] [--export-asset-list <value>]
|
||||
[-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>] [--custom-compression <value>]
|
||||
[--max-export-tasks <value>] [--export-asset-list <value>]
|
||||
[--assembly-folder <path>] [--unity-version <text>]
|
||||
[--not-restore-extension] [--load-all]
|
||||
|
||||
[--not-restore-extension] [--avoid-typetree-loading]
|
||||
[--load-all]
|
||||
|
||||
General Options:
|
||||
-m, --mode <value> Specify working mode
|
||||
@@ -28,25 +27,33 @@ General Options:
|
||||
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, akPortrait, textAsset, monoBehaviour, font, shader,
|
||||
<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 specified, 'ASExport' folder will be created in the program's work folder
|
||||
@@ -68,9 +75,9 @@ 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"
|
||||
|
||||
Live2D Options:
|
||||
@@ -86,11 +93,11 @@ Live2D Options:
|
||||
|
||||
FBX Options:
|
||||
--fbx-scale-factor <value> Specify the FBX Scale Factor
|
||||
<Value: float number from 0 to 100 (default=1)
|
||||
<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)
|
||||
<Value: integer number from 0 to 100 (default=10)>
|
||||
Example: "--fbx-bone-size 10"
|
||||
|
||||
Filter Options:
|
||||
@@ -112,35 +119,18 @@ Filter Options:
|
||||
Example: "--filter-by-text portrait" or "--filter-by-text portrait,art"
|
||||
|
||||
|
||||
Arknights Options:
|
||||
--spritealpha-mode <value> Specify the mode in which you want to export sprites with alpha texture
|
||||
<Value: none | internalOnly | searchExternal(default)>
|
||||
None - Export sprites without alpha texture applied
|
||||
InternalOnly - Export sprites with internal alpha texture applied (if exist)
|
||||
SearchExternal - Export sprites with internal alpha texture applied,
|
||||
and in case it doesn't exist, Studio will try to find an external alpha texture
|
||||
Example: "--spritealpha-mode internalOnly"
|
||||
|
||||
--alphatex-resampler <value> Specify the alpha texture upscale algorithm for 2048x2048 sprites
|
||||
<Value: nearest | bilinear | bicubic | mitchell(default) | spline | welch>
|
||||
Mitchell - Mitchell Netravali algorithm. Yields good equilibrium between
|
||||
sharpness and smoothness (produces less artifacts than bicubic in the current use case)
|
||||
Spline - Similar to Mitchell Netravali but yielding smoother results
|
||||
Welch - A high speed algorithm that delivers very sharpened results
|
||||
Example: "--alphatex-resampler bicubic"
|
||||
|
||||
--shadow-gamma <value> Specify the gamma correction of semi-transparent shadow for 2048x2048 sprites
|
||||
<Value: integer number from -5 to 5 (default=2)>
|
||||
<0 - Make the shadow darker
|
||||
0 - Do not change the brightness of the shadow
|
||||
>0 - Make the shadow lighter
|
||||
Example: "--shadow-gamma 0"
|
||||
|
||||
--original-avg-names (Flag) If specified, names of avg character sprites will not be restored
|
||||
|
||||
--add-aliases (Flag) If specified, aliases will be added to avg character sprite names (if exist)
|
||||
|
||||
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
|
||||
@@ -151,9 +141,12 @@ Advanced Options:
|
||||
--unity-version <text> Specify Unity version
|
||||
Example: "--unity-version 2017.4.39f1"
|
||||
|
||||
--not-restore-extension (Flag) If specified, Studio will not try to use/restore original TextAsset
|
||||
--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
|
||||
|
||||
--load-all (Flag) If specified, Studio will load assets of all types
|
||||
--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)
|
||||
```
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
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 = AssetStudio.ColorConsole;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
@@ -14,10 +17,10 @@ namespace AssetStudioCLI
|
||||
internal static class Studio
|
||||
{
|
||||
public static AssetsManager assetsManager = new AssetsManager();
|
||||
public static List<AssetItem> exportableAssetsList = new List<AssetItem>();
|
||||
public static List<AssetItem> loadedAssetsList = new List<AssetItem>();
|
||||
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()
|
||||
@@ -34,6 +37,8 @@ namespace AssetStudioCLI
|
||||
{
|
||||
var isLoaded = false;
|
||||
assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.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);
|
||||
@@ -55,6 +60,8 @@ 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);
|
||||
|
||||
@@ -111,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;
|
||||
@@ -125,14 +138,16 @@ namespace AssetStudioCLI
|
||||
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;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
assetItem.Text = m_GameObject.m_Name;
|
||||
@@ -152,45 +167,48 @@ namespace AssetStudioCLI
|
||||
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
|
||||
}
|
||||
|
||||
loadedAssetsList.Add(assetItem);
|
||||
isExportable = CLIOptions.o_exportAssetTypes.Value.Contains(asset.type);
|
||||
if (isExportable || (CLIOptions.f_loadAllAssets.Value && CLIOptions.o_exportAssetTypes.Value == CLIOptions.o_exportAssetTypes.DefaultValue))
|
||||
{
|
||||
exportableAssetsList.Add(assetItem);
|
||||
fileAssetsList.Add(assetItem);
|
||||
}
|
||||
|
||||
Progress.Report(++i, objectCount);
|
||||
}
|
||||
foreach (var asset in loadedAssetsList)
|
||||
foreach (var asset in fileAssetsList)
|
||||
{
|
||||
if (containers.TryGetValue(asset.Asset, out var container))
|
||||
{
|
||||
asset.Container = container;
|
||||
|
||||
if (asset.Type == ClassIDType.MonoBehaviour && container.Contains("/arts/charportraits/portraits"))
|
||||
{
|
||||
var portraitsList = Arknights.AkSpriteHelper.GeneratePortraits(asset);
|
||||
foreach (var portrait in portraitsList)
|
||||
{
|
||||
exportableAssetsList.Add(new AssetItem(portrait));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
|
||||
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();
|
||||
tex2dArrayAssetList.Clear();
|
||||
if (CLIOptions.o_workMode.Value != WorkMode.Live2D)
|
||||
{
|
||||
containers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects)
|
||||
if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects || CLIOptions.o_groupAssetsBy.Value == AssetGroupOption.SceneHierarchy)
|
||||
{
|
||||
BuildTreeStructure(objectAssetItemDic);
|
||||
}
|
||||
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {exportableAssetsList.Count} exportable assets";
|
||||
|
||||
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
|
||||
@@ -219,7 +237,7 @@ namespace AssetStudioCLI
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
var fileNode = new BaseNode(); //RootNode
|
||||
var fileNode = new BaseNode(assetsFile.fileName); //RootNode
|
||||
|
||||
foreach (var obj in assetsFile.Objects)
|
||||
{
|
||||
@@ -254,7 +272,6 @@ namespace AssetStudioCLI
|
||||
}
|
||||
|
||||
var parentNode = fileNode;
|
||||
|
||||
if (m_GameObject.m_Transform != null)
|
||||
{
|
||||
if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father))
|
||||
@@ -270,14 +287,13 @@ namespace AssetStudioCLI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parentNode.nodes.Add(currentNode);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNode.nodes.Count > 0)
|
||||
{
|
||||
GenerateFullPath(fileNode, fileNode.Text);
|
||||
gameObjectTree.Add(fileNode);
|
||||
}
|
||||
|
||||
@@ -288,13 +304,29 @@ namespace AssetStudioCLI
|
||||
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>();
|
||||
string info = "";
|
||||
if (exportableAssetsList.Count > 0)
|
||||
if (parsedAssetsList.Count > 0)
|
||||
{
|
||||
foreach (var asset in exportableAssetsList)
|
||||
foreach (var asset in parsedAssetsList)
|
||||
{
|
||||
if (exportableAssetsCountDict.ContainsKey(asset.Type))
|
||||
{
|
||||
@@ -313,7 +345,7 @@ namespace AssetStudioCLI
|
||||
}
|
||||
if (exportableAssetsCountDict.Count > 1)
|
||||
{
|
||||
info += $"#\n# Total: {exportableAssetsList.Count} assets";
|
||||
info += $"#\n# Total: {parsedAssetsList.Count} assets";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -335,7 +367,7 @@ namespace AssetStudioCLI
|
||||
{
|
||||
switch (CLIOptions.o_workMode.Value)
|
||||
{
|
||||
case WorkMode.ExportLive2D:
|
||||
case WorkMode.Live2D:
|
||||
case WorkMode.SplitObjects:
|
||||
break;
|
||||
default:
|
||||
@@ -346,34 +378,34 @@ namespace AssetStudioCLI
|
||||
|
||||
private static void FilterAssets()
|
||||
{
|
||||
var assetsCount = exportableAssetsList.Count;
|
||||
var assetsCount = parsedAssetsList.Count;
|
||||
var filteredAssets = new List<AssetItem>();
|
||||
|
||||
switch(CLIOptions.filterBy)
|
||||
{
|
||||
case FilterBy.Name:
|
||||
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.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 = exportableAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.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."
|
||||
);
|
||||
break;
|
||||
case FilterBy.PathID:
|
||||
filteredAssets = exportableAssetsList.FindAll(x => CLIOptions.o_filterByPathID.Value.Any(y => x.m_PathID.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByPathID.Value.Any(y => x.m_PathID.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs."
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameOrContainer:
|
||||
filteredAssets = exportableAssetsList.FindAll(x =>
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
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)
|
||||
);
|
||||
@@ -383,7 +415,7 @@ namespace AssetStudioCLI
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameAndContainer:
|
||||
filteredAssets = exportableAssetsList.FindAll(x =>
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
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)
|
||||
);
|
||||
@@ -394,18 +426,21 @@ namespace AssetStudioCLI
|
||||
);
|
||||
break;
|
||||
}
|
||||
exportableAssetsList.Clear();
|
||||
exportableAssetsList = filteredAssets;
|
||||
parsedAssetsList.Clear();
|
||||
parsedAssetsList = filteredAssets;
|
||||
}
|
||||
|
||||
public static void ExportAssets()
|
||||
{
|
||||
var savePath = CLIOptions.o_outputFolder.Value;
|
||||
var toExportCount = exportableAssetsList.Count;
|
||||
var toExportCount = parsedAssetsList.Count;
|
||||
var exportedCount = 0;
|
||||
|
||||
var groupOption = CLIOptions.o_groupAssetsBy.Value;
|
||||
foreach (var asset in exportableAssetsList)
|
||||
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)
|
||||
@@ -438,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;
|
||||
}
|
||||
}
|
||||
@@ -475,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)
|
||||
@@ -510,13 +609,14 @@ namespace AssetStudioCLI
|
||||
new XElement("Assets",
|
||||
new XAttribute("filename", filename),
|
||||
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
|
||||
exportableAssetsList.Select(
|
||||
parsedAssetsList.Select(
|
||||
asset => new XElement("Asset",
|
||||
new XElement("Name", asset.Text),
|
||||
new XElement("Container", asset.Container),
|
||||
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)
|
||||
)
|
||||
)
|
||||
@@ -526,7 +626,7 @@ namespace AssetStudioCLI
|
||||
|
||||
break;
|
||||
}
|
||||
Logger.Info($"Finished exporting asset list with {exportableAssetsList.Count} items.");
|
||||
Logger.Info($"Finished exporting asset list with {parsedAssetsList.Count} items.");
|
||||
}
|
||||
|
||||
public static void ExportSplitObjects()
|
||||
@@ -548,7 +648,7 @@ namespace AssetStudioCLI
|
||||
{
|
||||
if (isFiltered)
|
||||
{
|
||||
if (!searchList.Any(searchText => j.gameObject.m_Name.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
if (!searchList.Any(searchText => j.Text.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0))
|
||||
continue;
|
||||
}
|
||||
var gameObjects = new List<GameObject>();
|
||||
@@ -627,66 +727,60 @@ namespace AssetStudioCLI
|
||||
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 = exportableAssetsList.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)
|
||||
|
||||
Progress.Reset();
|
||||
Logger.Info($"Searching for Live2D files...");
|
||||
|
||||
foreach (var mocMonoBehaviour in cubismMocList)
|
||||
{
|
||||
var basePathSet = cubismMocs.Select(x =>
|
||||
{
|
||||
var pathLen = containers.TryGetValue(x, out var itemContainer) ? itemContainer.LastIndexOf("/") : 0;
|
||||
pathLen = pathLen < 0 ? containers[x].Length : pathLen;
|
||||
return itemContainer?.Substring(0, pathLen);
|
||||
}).ToHashSet();
|
||||
if (!containers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
|
||||
continue;
|
||||
|
||||
if (basePathSet.All(x => x == null))
|
||||
{
|
||||
Logger.Error($"Live2D Cubism export error: Cannot find any model related files.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePathSet.Count != cubismMocs.Length)
|
||||
{
|
||||
useFullContainerPath = true;
|
||||
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
|
||||
}
|
||||
var pathSepIndex = fullContainerPath.LastIndexOf('/');
|
||||
var basePath = pathSepIndex > 0
|
||||
? fullContainerPath.Substring(0, pathSepIndex)
|
||||
: fullContainerPath;
|
||||
basePathSet.Add(basePath);
|
||||
mocPathList.Add(fullContainerPath);
|
||||
}
|
||||
|
||||
var basePathList = cubismMocs.Select(x =>
|
||||
if (mocPathList.Count == 0)
|
||||
{
|
||||
containers.TryGetValue(x, out var container);
|
||||
container = useFullContainerPath
|
||||
? container
|
||||
: container?.Substring(0, container.LastIndexOf("/"));
|
||||
return container;
|
||||
}).Where(x => x != null).ToList();
|
||||
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.ToLookup(
|
||||
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
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 parallelTaskCount = CLIOptions.o_maxParallelExportTasks.Value;
|
||||
var modelCounter = 0;
|
||||
foreach (var assets in lookup)
|
||||
{
|
||||
@@ -698,11 +792,16 @@ namespace AssetStudioCLI
|
||||
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, motionMode, forceBezier);
|
||||
var modelExtractor = new Live2DExtractor(assets);
|
||||
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelTaskCount);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>0.18.0.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
53
AssetStudioGUI/AboutForm.Designer.cs
generated
53
AssetStudioGUI/AboutForm.Designer.cs
generated
@@ -49,7 +49,7 @@
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.modVersionLabel = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.basedOnLabel = new System.Windows.Forms.Label();
|
||||
this.label8 = new System.Windows.Forms.Label();
|
||||
this.checkUpdatesLinkLabel = new System.Windows.Forms.LinkLabel();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.licenseRichTextBox = new System.Windows.Forms.RichTextBox();
|
||||
@@ -116,7 +116,8 @@
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(347, 46);
|
||||
this.label2.TabIndex = 0;
|
||||
this.label2.Text = "ArknightsStudio is a modified version of AssetStudio designed for Arknights.";
|
||||
this.label2.Text = "AssetStudio is a tool for exploring, extracting, and exporting assets and asset b" +
|
||||
"undles.";
|
||||
this.label2.UseCompatibleTextRendering = true;
|
||||
//
|
||||
// textBox2
|
||||
@@ -163,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, 113F));
|
||||
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);
|
||||
@@ -203,7 +204,7 @@
|
||||
//
|
||||
this.gitPerfareLinkLabel.AutoSize = true;
|
||||
this.gitPerfareLinkLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.gitPerfareLinkLabel.Location = new System.Drawing.Point(237, 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;
|
||||
@@ -229,13 +230,13 @@
|
||||
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(237, 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;
|
||||
@@ -249,13 +250,13 @@
|
||||
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, 113F));
|
||||
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);
|
||||
this.tableLayoutPanel1.Controls.Add(this.modVersionLabel, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label4, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.basedOnLabel, 1, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label8, 1, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.checkUpdatesLinkLabel, 2, 1);
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 80);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
@@ -286,9 +287,9 @@
|
||||
this.productNamelabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.productNamelabel.Location = new System.Drawing.Point(101, 2);
|
||||
this.productNamelabel.Name = "productNamelabel";
|
||||
this.productNamelabel.Size = new System.Drawing.Size(100, 13);
|
||||
this.productNamelabel.Size = new System.Drawing.Size(103, 13);
|
||||
this.productNamelabel.TabIndex = 1;
|
||||
this.productNamelabel.Text = "ArknightsStudioGUI";
|
||||
this.productNamelabel.Text = "AssetStudioModGUI";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
@@ -296,9 +297,9 @@
|
||||
this.label7.BackColor = System.Drawing.Color.Transparent;
|
||||
this.label7.Location = new System.Drawing.Point(5, 20);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(45, 13);
|
||||
this.label7.Size = new System.Drawing.Size(68, 13);
|
||||
this.label7.TabIndex = 2;
|
||||
this.label7.Text = "Version:";
|
||||
this.label7.Text = "Mod version:";
|
||||
//
|
||||
// modVersionLabel
|
||||
//
|
||||
@@ -307,9 +308,9 @@
|
||||
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(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
|
||||
//
|
||||
@@ -322,21 +323,21 @@
|
||||
this.label4.TabIndex = 4;
|
||||
this.label4.Text = "Based on:";
|
||||
//
|
||||
// basedOnLabel
|
||||
// label8
|
||||
//
|
||||
this.basedOnLabel.AutoSize = true;
|
||||
this.basedOnLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.basedOnLabel.Location = new System.Drawing.Point(101, 38);
|
||||
this.basedOnLabel.Name = "basedOnLabel";
|
||||
this.basedOnLabel.Size = new System.Drawing.Size(123, 13);
|
||||
this.basedOnLabel.TabIndex = 5;
|
||||
this.basedOnLabel.Text = "AssetStudioMod v0.17.0";
|
||||
this.label8.AutoSize = true;
|
||||
this.label8.BackColor = System.Drawing.Color.Transparent;
|
||||
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;
|
||||
this.label8.Text = "AssetStudio v0.16.47";
|
||||
//
|
||||
// checkUpdatesLinkLabel
|
||||
//
|
||||
this.checkUpdatesLinkLabel.AutoSize = true;
|
||||
this.checkUpdatesLinkLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.checkUpdatesLinkLabel.Location = new System.Drawing.Point(237, 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;
|
||||
@@ -390,7 +391,7 @@
|
||||
this.productTitleLabel.Name = "productTitleLabel";
|
||||
this.productTitleLabel.Size = new System.Drawing.Size(384, 30);
|
||||
this.productTitleLabel.TabIndex = 1;
|
||||
this.productTitleLabel.Text = "ArknightsStudioGUI";
|
||||
this.productTitleLabel.Text = "AssetStudioModGUI";
|
||||
this.productTitleLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// CloseButton
|
||||
@@ -413,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
|
||||
@@ -491,7 +492,7 @@
|
||||
private System.Windows.Forms.Label label7;
|
||||
private System.Windows.Forms.Label modVersionLabel;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.Label basedOnLabel;
|
||||
private System.Windows.Forms.Label label8;
|
||||
private System.Windows.Forms.LinkLabel checkUpdatesLinkLabel;
|
||||
private System.Windows.Forms.RichTextBox licenseRichTextBox;
|
||||
private System.Windows.Forms.TextBox textBox2;
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace AssetStudioGUI
|
||||
productVersionLabel.Text = $"v{productVer} [{arch}]";
|
||||
productNamelabel.Text = productName;
|
||||
modVersionLabel.Text = productVer;
|
||||
basedOnLabel.Text = "AssetStudioMod v0.17.4";
|
||||
|
||||
licenseRichTextBox.Text = GetLicenseText();
|
||||
}
|
||||
@@ -44,7 +43,7 @@ namespace AssetStudioGUI
|
||||
|
||||
private void checkUpdatesLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
var ps = new ProcessStartInfo("https://github.com/aelurum/AssetStudio/tags")
|
||||
var ps = new ProcessStartInfo("https://github.com/aelurum/AssetStudio/releases")
|
||||
{
|
||||
UseShellExecute = true
|
||||
};
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<TargetFrameworks>net472;net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||
<AssemblyTitle>ArknightsStudio by aelurum</AssemblyTitle>
|
||||
<AssemblyName>ArknightsStudioGUI</AssemblyName>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright>
|
||||
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
|
||||
<AssemblyName>AssetStudioModGUI</AssemblyName>
|
||||
<Version>0.18.0.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2024</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
332
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
332
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
@@ -39,14 +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.akSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.akTitleMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.akUseExternalAlphaToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.akSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
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();
|
||||
@@ -73,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();
|
||||
@@ -82,8 +87,8 @@
|
||||
this.filterTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem15 = 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();
|
||||
@@ -111,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();
|
||||
@@ -145,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();
|
||||
@@ -162,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();
|
||||
@@ -237,14 +247,12 @@
|
||||
//
|
||||
this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.displayAll,
|
||||
this.useAssetLoadingViaTypetreeToolStripMenuItem,
|
||||
this.assetLoadingToolStripSeparator,
|
||||
this.enablePreview,
|
||||
this.displayInfo,
|
||||
this.akSeparator1,
|
||||
this.akTitleMenuItem,
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem,
|
||||
this.akUseExternalAlphaToolStripMenuItem,
|
||||
this.akSeparator2,
|
||||
this.buildTreeStructureToolStripMenuItem,
|
||||
this.customCompressionTypeToolStripMenuItem,
|
||||
this.toolStripMenuItem14,
|
||||
this.showExpOpt});
|
||||
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
|
||||
@@ -255,19 +263,36 @@
|
||||
//
|
||||
this.displayAll.CheckOnClick = true;
|
||||
this.displayAll.Name = "displayAll";
|
||||
this.displayAll.Size = new System.Drawing.Size(276, 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(276, 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.";
|
||||
@@ -279,72 +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(276, 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);
|
||||
//
|
||||
// akSeparator1
|
||||
//
|
||||
this.akSeparator1.Name = "akSeparator1";
|
||||
this.akSeparator1.Size = new System.Drawing.Size(273, 6);
|
||||
//
|
||||
// akTitleMenuItem
|
||||
//
|
||||
this.akTitleMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.akTitleMenuItem.Enabled = false;
|
||||
this.akTitleMenuItem.Name = "akTitleMenuItem";
|
||||
this.akTitleMenuItem.ShowShortcutKeys = false;
|
||||
this.akTitleMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akTitleMenuItem.Text = "Arknights";
|
||||
//
|
||||
// akFixFaceSpriteNamesToolStripMenuItem
|
||||
//
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Checked = true;
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckOnClick = true;
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Name = "akFixFaceSpriteNamesToolStripMenuItem";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.Text = "Restore names of avg character sprites";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.ToolTipText = "Rename face sprites with numeric names to correct ones";
|
||||
this.akFixFaceSpriteNamesToolStripMenuItem.CheckedChanged += new System.EventHandler(this.akFixFaceSpriteNamesToolStripMenuItem_Check);
|
||||
//
|
||||
// akUseExternalAlphaToolStripMenuItem
|
||||
//
|
||||
this.akUseExternalAlphaToolStripMenuItem.Checked = true;
|
||||
this.akUseExternalAlphaToolStripMenuItem.CheckOnClick = true;
|
||||
this.akUseExternalAlphaToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.akUseExternalAlphaToolStripMenuItem.Name = "akUseExternalAlphaToolStripMenuItem";
|
||||
this.akUseExternalAlphaToolStripMenuItem.Size = new System.Drawing.Size(276, 22);
|
||||
this.akUseExternalAlphaToolStripMenuItem.Text = "Use external alpha texture for sprites";
|
||||
this.akUseExternalAlphaToolStripMenuItem.ToolTipText = "Trying to find an external alpha texture for preview/export sprite assets (Skins," +
|
||||
" Char arts, Avg char arts, etc.)";
|
||||
this.akUseExternalAlphaToolStripMenuItem.CheckedChanged += new System.EventHandler(this.akUseExternalAlphaToolStripMenuItem_Check);
|
||||
//
|
||||
// akSeparator2
|
||||
//
|
||||
this.akSeparator2.Name = "akSeparator2";
|
||||
this.akSeparator2.Size = new System.Drawing.Size(273, 6);
|
||||
//
|
||||
// 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(276, 22);
|
||||
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(276, 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
|
||||
//
|
||||
@@ -357,7 +372,7 @@
|
||||
// showExpOpt
|
||||
//
|
||||
this.showExpOpt.Name = "showExpOpt";
|
||||
this.showExpOpt.Size = new System.Drawing.Size(276, 22);
|
||||
this.showExpOpt.Size = new System.Drawing.Size(241, 22);
|
||||
this.showExpOpt.Text = "Export options";
|
||||
this.showExpOpt.Click += new System.EventHandler(this.showExpOpt_Click);
|
||||
//
|
||||
@@ -379,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
|
||||
//
|
||||
@@ -393,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
|
||||
//
|
||||
@@ -405,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
|
||||
//
|
||||
@@ -426,7 +441,7 @@
|
||||
this.toolStripMenuItem2,
|
||||
this.toolStripMenuItem3,
|
||||
this.toolStripSeparator6,
|
||||
this.allLive2DModelsToolStripMenuItem,
|
||||
this.live2DCubismModelsToolStripMenuItem,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripMenuItem10});
|
||||
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
|
||||
@@ -464,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
|
||||
//
|
||||
@@ -538,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
|
||||
//
|
||||
@@ -602,44 +657,44 @@
|
||||
// debugMenuItem
|
||||
//
|
||||
this.debugMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripMenuItem15,
|
||||
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";
|
||||
//
|
||||
// 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.Click += new System.EventHandler(this.toolStripMenuItem15_Click);
|
||||
//
|
||||
// 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(200, 22);
|
||||
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(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(200, 22);
|
||||
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);
|
||||
//
|
||||
@@ -802,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;
|
||||
@@ -932,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);
|
||||
@@ -941,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";
|
||||
@@ -994,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";
|
||||
@@ -1005,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";
|
||||
@@ -1017,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";
|
||||
@@ -1278,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);
|
||||
@@ -1325,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);
|
||||
@@ -1363,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);
|
||||
@@ -1397,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;
|
||||
@@ -1439,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;
|
||||
@@ -1489,18 +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 akFixFaceSpriteNamesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem akUseExternalAlphaToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator akSeparator1;
|
||||
private System.Windows.Forms.ToolStripMenuItem akTitleMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator akSeparator2;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Arknights;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using Newtonsoft.Json;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
@@ -19,8 +18,6 @@ using System.Timers;
|
||||
using System.Windows.Forms;
|
||||
using static AssetStudioGUI.Studio;
|
||||
using Font = AssetStudio.Font;
|
||||
using SharpImage = SixLabors.ImageSharp;
|
||||
using SharpImageFormat = SixLabors.ImageSharp.PixelFormats;
|
||||
using Microsoft.WindowsAPICodePack.Taskbar;
|
||||
#if NET472
|
||||
using OpenTK;
|
||||
@@ -50,7 +47,6 @@ namespace AssetStudioGUI
|
||||
|
||||
#region SpriteControl
|
||||
private SpriteMaskMode spriteMaskVisibleMode = SpriteMaskMode.On;
|
||||
private bool showDebugInfo = false;
|
||||
#endregion
|
||||
|
||||
#region TexControl
|
||||
@@ -93,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;
|
||||
@@ -133,10 +133,9 @@ namespace AssetStudioGUI
|
||||
displayAll.Checked = Properties.Settings.Default.displayAll;
|
||||
displayInfo.Checked = Properties.Settings.Default.displayInfo;
|
||||
enablePreview.Checked = Properties.Settings.Default.enablePreview;
|
||||
akFixFaceSpriteNamesToolStripMenuItem.Checked = Properties.Settings.Default.fixFaceSpriteNames;
|
||||
akUseExternalAlphaToolStripMenuItem.Checked = Properties.Settings.Default.useExternalAlpha;
|
||||
showConsoleToolStripMenuItem.Checked = Properties.Settings.Default.showConsole;
|
||||
buildTreeStructureToolStripMenuItem.Checked = Properties.Settings.Default.buildTreeStructure;
|
||||
useAssetLoadingViaTypetreeToolStripMenuItem.Checked = Properties.Settings.Default.useTypetreeLoading;
|
||||
FMODinit();
|
||||
listSearchFilterMode.SelectedIndex = 0;
|
||||
|
||||
@@ -174,7 +173,6 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
}
|
||||
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
|
||||
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
|
||||
saveDirectoryBackup = openDirectoryBackup;
|
||||
BuildAssetStructures();
|
||||
@@ -186,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();
|
||||
}
|
||||
@@ -199,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)
|
||||
@@ -274,9 +288,6 @@ namespace AssetStudioGUI
|
||||
typeMap.Clear();
|
||||
classesListView.EndUpdate();
|
||||
|
||||
if (akFixFaceSpriteNamesToolStripMenuItem.Checked)
|
||||
FixFaceSpriteNames();
|
||||
|
||||
var types = exportableAssets.Select(x => x.Type).Distinct().OrderBy(x => x.ToString()).ToArray();
|
||||
foreach (var type in types)
|
||||
{
|
||||
@@ -291,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);
|
||||
@@ -354,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)
|
||||
{
|
||||
@@ -376,7 +387,7 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((lastSelectedItem?.Type == ClassIDType.Sprite && !((Sprite)lastSelectedItem.Asset).m_RD.alphaTexture.IsNull) || lastSelectedItem?.Type == ClassIDType.AkPortraitSprite)
|
||||
else if (lastSelectedItem?.Type == ClassIDType.Sprite && !((Sprite)lastSelectedItem.Asset).m_RD.alphaTexture.IsNull)
|
||||
{
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
@@ -388,10 +399,6 @@ namespace AssetStudioGUI
|
||||
spriteMaskVisibleMode = spriteMaskVisibleMode == SpriteMaskMode.MaskOnly ? SpriteMaskMode.On : SpriteMaskMode.MaskOnly;
|
||||
need = true;
|
||||
break;
|
||||
case Keys.D:
|
||||
showDebugInfo = !showDebugInfo;
|
||||
need = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (need)
|
||||
@@ -446,17 +453,16 @@ namespace AssetStudioGUI
|
||||
switch (lastSelectedItem.Type)
|
||||
{
|
||||
case ClassIDType.Texture2D:
|
||||
case ClassIDType.AkPortraitSprite:
|
||||
case ClassIDType.Sprite:
|
||||
{
|
||||
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;
|
||||
@@ -654,7 +660,7 @@ namespace AssetStudioGUI
|
||||
enableFiltering = false;
|
||||
listSearch.Text = " Filter ";
|
||||
listSearch.ForeColor = SystemColors.GrayText;
|
||||
listSearch.BackColor = System.Drawing.Color.White;
|
||||
listSearch.BackColor = SystemColors.Window;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,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) =>
|
||||
@@ -751,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;
|
||||
@@ -818,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;
|
||||
@@ -830,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);
|
||||
@@ -847,9 +868,6 @@ namespace AssetStudioGUI
|
||||
case ClassIDType.Sprite:
|
||||
PreviewSprite(assetItem, assetItem.Asset as Sprite);
|
||||
break;
|
||||
case ClassIDType.AkPortraitSprite:
|
||||
PreviewAkPortraitSprite(assetItem);
|
||||
break;
|
||||
case ClassIDType.Animator:
|
||||
StatusStripUpdate("Can be exported to FBX file.");
|
||||
break;
|
||||
@@ -872,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);
|
||||
@@ -882,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)
|
||||
@@ -920,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");
|
||||
@@ -934,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";
|
||||
@@ -1022,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);
|
||||
@@ -1094,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)
|
||||
@@ -1295,31 +1358,7 @@ namespace AssetStudioGUI
|
||||
|
||||
private void PreviewSprite(AssetItem assetItem, Sprite m_Sprite)
|
||||
{
|
||||
SharpImage.Image<SharpImageFormat.Bgra32> image;
|
||||
AvgSprite avgSprite = null;
|
||||
|
||||
bool isCharAvgSprite = assetItem.Container.Contains("avg/characters");
|
||||
bool isCharArt = assetItem.Container.Contains("arts/characters");
|
||||
if (akUseExternalAlphaToolStripMenuItem.Checked && (isCharAvgSprite || isCharArt))
|
||||
{
|
||||
avgSprite = isCharAvgSprite ? new AvgSprite(assetItem) : null;
|
||||
|
||||
if (m_Sprite.m_RD.alphaTexture.IsNull)
|
||||
{
|
||||
var charAlphaTex = AkSpriteHelper.TryFindAlphaTex(assetItem, avgSprite, isCharAvgSprite);
|
||||
if (charAlphaTex != null)
|
||||
{
|
||||
m_Sprite.m_RD.alphaTexture.Set(charAlphaTex);
|
||||
m_Sprite.akSplitAlpha = true;
|
||||
}
|
||||
}
|
||||
image = m_Sprite.AkGetImage(avgSprite, spriteMaskMode: spriteMaskVisibleMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = m_Sprite.GetImage(spriteMaskMode: spriteMaskVisibleMode);
|
||||
}
|
||||
|
||||
var image = m_Sprite.GetImage(spriteMaskMode: spriteMaskVisibleMode);
|
||||
if (image != null)
|
||||
{
|
||||
var bitmap = new DirectBitmap(image);
|
||||
@@ -1327,33 +1366,10 @@ namespace AssetStudioGUI
|
||||
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
|
||||
PreviewTexture(bitmap);
|
||||
|
||||
if (!m_Sprite.m_RD.alphaTexture.IsNull && (akUseExternalAlphaToolStripMenuItem.Checked || !m_Sprite.akSplitAlpha))
|
||||
if (!m_Sprite.m_RD.alphaTexture.IsNull)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"Alpha mask: {spriteMaskVisibleMode}");
|
||||
sb.Append(spriteMaskVisibleMode != SpriteMaskMode.Off ? $"Is external mask: {m_Sprite.akSplitAlpha}\n" : "");
|
||||
if (avgSprite != null)
|
||||
{
|
||||
sb.AppendLine($"Alias: \"{avgSprite.Alias}\"");
|
||||
if (showDebugInfo)
|
||||
{
|
||||
sb.AppendLine($"[Debug]");
|
||||
sb.AppendLine($"Is avg hub parsed: {avgSprite.IsHubParsed}");
|
||||
if (avgSprite.IsHubParsed)
|
||||
{
|
||||
sb.AppendLine($"Is face data exist: {avgSprite.FaceSize.Width > 0}");
|
||||
sb.AppendLine($"Is face sprite: {avgSprite.IsFaceSprite}");
|
||||
sb.AppendLine($"Is whole body sprite: {avgSprite.IsWholeBodySprite}");
|
||||
}
|
||||
}
|
||||
StatusStripUpdate("'Ctrl'+'A' - Enable/Disable alpha mask usage. 'Ctrl'+'M' - Show alpha mask only. 'Ctrl'+'D' - Show debug info.");
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("'Ctrl'+'A' - Enable/Disable alpha mask usage. 'Ctrl'+'M' - Show alpha mask only.");
|
||||
}
|
||||
assetItem.InfoText += sb.ToString();
|
||||
assetItem.InfoText += $"Alpha Mask: {spriteMaskVisibleMode}\n";
|
||||
StatusStripUpdate("'Ctrl'+'A' - Enable/Disable alpha mask usage. 'Ctrl'+'M' - Show alpha mask only.");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1362,34 +1378,15 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviewAkPortraitSprite(AssetItem assetItem)
|
||||
{
|
||||
var image = assetItem.AkPortraitSprite.AkGetImage(spriteMaskMode: spriteMaskVisibleMode);
|
||||
if (image != null)
|
||||
{
|
||||
var bitmap = new DirectBitmap(image);
|
||||
image.Dispose();
|
||||
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
|
||||
assetItem.InfoText += $"Alpha mask: {spriteMaskVisibleMode}";
|
||||
PreviewTexture(bitmap);
|
||||
|
||||
StatusStripUpdate("'Ctrl'+'A' - Enable/Disable alpha mask usage. 'Ctrl'+'M' - Show alpha mask only.");
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("Unsupported sprite for preview.");
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviewTexture(DirectBitmap bitmap)
|
||||
{
|
||||
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)
|
||||
@@ -1449,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;
|
||||
@@ -1464,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();
|
||||
|
||||
@@ -1478,34 +1478,6 @@ namespace AssetStudioGUI
|
||||
FMODreset();
|
||||
}
|
||||
|
||||
private void FixFaceSpriteNames()
|
||||
{
|
||||
assetListView.BeginUpdate();
|
||||
for (int i = 0; i < assetListView.Items.Count; i++)
|
||||
{
|
||||
var assetItem = (AssetItem)assetListView.Items[i];
|
||||
if (assetItem.Type == ClassIDType.Sprite)
|
||||
{
|
||||
var m_Sprite = (Sprite)assetItem.Asset;
|
||||
if (akFixFaceSpriteNamesToolStripMenuItem.Checked)
|
||||
{
|
||||
var groupedPattern = new Regex(@"^\d{1,2}\$\d{1,2}$"); // "spriteIndex$groupIndex"
|
||||
var notGroupedPattern = new Regex(@"^\d{1,2}$"); // "spriteIndex"
|
||||
if (groupedPattern.IsMatch(m_Sprite.m_Name) || notGroupedPattern.IsMatch(m_Sprite.m_Name))
|
||||
{
|
||||
var fullName = Path.GetFileNameWithoutExtension(assetItem.Container);
|
||||
assetItem.Text = $"{fullName}#{m_Sprite.m_Name}";
|
||||
}
|
||||
}
|
||||
else if (assetItem.Text != m_Sprite.m_Name)
|
||||
{
|
||||
assetItem.Text = m_Sprite.m_Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
assetListView.EndUpdate();
|
||||
}
|
||||
|
||||
private void tabControl2_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (tabControl2.SelectedIndex == 1 && lastSelectedItem != null)
|
||||
@@ -1520,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)
|
||||
{
|
||||
@@ -1530,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));
|
||||
@@ -1561,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)
|
||||
{
|
||||
@@ -1578,10 +1585,6 @@ namespace AssetStudioGUI
|
||||
{
|
||||
animator = assetPreloadData;
|
||||
}
|
||||
else if (assetPreloadData.Type == ClassIDType.AnimationClip)
|
||||
{
|
||||
animationList.Add(assetPreloadData);
|
||||
}
|
||||
}
|
||||
|
||||
if (animator != null)
|
||||
@@ -1592,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1602,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);
|
||||
}
|
||||
@@ -1635,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);
|
||||
}
|
||||
@@ -1683,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;
|
||||
}
|
||||
}
|
||||
@@ -1751,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)
|
||||
{
|
||||
@@ -1772,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()
|
||||
@@ -1849,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;
|
||||
@@ -1891,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);
|
||||
}
|
||||
}
|
||||
@@ -1936,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)
|
||||
@@ -1959,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;
|
||||
}
|
||||
@@ -1994,26 +2040,6 @@ namespace AssetStudioGUI
|
||||
sceneTreeView.EndUpdate();
|
||||
}
|
||||
|
||||
private void akFixFaceSpriteNamesToolStripMenuItem_Check(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.fixFaceSpriteNames = akFixFaceSpriteNamesToolStripMenuItem.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
FixFaceSpriteNames();
|
||||
}
|
||||
|
||||
private void akUseExternalAlphaToolStripMenuItem_Check(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.useExternalAlpha = akUseExternalAlphaToolStripMenuItem.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
|
||||
if (lastSelectedItem?.Type == ClassIDType.Sprite)
|
||||
{
|
||||
StatusStripUpdate("");
|
||||
PreviewAsset(lastSelectedItem);
|
||||
assetInfoLabel.Text = lastSelectedItem.InfoText;
|
||||
}
|
||||
}
|
||||
|
||||
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var aboutForm = new AboutForm();
|
||||
@@ -2022,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();
|
||||
@@ -2036,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;
|
||||
@@ -2175,6 +2165,158 @@ namespace AssetStudioGUI
|
||||
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()
|
||||
{
|
||||
@@ -2187,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
using Arknights.PortraitSpriteMono;
|
||||
using AssetStudio;
|
||||
using AssetStudioGUI;
|
||||
using AssetStudioGUI.Properties;
|
||||
using Newtonsoft.Json;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SixLabors.ImageSharp.Processing.Processors.Transforms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal static class AkSpriteHelper
|
||||
{
|
||||
public static Texture2D TryFindAlphaTex(AssetItem assetItem, AvgSprite avgSprite, bool isAvgSprite)
|
||||
{
|
||||
Sprite m_Sprite = (Sprite)assetItem.Asset;
|
||||
var imgType = "arts/characters";
|
||||
if (m_Sprite.m_RD.alphaTexture.m_PathID == 0)
|
||||
{
|
||||
if (isAvgSprite)
|
||||
{
|
||||
if (avgSprite?.FullAlphaTexture != null)
|
||||
return avgSprite.FullAlphaTexture;
|
||||
|
||||
imgType = "avg/characters"; //since the avg hub was not found for some reason, let's try to find alpha tex by name
|
||||
}
|
||||
var spriteFullName = Path.GetFileNameWithoutExtension(assetItem.Container);
|
||||
foreach (var item in Studio.exportableAssets)
|
||||
{
|
||||
if (item.Type == ClassIDType.Texture2D)
|
||||
{
|
||||
if (item.Container.Contains(imgType) && item.Container.Contains($"illust_{m_Sprite.m_Name}_material") && item.Text.Contains("[alpha]"))
|
||||
return (Texture2D)item.Asset;
|
||||
if (item.Container.Contains(imgType) && item.Container.Contains(spriteFullName) && item.Text == $"{m_Sprite.m_Name}[alpha]")
|
||||
return (Texture2D)item.Asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Image<Bgra32> AkGetImage(this Sprite m_Sprite, AvgSprite avgSprite = null, SpriteMaskMode spriteMaskMode = SpriteMaskMode.On)
|
||||
{
|
||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
|
||||
{
|
||||
Image<Bgra32> tex = null;
|
||||
Image<Bgra32> alphaTex = null;
|
||||
|
||||
if (avgSprite != null && avgSprite.IsHubParsed)
|
||||
{
|
||||
alphaTex = m_AlphaTexture2D.ConvertToImage(true);
|
||||
if (avgSprite.IsFaceSprite)
|
||||
{
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var faceAlpha = avgSprite.FaceSpriteAlphaTexture.ConvertToImage(true);
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
faceAlpha.Mutate(x => x.Resize(new ResizeOptions { Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch }));
|
||||
}
|
||||
tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
alphaTex.Mutate(x => x.DrawImage(faceAlpha, avgSprite.FacePos, opacity: 1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
tex = m_Texture2D.ConvertToImage(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
|
||||
{
|
||||
tex = CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
}
|
||||
alphaTex = CutImage(m_AlphaTexture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
}
|
||||
|
||||
return ImageRender(tex, alphaTex, spriteMaskMode);
|
||||
}
|
||||
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D) && avgSprite != null && avgSprite.IsHubParsed)
|
||||
{
|
||||
if (!avgSprite.IsFaceSprite)
|
||||
{
|
||||
return m_Texture2D.ConvertToImage(true);
|
||||
}
|
||||
|
||||
var faceImage = m_Texture2D.ConvertToImage(true);
|
||||
var tex = avgSprite.FullTexture.ConvertToImage(true);
|
||||
if (new Size(faceImage.Width, faceImage.Height) != avgSprite.FaceSize)
|
||||
{
|
||||
faceImage.Mutate(x => x.Resize(new ResizeOptions {Size = avgSprite.FaceSize, Sampler = KnownResamplers.Lanczos3, Mode = ResizeMode.Stretch}));
|
||||
}
|
||||
tex.Mutate(x => x.DrawImage(faceImage, avgSprite.FacePos, opacity: 1f));
|
||||
|
||||
return tex;
|
||||
}
|
||||
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D))
|
||||
{
|
||||
return CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Image<Bgra32> AkGetImage(this PortraitSprite portraitSprite, SpriteMaskMode spriteMaskMode = SpriteMaskMode.On)
|
||||
{
|
||||
if (portraitSprite.Texture != null && portraitSprite.AlphaTexture != null)
|
||||
{
|
||||
Image<Bgra32> tex = null;
|
||||
Image<Bgra32> alphaTex = null;
|
||||
|
||||
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
|
||||
{
|
||||
tex = CutImage(portraitSprite.Texture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||
}
|
||||
if (spriteMaskMode != SpriteMaskMode.Off)
|
||||
{
|
||||
alphaTex = CutImage(portraitSprite.AlphaTexture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||
}
|
||||
|
||||
return ImageRender(tex, alphaTex, spriteMaskMode);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<PortraitSprite> GeneratePortraits(AssetItem asset)
|
||||
{
|
||||
var portraits = new List<PortraitSprite>();
|
||||
|
||||
var portraitsDict = ((MonoBehaviour)asset.Asset).ToType();
|
||||
if (portraitsDict == null)
|
||||
{
|
||||
Logger.Warning("Portraits MonoBehaviour is not readable.");
|
||||
return portraits;
|
||||
}
|
||||
var portraitsJson = JsonConvert.SerializeObject(portraitsDict);
|
||||
var portraitsData = JsonConvert.DeserializeObject<PortraitSpriteConfig>(portraitsJson);
|
||||
|
||||
var atlasTex = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == portraitsData._atlas.Texture.m_PathID).Asset;
|
||||
var atlasAlpha = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == portraitsData._atlas.Alpha.m_PathID).Asset;
|
||||
|
||||
foreach (var portraitData in portraitsData._sprites)
|
||||
{
|
||||
var portraitSprite = new PortraitSprite()
|
||||
{
|
||||
Name = portraitData.Name,
|
||||
AssetsFile = atlasTex.assetsFile,
|
||||
Container = asset.Container,
|
||||
Texture = atlasTex,
|
||||
AlphaTexture = atlasAlpha,
|
||||
TextureRect = new Rectf(portraitData.Rect.X, portraitData.Rect.Y, portraitData.Rect.W, portraitData.Rect.H),
|
||||
Rotate = portraitData.Rotate,
|
||||
};
|
||||
portraits.Add(portraitSprite);
|
||||
}
|
||||
|
||||
return portraits;
|
||||
}
|
||||
|
||||
private static Image<Bgra32> ImageRender(Image<Bgra32> tex, Image<Bgra32> alpha, SpriteMaskMode maskMode)
|
||||
{
|
||||
switch (maskMode)
|
||||
{
|
||||
case SpriteMaskMode.On:
|
||||
tex.ApplyRGBMask(alpha, isPreview: true);
|
||||
return tex;
|
||||
case SpriteMaskMode.Off:
|
||||
alpha?.Dispose();
|
||||
return tex;
|
||||
case SpriteMaskMode.MaskOnly:
|
||||
tex?.Dispose();
|
||||
return alpha;
|
||||
case SpriteMaskMode.Export:
|
||||
tex.ApplyRGBMask(alpha);
|
||||
return tex;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IResampler GetResampler(bool isPreview)
|
||||
{
|
||||
IResampler resampler;
|
||||
if (isPreview)
|
||||
{
|
||||
resampler = KnownResamplers.NearestNeighbor;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Settings.Default.resamplerIndex)
|
||||
{
|
||||
case 0:
|
||||
resampler = KnownResamplers.NearestNeighbor;
|
||||
break;
|
||||
case 1: //Bilinear
|
||||
resampler = KnownResamplers.Triangle;
|
||||
break;
|
||||
case 2:
|
||||
resampler = KnownResamplers.Bicubic;
|
||||
break;
|
||||
case 3:
|
||||
resampler = KnownResamplers.MitchellNetravali;
|
||||
break;
|
||||
case 4:
|
||||
resampler = KnownResamplers.Spline;
|
||||
break;
|
||||
case 5:
|
||||
resampler = KnownResamplers.Welch;
|
||||
break;
|
||||
default:
|
||||
resampler = KnownResamplers.MitchellNetravali;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return resampler;
|
||||
}
|
||||
|
||||
private static void ApplyRGBMask(this Image<Bgra32> tex, Image<Bgra32> texMask, bool isPreview = false)
|
||||
{
|
||||
using (texMask)
|
||||
{
|
||||
bool resized = false;
|
||||
if (tex.Width != texMask.Width || tex.Height != texMask.Height)
|
||||
{
|
||||
texMask.Mutate(x => x.Resize(tex.Width, tex.Height, GetResampler(isPreview)));
|
||||
resized = true;
|
||||
}
|
||||
|
||||
var invGamma = 1.0 / (1.0 + Settings.Default.alphaMaskGamma / 10.0);
|
||||
if (Settings.Default.resizedOnly && !resized)
|
||||
{
|
||||
invGamma = 1.0;
|
||||
}
|
||||
|
||||
tex.ProcessPixelRows(texMask, (sourceTex, targetTexMask) =>
|
||||
{
|
||||
for (int y = 0; y < texMask.Height; y++)
|
||||
{
|
||||
var texRow = sourceTex.GetRowSpan(y);
|
||||
var maskRow = targetTexMask.GetRowSpan(y);
|
||||
for (int x = 0; x < maskRow.Length; x++)
|
||||
{
|
||||
var grayscale = (maskRow[x].R + maskRow[x].G + maskRow[x].B) / 3.0;
|
||||
if (invGamma != 1)
|
||||
{
|
||||
grayscale = 255 - Math.Pow((255 - grayscale) / 255, invGamma) * 255;
|
||||
}
|
||||
texRow[x].A = (byte)grayscale;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Image<Bgra32> CutImage(Image<Bgra32> originalImage, Rectf textureRect, float downscaleMultiplier, bool rotate = false)
|
||||
{
|
||||
if (originalImage != null)
|
||||
{
|
||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||
{
|
||||
var newSize = (Size)(new Size(originalImage.Width, originalImage.Height) / downscaleMultiplier);
|
||||
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
||||
}
|
||||
var rectX = (int)Math.Floor(textureRect.x);
|
||||
var rectY = (int)Math.Floor(textureRect.y);
|
||||
var rectRight = (int)Math.Ceiling(textureRect.x + textureRect.width);
|
||||
var rectBottom = (int)Math.Ceiling(textureRect.y + textureRect.height);
|
||||
rectRight = Math.Min(rectRight, originalImage.Width);
|
||||
rectBottom = Math.Min(rectBottom, originalImage.Height);
|
||||
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
|
||||
var spriteImage = originalImage.Clone(x => x.Crop(rect));
|
||||
originalImage.Dispose();
|
||||
if (rotate)
|
||||
{
|
||||
spriteImage.Mutate(x => x.Rotate(RotateMode.Rotate270));
|
||||
}
|
||||
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
|
||||
return spriteImage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using Arknights.AvgCharHubMono;
|
||||
using AssetStudio;
|
||||
using AssetStudioGUI;
|
||||
using SixLabors.ImageSharp;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal class AvgSprite
|
||||
{
|
||||
public Texture2D FaceSpriteAlphaTexture { get; }
|
||||
public Texture2D FullTexture { get; }
|
||||
public Texture2D FullAlphaTexture { get; }
|
||||
public Point FacePos { get; }
|
||||
public Size FaceSize { get; }
|
||||
public string Alias { get; }
|
||||
public bool IsWholeBodySprite { get; }
|
||||
public bool IsFaceSprite { get; }
|
||||
public bool IsHubParsed { get; }
|
||||
|
||||
private AvgSpriteConfig GetCurSpriteGroup(AvgSpriteConfigGroup spriteHubDataGrouped, long spriteItemID, string spriteName)
|
||||
{
|
||||
if (spriteHubDataGrouped.SpriteGroups.Length > 1)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(spriteName))
|
||||
{
|
||||
var groupFromName = int.TryParse(spriteName?.Substring(spriteName.IndexOf('$') + 1, 1), out int groupIndex);
|
||||
if (groupFromName)
|
||||
{
|
||||
return spriteHubDataGrouped.SpriteGroups[groupIndex - 1];
|
||||
}
|
||||
}
|
||||
return spriteHubDataGrouped.SpriteGroups.FirstOrDefault(x => x.Sprites.Any(y => y.Sprite.m_PathID == spriteItemID));
|
||||
}
|
||||
else
|
||||
{
|
||||
return spriteHubDataGrouped.SpriteGroups[0];
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetSpriteHub(AssetItem assetItem, out AvgSpriteConfig spriteHubData)
|
||||
{
|
||||
spriteHubData = null;
|
||||
var avgSpriteHubItem = Studio.exportableAssets.Find(x =>
|
||||
x.Type == ClassIDType.MonoBehaviour
|
||||
&& x.Container == assetItem.Container
|
||||
&& x.Text.IndexOf("AVGCharacterSpriteHub", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
);
|
||||
if (avgSpriteHubItem == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub was not found.");
|
||||
return false;
|
||||
}
|
||||
var spriteHubDict = ((MonoBehaviour)avgSpriteHubItem.Asset).ToType();
|
||||
if (spriteHubDict == null)
|
||||
{
|
||||
Logger.Warning("AVGCharacterSpriteHub is not readable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var spriteHubJson = JsonConvert.SerializeObject(spriteHubDict);
|
||||
if (avgSpriteHubItem.Text.ToLower().Contains("hubgroup"))
|
||||
{
|
||||
var groupedSpriteHub = JsonConvert.DeserializeObject<AvgSpriteConfigGroup>(spriteHubJson);
|
||||
spriteHubData = GetCurSpriteGroup(groupedSpriteHub, assetItem.m_PathID, assetItem.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteHubData = JsonConvert.DeserializeObject<AvgSpriteConfig>(spriteHubJson);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public AvgSprite(AssetItem assetItem)
|
||||
{
|
||||
if (TryGetSpriteHub(assetItem, out var spriteHubData))
|
||||
{
|
||||
IsHubParsed = spriteHubData?.Sprites.Length > 0;
|
||||
}
|
||||
if (IsHubParsed)
|
||||
{
|
||||
var curSpriteData = spriteHubData.Sprites.FirstOrDefault(x => x.Sprite.m_PathID == assetItem.m_PathID);
|
||||
|
||||
if (curSpriteData == null)
|
||||
{
|
||||
Studio.StatusStripUpdate($"Sprite \"{assetItem.Text}\" was not found in the avg sprite hub.");
|
||||
return;
|
||||
}
|
||||
|
||||
Alias = curSpriteData.Alias;
|
||||
IsWholeBodySprite = curSpriteData.IsWholeBody;
|
||||
|
||||
if (spriteHubData.FaceSize.X > 0 && spriteHubData.FaceSize.Y > 0) //If face data exist
|
||||
{
|
||||
var fullTexSpriteData = spriteHubData.Sprites.Last(); //Last sprite item in the list usually contains PathID of Sprite with full texture
|
||||
|
||||
var curSprite = (Sprite)assetItem.Asset;
|
||||
IsFaceSprite = curSprite.m_Rect.width <= 256 && curSprite.m_Rect.height <= 256 && curSprite.m_PathID != fullTexSpriteData.Sprite.m_PathID;
|
||||
|
||||
var curSpriteAlphaID = curSpriteData.AlphaTex.m_PathID;
|
||||
var curSpriteAlphaTex = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == curSpriteAlphaID)?.Asset;
|
||||
if (curSpriteAlphaTex != null)
|
||||
{
|
||||
FaceSpriteAlphaTexture = IsFaceSprite ? curSpriteAlphaTex : null;
|
||||
fullTexSpriteData = IsFaceSprite ? fullTexSpriteData : curSpriteData;
|
||||
}
|
||||
var fullTexSpriteID = fullTexSpriteData.Sprite.m_PathID;
|
||||
var fullTexAlphaID = fullTexSpriteData.AlphaTex.m_PathID;
|
||||
var fullTexSprite = (Sprite)Studio.exportableAssets.Find(x => x.m_PathID == fullTexSpriteID).Asset;
|
||||
|
||||
FullTexture = fullTexSprite.m_RD.texture.TryGet(out var fullTex) ? fullTex : null;
|
||||
FullAlphaTexture = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == fullTexAlphaID)?.Asset;
|
||||
FacePos = new Point((int)Math.Round(spriteHubData.FacePos.X), (int)Math.Round(spriteHubData.FacePos.Y));
|
||||
FaceSize = new Size((int)Math.Round(spriteHubData.FaceSize.X), (int)Math.Round(spriteHubData.FaceSize.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
FullAlphaTexture = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == curSpriteData.AlphaTex.m_PathID).Asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using AssetStudio;
|
||||
|
||||
namespace Arknights.AvgCharHubMono
|
||||
{
|
||||
internal class AvgAssetIDs
|
||||
{
|
||||
public int m_FileID { get; set; }
|
||||
public long m_PathID { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteData
|
||||
{
|
||||
public AvgAssetIDs Sprite { get; set; }
|
||||
public AvgAssetIDs AlphaTex { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public bool IsWholeBody { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteConfig
|
||||
{
|
||||
public AvgSpriteData[] Sprites { get; set; }
|
||||
public Vector2 FaceSize { get; set; }
|
||||
public Vector3 FacePos { get; set; }
|
||||
}
|
||||
|
||||
internal class AvgSpriteConfigGroup
|
||||
{
|
||||
public AvgSpriteConfig[] SpriteGroups { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using AssetStudio;
|
||||
|
||||
|
||||
namespace Arknights
|
||||
{
|
||||
internal class PortraitSprite
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ClassIDType Type { get; }
|
||||
public SerializedFile AssetsFile { get; set; }
|
||||
public string Container { get; set; }
|
||||
public Texture2D Texture { get; set; }
|
||||
public Texture2D AlphaTexture { get; set; }
|
||||
public Rectf TextureRect { get; set; }
|
||||
public bool Rotate { get; set; }
|
||||
public float DownscaleMultiplier { get; }
|
||||
|
||||
public PortraitSprite()
|
||||
{
|
||||
Type = ClassIDType.AkPortraitSprite;
|
||||
DownscaleMultiplier = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
namespace Arknights.PortraitSpriteMono
|
||||
{
|
||||
internal class PortraitRect
|
||||
{
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float W { get; set; }
|
||||
public float H { get; set; }
|
||||
}
|
||||
|
||||
internal class AtlasSprite
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Guid { get; set; }
|
||||
public int Atlas { get; set; }
|
||||
public PortraitRect Rect { get; set; }
|
||||
public bool Rotate { get; set; }
|
||||
}
|
||||
|
||||
internal class TextureIDs
|
||||
{
|
||||
public int m_FileID { get; set; }
|
||||
public long m_PathID { get; set; }
|
||||
}
|
||||
|
||||
internal class AtlasInfo
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public TextureIDs Texture { get; set; }
|
||||
public TextureIDs Alpha { get; set; }
|
||||
public int Size { get; set; }
|
||||
}
|
||||
|
||||
internal class PortraitSpriteConfig
|
||||
{
|
||||
public string m_Name { get; set; }
|
||||
public AtlasSprite[] _sprites { get; set; }
|
||||
public AtlasInfo _atlas { get; set; }
|
||||
public int _index { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Windows.Forms;
|
||||
using AssetStudio;
|
||||
using Arknights;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
@@ -16,7 +15,6 @@ namespace AssetStudioGUI
|
||||
public string InfoText;
|
||||
public string UniqueID;
|
||||
public GameObjectTreeNode TreeNode;
|
||||
public PortraitSprite AkPortraitSprite;
|
||||
|
||||
public AssetItem(Object asset)
|
||||
{
|
||||
@@ -28,19 +26,6 @@ namespace AssetStudioGUI
|
||||
FullSize = asset.byteSize;
|
||||
}
|
||||
|
||||
public AssetItem(PortraitSprite akPortraitSprite)
|
||||
{
|
||||
Asset = null;
|
||||
SourceFile = akPortraitSprite.AssetsFile;
|
||||
Container = akPortraitSprite.Container;
|
||||
Type = akPortraitSprite.Type;
|
||||
TypeString = Type.ToString();
|
||||
Text = akPortraitSprite.Name;
|
||||
m_PathID = -1;
|
||||
FullSize = (long)(akPortraitSprite.TextureRect.width * akPortraitSprite.TextureRect.height * 4);
|
||||
AkPortraitSprite = akPortraitSprite;
|
||||
}
|
||||
|
||||
public void SetSubItems()
|
||||
{
|
||||
SubItems.AddRange(new[]
|
||||
|
||||
@@ -43,6 +43,6 @@ namespace AssetStudioGUI
|
||||
public Bitmap Bitmap => m_bitmap;
|
||||
|
||||
private Bitmap m_bitmap;
|
||||
private readonly GCHandle m_handle;
|
||||
private GCHandle m_handle;
|
||||
}
|
||||
}
|
||||
|
||||
248
AssetStudioGUI/ExportOptions.Designer.cs
generated
248
AssetStudioGUI/ExportOptions.Designer.cs
generated
@@ -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();
|
||||
@@ -69,18 +71,10 @@
|
||||
this.castToBone = new System.Windows.Forms.CheckBox();
|
||||
this.exportAllNodes = new System.Windows.Forms.CheckBox();
|
||||
this.eulerFilter = new System.Windows.Forms.CheckBox();
|
||||
this.akResamplerLabel = new System.Windows.Forms.Label();
|
||||
this.akResamplerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.akSpritesAlphaGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.akGammaNoteLabel = new System.Windows.Forms.Label();
|
||||
this.akResamplerDescLabel = new System.Windows.Forms.Label();
|
||||
this.akResizedOnlyCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.akGammaValueLabel = new System.Windows.Forms.Label();
|
||||
this.akGammaLabel = new System.Windows.Forms.Label();
|
||||
this.akAlphaMaskGammaTrackBar = new System.Windows.Forms.TrackBar();
|
||||
this.akSpritesExportGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.akAddAliasesCheckBox = new System.Windows.Forms.CheckBox();
|
||||
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();
|
||||
@@ -89,17 +83,15 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boneSize)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).BeginInit();
|
||||
this.akSpritesAlphaGroupBox.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.akAlphaMaskGammaTrackBar)).BeginInit();
|
||||
this.akSpritesExportGroupBox.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.parallelExportUpDown)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// OKbutton
|
||||
//
|
||||
this.OKbutton.Location = new System.Drawing.Point(681, 381);
|
||||
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);
|
||||
@@ -107,10 +99,10 @@
|
||||
// Cancel
|
||||
//
|
||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel.Location = new System.Drawing.Point(762, 381);
|
||||
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);
|
||||
@@ -118,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);
|
||||
@@ -133,6 +130,28 @@
|
||||
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;
|
||||
@@ -179,6 +198,7 @@
|
||||
"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";
|
||||
@@ -201,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.Size = new System.Drawing.Size(213, 17);
|
||||
this.convertAudio.TabIndex = 7;
|
||||
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
|
||||
this.convertAudio.Text = "Convert FMOD AudioClip to WAV(PCM)";
|
||||
this.convertAudio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// panel1
|
||||
@@ -319,7 +339,7 @@
|
||||
//
|
||||
// l2dAnimationClipRadioButton
|
||||
//
|
||||
this.l2dAnimationClipRadioButton.AccessibleName = "AnimationClip";
|
||||
this.l2dAnimationClipRadioButton.AccessibleName = "AnimationClipV2";
|
||||
this.l2dAnimationClipRadioButton.AutoSize = true;
|
||||
this.l2dAnimationClipRadioButton.Location = new System.Drawing.Point(172, 5);
|
||||
this.l2dAnimationClipRadioButton.Name = "l2dAnimationClipRadioButton";
|
||||
@@ -580,130 +600,52 @@
|
||||
this.eulerFilter.Text = "EulerFilter";
|
||||
this.eulerFilter.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// akResamplerLabel
|
||||
// parallelExportUpDown
|
||||
//
|
||||
this.akResamplerLabel.AutoSize = true;
|
||||
this.akResamplerLabel.Location = new System.Drawing.Point(6, 21);
|
||||
this.akResamplerLabel.Name = "akResamplerLabel";
|
||||
this.akResamplerLabel.Size = new System.Drawing.Size(120, 13);
|
||||
this.akResamplerLabel.TabIndex = 1;
|
||||
this.akResamplerLabel.Text = "Alpha texture resampler:";
|
||||
this.optionTooltip.SetToolTip(this.akResamplerLabel, "Only affects exported images");
|
||||
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});
|
||||
//
|
||||
// akResamplerComboBox
|
||||
// parallelExportCheckBox
|
||||
//
|
||||
this.akResamplerComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.akResamplerComboBox.FormattingEnabled = true;
|
||||
this.akResamplerComboBox.Items.AddRange(new object[] {
|
||||
"Nearest Neighbor",
|
||||
"Bilinear",
|
||||
"Bicubic",
|
||||
"Mitchell-Netravali",
|
||||
"Spline",
|
||||
"Welch"});
|
||||
this.akResamplerComboBox.Location = new System.Drawing.Point(132, 18);
|
||||
this.akResamplerComboBox.Name = "akResamplerComboBox";
|
||||
this.akResamplerComboBox.Size = new System.Drawing.Size(162, 21);
|
||||
this.akResamplerComboBox.TabIndex = 2;
|
||||
this.optionTooltip.SetToolTip(this.akResamplerComboBox, "Only affects exported images");
|
||||
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);
|
||||
//
|
||||
// akSpritesAlphaGroupBox
|
||||
// parallelExportMaxLabel
|
||||
//
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akGammaNoteLabel);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akResamplerDescLabel);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akResamplerLabel);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akResamplerComboBox);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akResizedOnlyCheckBox);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akGammaValueLabel);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akGammaLabel);
|
||||
this.akSpritesAlphaGroupBox.Controls.Add(this.akAlphaMaskGammaTrackBar);
|
||||
this.akSpritesAlphaGroupBox.Location = new System.Drawing.Point(537, 13);
|
||||
this.akSpritesAlphaGroupBox.Name = "akSpritesAlphaGroupBox";
|
||||
this.akSpritesAlphaGroupBox.Size = new System.Drawing.Size(300, 178);
|
||||
this.akSpritesAlphaGroupBox.TabIndex = 4;
|
||||
this.akSpritesAlphaGroupBox.TabStop = false;
|
||||
this.akSpritesAlphaGroupBox.Text = "Sprites: Alpha Texture [Arknights]";
|
||||
//
|
||||
// akGammaNoteLabel
|
||||
//
|
||||
this.akGammaNoteLabel.AutoSize = true;
|
||||
this.akGammaNoteLabel.ForeColor = System.Drawing.SystemColors.GrayText;
|
||||
this.akGammaNoteLabel.Location = new System.Drawing.Point(6, 138);
|
||||
this.akGammaNoteLabel.Name = "akGammaNoteLabel";
|
||||
this.akGammaNoteLabel.Size = new System.Drawing.Size(230, 13);
|
||||
this.akGammaNoteLabel.TabIndex = 8;
|
||||
this.akGammaNoteLabel.Text = "* Gamma settings also affect the preview image";
|
||||
//
|
||||
// akResamplerDescLabel
|
||||
//
|
||||
this.akResamplerDescLabel.AutoSize = true;
|
||||
this.akResamplerDescLabel.ForeColor = System.Drawing.SystemColors.GrayText;
|
||||
this.akResamplerDescLabel.Location = new System.Drawing.Point(6, 43);
|
||||
this.akResamplerDescLabel.Name = "akResamplerDescLabel";
|
||||
this.akResamplerDescLabel.Size = new System.Drawing.Size(251, 13);
|
||||
this.akResamplerDescLabel.TabIndex = 3;
|
||||
this.akResamplerDescLabel.Text = "Alpha texture upscale method for 2048x2048 sprites";
|
||||
//
|
||||
// akResizedOnlyCheckBox
|
||||
//
|
||||
this.akResizedOnlyCheckBox.AutoSize = true;
|
||||
this.akResizedOnlyCheckBox.Checked = true;
|
||||
this.akResizedOnlyCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.akResizedOnlyCheckBox.Location = new System.Drawing.Point(172, 85);
|
||||
this.akResizedOnlyCheckBox.Name = "akResizedOnlyCheckBox";
|
||||
this.akResizedOnlyCheckBox.Size = new System.Drawing.Size(122, 17);
|
||||
this.akResizedOnlyCheckBox.TabIndex = 6;
|
||||
this.akResizedOnlyCheckBox.Text = "Apply to resized only";
|
||||
this.akResizedOnlyCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// akGammaValueLabel
|
||||
//
|
||||
this.akGammaValueLabel.AutoSize = true;
|
||||
this.akGammaValueLabel.Location = new System.Drawing.Point(111, 86);
|
||||
this.akGammaValueLabel.Name = "akGammaValueLabel";
|
||||
this.akGammaValueLabel.Size = new System.Drawing.Size(41, 13);
|
||||
this.akGammaValueLabel.TabIndex = 5;
|
||||
this.akGammaValueLabel.Text = "Default";
|
||||
//
|
||||
// akGammaLabel
|
||||
//
|
||||
this.akGammaLabel.AutoSize = true;
|
||||
this.akGammaLabel.Location = new System.Drawing.Point(6, 86);
|
||||
this.akGammaLabel.Name = "akGammaLabel";
|
||||
this.akGammaLabel.Size = new System.Drawing.Size(86, 13);
|
||||
this.akGammaLabel.TabIndex = 4;
|
||||
this.akGammaLabel.Text = "Shadow gamma:";
|
||||
//
|
||||
// akAlphaMaskGammaTrackBar
|
||||
//
|
||||
this.akAlphaMaskGammaTrackBar.LargeChange = 2;
|
||||
this.akAlphaMaskGammaTrackBar.Location = new System.Drawing.Point(6, 102);
|
||||
this.akAlphaMaskGammaTrackBar.Maximum = 5;
|
||||
this.akAlphaMaskGammaTrackBar.Minimum = -5;
|
||||
this.akAlphaMaskGammaTrackBar.Name = "akAlphaMaskGammaTrackBar";
|
||||
this.akAlphaMaskGammaTrackBar.Size = new System.Drawing.Size(288, 45);
|
||||
this.akAlphaMaskGammaTrackBar.TabIndex = 7;
|
||||
this.akAlphaMaskGammaTrackBar.Scroll += new System.EventHandler(this.akAlphaMaskGammaTrackBar_Scroll);
|
||||
//
|
||||
// akSpritesExportGroupBox
|
||||
//
|
||||
this.akSpritesExportGroupBox.Controls.Add(this.akAddAliasesCheckBox);
|
||||
this.akSpritesExportGroupBox.Location = new System.Drawing.Point(537, 197);
|
||||
this.akSpritesExportGroupBox.Name = "akSpritesExportGroupBox";
|
||||
this.akSpritesExportGroupBox.Size = new System.Drawing.Size(300, 178);
|
||||
this.akSpritesExportGroupBox.TabIndex = 5;
|
||||
this.akSpritesExportGroupBox.TabStop = false;
|
||||
this.akSpritesExportGroupBox.Text = "Sprites: Export [Arknights]";
|
||||
//
|
||||
// akAddAliasesCheckBox
|
||||
//
|
||||
this.akAddAliasesCheckBox.AutoSize = true;
|
||||
this.akAddAliasesCheckBox.Location = new System.Drawing.Point(6, 28);
|
||||
this.akAddAliasesCheckBox.Name = "akAddAliasesCheckBox";
|
||||
this.akAddAliasesCheckBox.Size = new System.Drawing.Size(261, 17);
|
||||
this.akAddAliasesCheckBox.TabIndex = 1;
|
||||
this.akAddAliasesCheckBox.Text = "Add aliases to avg character sprite names (if exist)";
|
||||
this.akAddAliasesCheckBox.UseVisualStyleBackColor = true;
|
||||
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
|
||||
//
|
||||
@@ -711,10 +653,8 @@
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(849, 416);
|
||||
this.ClientSize = new System.Drawing.Size(549, 416);
|
||||
this.Controls.Add(this.l2dGroupBox);
|
||||
this.Controls.Add(this.akSpritesExportGroupBox);
|
||||
this.Controls.Add(this.akSpritesAlphaGroupBox);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.Cancel);
|
||||
@@ -740,11 +680,7 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boneSize)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).EndInit();
|
||||
this.akSpritesAlphaGroupBox.ResumeLayout(false);
|
||||
this.akSpritesAlphaGroupBox.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.akAlphaMaskGammaTrackBar)).EndInit();
|
||||
this.akSpritesExportGroupBox.ResumeLayout(false);
|
||||
this.akSpritesExportGroupBox.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.parallelExportUpDown)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@@ -786,22 +722,16 @@
|
||||
private System.Windows.Forms.ToolTip optionTooltip;
|
||||
private System.Windows.Forms.CheckBox exportSpriteWithAlphaMask;
|
||||
private System.Windows.Forms.RadioButton towebp;
|
||||
private System.Windows.Forms.GroupBox akSpritesAlphaGroupBox;
|
||||
private System.Windows.Forms.TrackBar akAlphaMaskGammaTrackBar;
|
||||
private System.Windows.Forms.Label akResamplerDescLabel;
|
||||
private System.Windows.Forms.Label akResamplerLabel;
|
||||
private System.Windows.Forms.ComboBox akResamplerComboBox;
|
||||
private System.Windows.Forms.CheckBox akResizedOnlyCheckBox;
|
||||
private System.Windows.Forms.Label akGammaValueLabel;
|
||||
private System.Windows.Forms.Label akGammaLabel;
|
||||
private System.Windows.Forms.GroupBox akSpritesExportGroupBox;
|
||||
private System.Windows.Forms.CheckBox akAddAliasesCheckBox;
|
||||
private System.Windows.Forms.Label akGammaNoteLabel;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -30,17 +30,16 @@ namespace AssetStudioGUI
|
||||
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
|
||||
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
|
||||
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
|
||||
|
||||
//Arknights
|
||||
akResamplerComboBox.SelectedIndex = Properties.Settings.Default.resamplerIndex;
|
||||
akAlphaMaskGammaTrackBar.Value = Properties.Settings.Default.alphaMaskGamma;
|
||||
akGammaValueLabel.Text = akAlphaMaskGammaTrackBar.Value == 0 ? "Default" : $"{akAlphaMaskGammaTrackBar.Value * 10:+#;-#;0}%";
|
||||
akResizedOnlyCheckBox.Checked = Properties.Settings.Default.resizedOnly;
|
||||
akAddAliasesCheckBox.Checked = Properties.Settings.Default.addAliases;
|
||||
|
||||
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)
|
||||
@@ -65,31 +64,26 @@ namespace AssetStudioGUI
|
||||
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
|
||||
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
|
||||
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
|
||||
|
||||
//Arknights
|
||||
Properties.Settings.Default.resamplerIndex = akResamplerComboBox.SelectedIndex;
|
||||
Properties.Settings.Default.alphaMaskGamma = akAlphaMaskGammaTrackBar.Value;
|
||||
Properties.Settings.Default.resizedOnly = akResizedOnlyCheckBox.Checked;
|
||||
Properties.Settings.Default.addAliases = akAddAliasesCheckBox.Checked;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
//Arknights
|
||||
private void akAlphaMaskGammaTrackBar_Scroll(object sender, EventArgs e)
|
||||
{
|
||||
akGammaValueLabel.Text = akAlphaMaskGammaTrackBar.Value == 0 ? "Default" : $"{akAlphaMaskGammaTrackBar.Value * 10:+#;-#;0}%";
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void parallelExportCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
parallelExportUpDown.Enabled = parallelExportCheckBox.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,4 +120,10 @@
|
||||
<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>
|
||||
@@ -1,7 +1,4 @@
|
||||
using Arknights;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -12,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))
|
||||
@@ -240,109 +183,43 @@ namespace AssetStudioGUI
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportSprite(AssetItem item, string exportPath)
|
||||
{
|
||||
Image<Bgra32> image;
|
||||
AvgSprite avgSprite = null;
|
||||
var alias = "";
|
||||
var m_Sprite = (Sprite)item.Asset;
|
||||
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
||||
var type = Properties.Settings.Default.convertType;
|
||||
var isCharAvgSprite = item.Container.Contains("avg/characters");
|
||||
var isCharArt = item.Container.Contains("arts/characters");
|
||||
|
||||
if (isCharAvgSprite)
|
||||
{
|
||||
avgSprite = new AvgSprite(item);
|
||||
|
||||
if (Properties.Settings.Default.addAliases && !string.IsNullOrEmpty(avgSprite.Alias))
|
||||
{
|
||||
alias = $"_{avgSprite.Alias}";
|
||||
}
|
||||
}
|
||||
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath, alias))
|
||||
return false;
|
||||
|
||||
if (Properties.Settings.Default.useExternalAlpha && (isCharAvgSprite || isCharArt))
|
||||
{
|
||||
if (m_Sprite.m_RD.alphaTexture.IsNull)
|
||||
{
|
||||
var charAlphaAtlas = AkSpriteHelper.TryFindAlphaTex(item, avgSprite, isCharAvgSprite);
|
||||
if (charAlphaAtlas != null)
|
||||
{
|
||||
m_Sprite.m_RD.alphaTexture.Set(charAlphaAtlas);
|
||||
m_Sprite.akSplitAlpha = true;
|
||||
}
|
||||
}
|
||||
image = m_Sprite.AkGetImage(avgSprite, spriteMaskMode: spriteMaskMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = m_Sprite.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 ExportPortraitSprite(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 = item.AkPortraitSprite.AkGetImage(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 (item.Asset == null)
|
||||
return false;
|
||||
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, string alias = "")
|
||||
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath, string mode = "Export")
|
||||
{
|
||||
var fileName = FixFileName(item.Text) + alias;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -399,9 +276,7 @@ namespace AssetStudioGUI
|
||||
|
||||
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
||||
{
|
||||
if (item.Asset == null)
|
||||
return false;
|
||||
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)
|
||||
@@ -409,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);
|
||||
@@ -422,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:
|
||||
@@ -439,10 +320,6 @@ namespace AssetStudioGUI
|
||||
return ExportVideoClip(item, exportPath);
|
||||
case ClassIDType.MovieTexture:
|
||||
return ExportMovieTexture(item, exportPath);
|
||||
case ClassIDType.Sprite:
|
||||
return ExportSprite(item, exportPath);
|
||||
case ClassIDType.AkPortraitSprite:
|
||||
return ExportPortraitSprite(item, exportPath);
|
||||
case ClassIDType.Animator:
|
||||
return ExportAnimator(item, exportPath);
|
||||
case ClassIDType.AnimationClip:
|
||||
@@ -454,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, '_'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
class GUILogger : ILogger
|
||||
{
|
||||
public bool ShowErrorMessage = false;
|
||||
private bool IsFileLoggerRunning = false;
|
||||
private string LoggerInitString;
|
||||
private string FileLogName;
|
||||
private string FileLogPath;
|
||||
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
|
||||
@@ -23,19 +29,23 @@ namespace AssetStudioGUI
|
||||
set
|
||||
{
|
||||
_useFileLogger = value;
|
||||
if (_useFileLogger && !IsFileLoggerRunning)
|
||||
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);
|
||||
fileLogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
|
||||
fileLogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileLogName);
|
||||
tokenSource = new CancellationTokenSource();
|
||||
isFileLoggerRunning = true;
|
||||
|
||||
LogToFile(LoggerEvent.Verbose, $"# {LoggerInitString} - Logger launched #");
|
||||
IsFileLoggerRunning = true;
|
||||
ConcurrentFileWriter(tokenSource.Token);
|
||||
LogToFile(LoggerEvent.Verbose, $"# {loggerInitString} - Logger launched #");
|
||||
}
|
||||
else if (!_useFileLogger && IsFileLoggerRunning)
|
||||
else if (!_useFileLogger && isFileLoggerRunning)
|
||||
{
|
||||
LogToFile(LoggerEvent.Verbose, "# Logger closed #");
|
||||
IsFileLoggerRunning = false;
|
||||
isFileLoggerRunning = false;
|
||||
tokenSource.Cancel();
|
||||
tokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +57,7 @@ namespace AssetStudioGUI
|
||||
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}]";
|
||||
loggerInitString = $"{appAssembly.Name} v{appAssembly.Version} [{arch}] [{frameworkName}]";
|
||||
try
|
||||
{
|
||||
Console.Title = $"Console Logger - {appAssembly.Name} v{appAssembly.Version}";
|
||||
@@ -57,7 +67,9 @@ namespace AssetStudioGUI
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Console.WriteLine($"# {LoggerInitString}");
|
||||
|
||||
ConcurrentConsoleWriter();
|
||||
Console.WriteLine($"# {loggerInitString}");
|
||||
}
|
||||
|
||||
private static string ColorLogLevel(LoggerEvent logLevel)
|
||||
@@ -79,7 +91,7 @@ namespace AssetStudioGUI
|
||||
private static string FormatMessage(LoggerEvent logMsgLevel, string message, bool toConsole)
|
||||
{
|
||||
message = message.TrimEnd();
|
||||
var multiLine = message.Contains('\n');
|
||||
var multiLine = message.Contains("\n");
|
||||
|
||||
string formattedMessage;
|
||||
if (toConsole)
|
||||
@@ -88,7 +100,7 @@ namespace AssetStudioGUI
|
||||
formattedMessage = $"{colorLogLevel} {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ");
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ") + $"\n{colorLogLevel}";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -99,19 +111,48 @@ namespace AssetStudioGUI
|
||||
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;
|
||||
}
|
||||
|
||||
private async void LogToFile(LoggerEvent logMsgLevel, string message)
|
||||
private void ConcurrentFileWriter(CancellationToken token)
|
||||
{
|
||||
using (var sw = new StreamWriter(FileLogPath, append: true, System.Text.Encoding.UTF8))
|
||||
Task.Run(() =>
|
||||
{
|
||||
await sw.WriteLineAsync(FormatMessage(logMsgLevel, message, toConsole: false));
|
||||
}
|
||||
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)
|
||||
@@ -123,7 +164,9 @@ namespace AssetStudioGUI
|
||||
}
|
||||
|
||||
//Console logger
|
||||
Console.WriteLine(FormatMessage(loggerEvent, message, toConsole: true));
|
||||
if (!ShowDebugMessage && loggerEvent == LoggerEvent.Debug)
|
||||
return;
|
||||
LogToConsole(loggerEvent, message);
|
||||
|
||||
//GUI logger
|
||||
switch (loggerEvent)
|
||||
@@ -132,14 +175,7 @@ namespace AssetStudioGUI
|
||||
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;
|
||||
|
||||
226
AssetStudioGUI/ParallelExport.cs
Normal file
226
AssetStudioGUI/ParallelExport.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
122
AssetStudioGUI/Properties/Settings.Designer.cs
generated
122
AssetStudioGUI/Properties/Settings.Designer.cs
generated
@@ -12,7 +12,7 @@ namespace AssetStudioGUI.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.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())));
|
||||
@@ -287,78 +287,6 @@ namespace AssetStudioGUI.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool fixFaceSpriteNames {
|
||||
get {
|
||||
return ((bool)(this["fixFaceSpriteNames"]));
|
||||
}
|
||||
set {
|
||||
this["fixFaceSpriteNames"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool useExternalAlpha {
|
||||
get {
|
||||
return ((bool)(this["useExternalAlpha"]));
|
||||
}
|
||||
set {
|
||||
this["useExternalAlpha"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool addAliases {
|
||||
get {
|
||||
return ((bool)(this["addAliases"]));
|
||||
}
|
||||
set {
|
||||
this["addAliases"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("3")]
|
||||
public int resamplerIndex {
|
||||
get {
|
||||
return ((int)(this["resamplerIndex"]));
|
||||
}
|
||||
set {
|
||||
this["resamplerIndex"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool resizedOnly {
|
||||
get {
|
||||
return ((bool)(this["resizedOnly"]));
|
||||
}
|
||||
set {
|
||||
this["resizedOnly"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("2")]
|
||||
public int alphaMaskGamma {
|
||||
get {
|
||||
return ((int)(this["alphaMaskGamma"]));
|
||||
}
|
||||
set {
|
||||
this["alphaMaskGamma"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("MonoBehaviour")]
|
||||
@@ -418,5 +346,53 @@ namespace AssetStudioGUI.Properties {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,24 +68,6 @@
|
||||
<Setting Name="exportSpriteWithMask" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="fixFaceSpriteNames" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="useExternalAlpha" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="addAliases" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="resamplerIndex" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">3</Value>
|
||||
</Setting>
|
||||
<Setting Name="resizedOnly" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="alphaMaskGamma" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">2</Value>
|
||||
</Setting>
|
||||
<Setting Name="l2dMotionMode" Type="CubismLive2DExtractor.Live2DMotionMode" Scope="User">
|
||||
<Value Profile="(Default)">MonoBehaviour</Value>
|
||||
</Setting>
|
||||
@@ -101,5 +83,17 @@
|
||||
<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>
|
||||
@@ -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,7 +181,8 @@ 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)>();
|
||||
allContainers.Clear();
|
||||
var tex2dArrayAssetList = new List<AssetItem>();
|
||||
l2dResourceContainers.Clear();
|
||||
var i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
@@ -185,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;
|
||||
@@ -218,14 +249,16 @@ 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:
|
||||
@@ -275,25 +308,40 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (pptr.TryGet(out var obj))
|
||||
{
|
||||
var asset = objectAssetItemDic[obj];
|
||||
asset.Container = container;
|
||||
allContainers[obj] = container;
|
||||
|
||||
if (asset.Type == ClassIDType.MonoBehaviour && container.Contains("/arts/charportraits/portraits"))
|
||||
objectAssetItemDic[obj].Container = container;
|
||||
switch (obj)
|
||||
{
|
||||
var portraitsList = Arknights.AkSpriteHelper.GeneratePortraits(asset);
|
||||
foreach (var portrait in portraitsList)
|
||||
{
|
||||
exportableAssets.Add(new AssetItem(portrait));
|
||||
}
|
||||
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)
|
||||
{
|
||||
tmp.SetSubItems();
|
||||
}
|
||||
containers.Clear();
|
||||
tex2dArrayAssetList.Clear();
|
||||
|
||||
visibleAssets = exportableAssets;
|
||||
|
||||
@@ -364,7 +412,6 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parentNode.Nodes.Add(currentNode);
|
||||
}
|
||||
}
|
||||
@@ -423,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)
|
||||
@@ -461,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)
|
||||
{
|
||||
@@ -538,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)
|
||||
)
|
||||
)
|
||||
@@ -549,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);
|
||||
}
|
||||
@@ -636,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);
|
||||
@@ -734,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)
|
||||
{
|
||||
@@ -748,17 +906,20 @@ namespace AssetStudioGUI
|
||||
assemblyLoader.Loaded = true;
|
||||
}
|
||||
}
|
||||
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
|
||||
}
|
||||
|
||||
public static string DumpAsset(Object obj)
|
||||
{
|
||||
var str = obj?.Dump();
|
||||
var str = obj.Dump();
|
||||
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
|
||||
str = m_MonoBehaviour.Dump(type);
|
||||
}
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
str = obj.DumpObject();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -769,56 +930,70 @@ 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 motionMode = Properties.Settings.Default.l2dMotionMode;
|
||||
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 =>
|
||||
{
|
||||
var pathLen = allContainers.TryGetValue(x, out var itemContainer) ? itemContainer.LastIndexOf("/") : 0;
|
||||
pathLen = pathLen < 0 ? allContainers[x].Length : pathLen;
|
||||
return itemContainer?.Substring(0, pathLen);
|
||||
}).ToHashSet();
|
||||
if (!l2dResourceContainers.TryGetValue(mocMonoBehaviour, out var fullContainerPath))
|
||||
continue;
|
||||
|
||||
if (basePathSet.All(x => x == null))
|
||||
{
|
||||
Logger.Error($"Live2D Cubism export error\r\nCannot find any model related files");
|
||||
StatusStripUpdate("Live2D export canceled");
|
||||
Progress.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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 basePathList = cubismMocs.Select(x =>
|
||||
var basePathSet = mocPathDict.Values.Select(x => x.Item2).ToHashSet();
|
||||
var useFullContainerPath = mocPathDict.Count != basePathSet.Count;
|
||||
foreach (var moc in mocList)
|
||||
{
|
||||
allContainers.TryGetValue(x, out var container);
|
||||
container = useFullContainerPath
|
||||
? container
|
||||
: container?.Substring(0, container.LastIndexOf("/"));
|
||||
return container;
|
||||
}).Where(x => x != null).ToList();
|
||||
var mocPath = useFullContainerPath
|
||||
? mocPathDict[moc].Item1 //fullContainerPath
|
||||
: mocPathDict[moc].Item2; //basePath
|
||||
mocPathList.Add(mocPath);
|
||||
}
|
||||
mocPathDict.Clear();
|
||||
|
||||
var lookup = allContainers.ToLookup(
|
||||
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
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 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 srcContainer = assets.Key;
|
||||
@@ -829,11 +1004,16 @@ namespace AssetStudioGUI
|
||||
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, motionMode, forceBezier);
|
||||
var modelExtractor = new Live2DExtractor(assets, selClipMotions, selFadeMotions, selFadeLst);
|
||||
modelExtractor.ExtractCubismModel(destPath, modelName, motionMode, assemblyLoader, forceBezier, parallelExportCount);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<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="2.1.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
AssetStudioUtility/CubismLive2DExtractor/CubismCdi3Json.cs
Normal file
35
AssetStudioUtility/CubismLive2DExtractor/CubismCdi3Json.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace CubismLive2DExtractor
|
||||
{
|
||||
public class AnimationCurve
|
||||
public sealed class AnimationCurve
|
||||
{
|
||||
public CubismKeyframeData[] m_Curve { get; set; }
|
||||
public int m_PreInfinity { get; set; }
|
||||
@@ -10,7 +10,7 @@ namespace CubismLive2DExtractor
|
||||
public int m_RotationOrder { get; set; }
|
||||
}
|
||||
|
||||
public class CubismFadeMotion
|
||||
public sealed class CubismFadeMotion
|
||||
{
|
||||
public string m_Name { get; set; }
|
||||
public string MotionName { get; set; }
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace CubismLive2DExtractor
|
||||
{
|
||||
public string Moc;
|
||||
public string[] Textures;
|
||||
public string DisplayInfo;
|
||||
public string Physics;
|
||||
public JObject Motions;
|
||||
public JArray Expressions;
|
||||
|
||||
@@ -7,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++)
|
||||
@@ -127,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)
|
||||
{
|
||||
@@ -160,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)
|
||||
{
|
||||
@@ -183,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))
|
||||
|
||||
62
AssetStudioUtility/CubismLive2DExtractor/CubismObjectList.cs
Normal file
62
AssetStudioUtility/CubismLive2DExtractor/CubismObjectList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
163
AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs
Normal file
163
AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,55 @@
|
||||
////
|
||||
// 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, Live2DMotionMode motionMode, bool forceBezier = false)
|
||||
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; }
|
||||
|
||||
public Live2DExtractor(IGrouping<string, AssetStudio.Object> assets, List<AnimationClip> inClipMotions = null, List<MonoBehaviour> inFadeMotions = null, MonoBehaviour inFadeMotionLst = null)
|
||||
{
|
||||
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);
|
||||
|
||||
var expressionList = new List<MonoBehaviour>();
|
||||
var fadeMotionList = new List<MonoBehaviour>();
|
||||
var gameObjects = new List<GameObject>();
|
||||
var animationClips = new List<AnimationClip>();
|
||||
|
||||
var textures = new SortedSet<string>();
|
||||
var eyeBlinkParameters = new HashSet<string>();
|
||||
var lipSyncParameters = new HashSet<string>();
|
||||
var parameterNames = new HashSet<string>();
|
||||
var partNames = new HashSet<string>();
|
||||
MonoBehaviour physics = 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)
|
||||
@@ -48,226 +60,346 @@ namespace CubismLive2DExtractor
|
||||
switch (m_Script.m_ClassName)
|
||||
{
|
||||
case "CubismMoc":
|
||||
File.WriteAllBytes($"{destPath}{modelName}.moc3", ParseMoc(m_MonoBehaviour)); //moc
|
||||
MocMono = m_MonoBehaviour;
|
||||
break;
|
||||
case "CubismPhysicsController":
|
||||
physics = physics ?? m_MonoBehaviour;
|
||||
PhysicsMono = m_MonoBehaviour;
|
||||
break;
|
||||
case "CubismExpressionData":
|
||||
expressionList.Add(m_MonoBehaviour);
|
||||
Expressions.Add(m_MonoBehaviour);
|
||||
break;
|
||||
case "CubismFadeMotionData":
|
||||
fadeMotionList.Add(m_MonoBehaviour);
|
||||
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);
|
||||
EyeBlinkParameters.Add(blinkGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismMouthParameter":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var mouthGameObject))
|
||||
{
|
||||
lipSyncParameters.Add(mouthGameObject.m_Name);
|
||||
LipSyncParameters.Add(mouthGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismParameter":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var paramGameObject))
|
||||
{
|
||||
parameterNames.Add(paramGameObject.m_Name);
|
||||
ParameterNames.Add(paramGameObject.m_Name);
|
||||
}
|
||||
break;
|
||||
case "CubismPart":
|
||||
if (m_MonoBehaviour.m_GameObject.TryGet(out var partGameObject))
|
||||
{
|
||||
partNames.Add(partGameObject.m_Name);
|
||||
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 Texture2D m_Texture2D:
|
||||
using (var image = m_Texture2D.ConvertToImage(flip: true))
|
||||
case AnimationClip m_AnimationClip:
|
||||
if (inClipMotions == null)
|
||||
{
|
||||
using (var file = File.OpenWrite($"{destTexturePath}{m_Texture2D.m_Name}.png"))
|
||||
{
|
||||
image.WriteToStream(file, ImageFormat.Png);
|
||||
}
|
||||
textures.Add($"textures/{m_Texture2D.m_Name}.png"); //texture
|
||||
AnimationClips.Add(m_AnimationClip);
|
||||
}
|
||||
break;
|
||||
case GameObject m_GameObject:
|
||||
gameObjects.Add(m_GameObject);
|
||||
GameObjects.Add(m_GameObject);
|
||||
break;
|
||||
case AnimationClip m_AnimationClip:
|
||||
animationClips.Add(m_AnimationClip);
|
||||
case Texture2D m_Texture2D:
|
||||
Texture2Ds.Add(m_Texture2D);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (textures.Count == 0)
|
||||
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))
|
||||
{
|
||||
Logger.Warning($"No textures found for \"{modelName}\" model.");
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Model Stats:");
|
||||
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($"Part Count: {cubismModel.PartCount}");
|
||||
sb.AppendLine($"Parameter Count: {cubismModel.ParamCount}");
|
||||
Logger.Debug(sb.ToString());
|
||||
|
||||
ParameterNames = cubismModel.ParamNames;
|
||||
PartNames = cubismModel.PartNames;
|
||||
}
|
||||
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)
|
||||
{
|
||||
Logger.Warning($"No textures found for \"{modelName}\" model");
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(destTexturePath);
|
||||
}
|
||||
|
||||
//physics
|
||||
if (physics != null)
|
||||
var textureBag = new ConcurrentBag<string>();
|
||||
var savePathHash = new ConcurrentDictionary<string, bool>();
|
||||
Parallel.ForEach(Texture2Ds, new ParallelOptions { MaxDegreeOfParallelism = parallelTaskCount }, texture2D =>
|
||||
{
|
||||
try
|
||||
var savePath = $"{destTexturePath}{texture2D.m_Name}.png";
|
||||
if (!savePathHash.TryAdd(savePath, true))
|
||||
return;
|
||||
|
||||
using (var image = texture2D.ConvertToImage(flip: true))
|
||||
{
|
||||
var buff = ParsePhysics(physics, assemblyLoader);
|
||||
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
|
||||
using (var file = File.OpenWrite(savePath))
|
||||
{
|
||||
image.WriteToStream(file, ImageFormat.Png);
|
||||
}
|
||||
textureBag.Add($"textures/{texture2D.m_Name}.png");
|
||||
}
|
||||
catch (Exception e)
|
||||
});
|
||||
textures.UnionWith(textureBag);
|
||||
#endregion
|
||||
|
||||
#region physics3.json
|
||||
if (PhysicsMono != null)
|
||||
{
|
||||
var physicsDict = ParseMonoBehaviour(PhysicsMono, CubismMonoBehaviourType.Physics, assemblyLoader);
|
||||
if (physicsDict != null)
|
||||
{
|
||||
Logger.Warning($"Error in parsing physics data: {e.Message}");
|
||||
physics = null;
|
||||
try
|
||||
{
|
||||
var buff = ParsePhysics(physicsDict);
|
||||
File.WriteAllText($"{destPath}{modelName}.physics3.json", buff);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Error in parsing physics data: {e.Message}");
|
||||
PhysicsMono = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PhysicsMono = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//motion
|
||||
#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 && fadeMotionList.Count > 0) //motion from MonoBehaviour
|
||||
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotionLst != null) //Fade motions from Fade Motion List
|
||||
{
|
||||
Logger.Debug("Motion export method: MonoBehaviour (Fade motion)");
|
||||
Directory.CreateDirectory(destMotionPath);
|
||||
foreach (var fadeMotionMono in fadeMotionList)
|
||||
var fadeMotionLstDict = ParseMonoBehaviour(FadeMotionLst, CubismMonoBehaviourType.FadeMotionList, assemblyLoader);
|
||||
if (fadeMotionLstDict != null)
|
||||
{
|
||||
var fadeMotionObj = fadeMotionMono.ToType();
|
||||
if (fadeMotionObj == null)
|
||||
CubismObjectList.AssetsFile = FadeMotionLst.assetsFile;
|
||||
var fadeMotionAssetList = JsonConvert.DeserializeObject<CubismObjectList>(JsonConvert.SerializeObject(fadeMotionLstDict)).GetFadeMotionAssetList();
|
||||
if (fadeMotionAssetList?.Count > 0)
|
||||
{
|
||||
var m_Type = fadeMotionMono.ConvertToTypeTree(assemblyLoader);
|
||||
fadeMotionObj = fadeMotionMono.ToType(m_Type);
|
||||
if (fadeMotionObj == null)
|
||||
{
|
||||
Logger.Warning($"Fade motion \"{fadeMotionMono.m_Name}\" is not readable.");
|
||||
continue;
|
||||
}
|
||||
FadeMotions = fadeMotionAssetList;
|
||||
Logger.Debug($"\"{FadeMotionLst.m_Name}\": found {fadeMotionAssetList.Count} motion(s)");
|
||||
}
|
||||
var fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotion>(JsonConvert.SerializeObject(fadeMotionObj));
|
||||
if (fadeMotion.ParameterIds.Length == 0)
|
||||
continue;
|
||||
|
||||
var motionJson = new CubismMotion3Json(fadeMotion, parameterNames, partNames, forceBezier);
|
||||
|
||||
var animName = Path.GetFileNameWithoutExtension(fadeMotion.m_Name);
|
||||
if (motions.ContainsKey(animName))
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
else if (gameObjects.Count > 0) //motion from AnimationClip
|
||||
|
||||
if (motionMode == Live2DMotionMode.MonoBehaviour && FadeMotions.Count > 0) //motion from MonoBehaviour
|
||||
{
|
||||
var exportMethod = motionMode == Live2DMotionMode.AnimationClip
|
||||
? "AnimationClip"
|
||||
: "AnimationClip (no Fade motions found)";
|
||||
Logger.Debug($"Motion export method: {exportMethod}");
|
||||
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);
|
||||
var converter = new CubismMotion3Converter(rootGameObject, animationClips.ToArray());
|
||||
if (converter.AnimationList.Count > 0)
|
||||
{
|
||||
Directory.CreateDirectory(destMotionPath);
|
||||
}
|
||||
foreach (var animation in converter.AnimationList)
|
||||
{
|
||||
var motionJson = new CubismMotion3Json(animation, forceBezier);
|
||||
|
||||
var animName = animation.Name;
|
||||
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()));
|
||||
}
|
||||
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 motions found for \"{modelName}\" model.");
|
||||
Logger.Warning($"No exportable motions found for \"{modelName}\" model");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"Exported {motions.Count} motion(s)");
|
||||
}
|
||||
#endregion
|
||||
|
||||
//expression
|
||||
#region exp3.json
|
||||
var expressions = new JArray();
|
||||
if (expressionList.Count > 0)
|
||||
var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar;
|
||||
|
||||
if (Expressions.Count > 0)
|
||||
{
|
||||
Directory.CreateDirectory(destExpressionPath);
|
||||
}
|
||||
foreach (var monoBehaviour in expressionList)
|
||||
foreach (var monoBehaviour in Expressions)
|
||||
{
|
||||
var expressionName = monoBehaviour.m_Name.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 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/{expressionName}.exp3.json" }
|
||||
});
|
||||
{
|
||||
{ "Name", expressionName },
|
||||
{ "File", $"expressions/{expressionName}.exp3.json" }
|
||||
});
|
||||
File.WriteAllText($"{destExpressionPath}{expressionName}.exp3.json", JsonConvert.SerializeObject(expression, Formatting.Indented));
|
||||
}
|
||||
#endregion
|
||||
|
||||
//group
|
||||
#region model3.json
|
||||
var groups = new List<CubismModel3Json.SerializableGroup>();
|
||||
|
||||
//Try looking for group IDs among the gameObjects
|
||||
if (eyeBlinkParameters.Count == 0)
|
||||
//Try looking for group IDs among the parameter names manually
|
||||
if (EyeBlinkParameters.Count == 0)
|
||||
{
|
||||
eyeBlinkParameters = gameObjects.Where(x =>
|
||||
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)
|
||||
if (LipSyncParameters.Count == 0)
|
||||
{
|
||||
lipSyncParameters = gameObjects.Where(x =>
|
||||
x.m_Name.ToLower().Contains("mouth")
|
||||
&& x.m_Name.ToLower().Contains("open")
|
||||
&& x.m_Name.ToLower().Contains('y')
|
||||
).Select(x => x.m_Name).ToHashSet();
|
||||
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()
|
||||
});
|
||||
groups.Add(new CubismModel3Json.SerializableGroup
|
||||
{
|
||||
Target = "Parameter",
|
||||
Name = "LipSync",
|
||||
Ids = lipSyncParameters.ToArray()
|
||||
Ids = LipSyncParameters.ToArray()
|
||||
});
|
||||
|
||||
//model
|
||||
var model3 = new CubismModel3Json
|
||||
{
|
||||
Version = 3,
|
||||
@@ -276,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 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 fadeMotion = JsonConvert.DeserializeObject<CubismFadeMotion>(JsonConvert.SerializeObject(fadeMotionDict));
|
||||
if (fadeMotion.ParameterIds.Length == 0)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
public enum Live2DMotionMode
|
||||
{
|
||||
MonoBehaviour,
|
||||
AnimationClip
|
||||
AnimationClipV1,
|
||||
AnimationClipV2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -871,11 +871,11 @@ namespace AssetStudio
|
||||
public int Length;
|
||||
public int Segment;
|
||||
|
||||
public ShaderSubProgramEntry(BinaryReader reader, int[] version)
|
||||
public ShaderSubProgramEntry(BinaryReader reader, UnityVersion version)
|
||||
{
|
||||
Offset = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
if (version >= (2019, 3)) //2019.3 and up
|
||||
{
|
||||
Segment = reader.ReadInt32();
|
||||
}
|
||||
@@ -887,7 +887,7 @@ namespace AssetStudio
|
||||
public ShaderSubProgramEntry[] entries;
|
||||
public ShaderSubProgram[] m_SubPrograms;
|
||||
|
||||
public ShaderProgram(BinaryReader reader, int[] version)
|
||||
public ShaderProgram(BinaryReader reader, UnityVersion version)
|
||||
{
|
||||
var subProgramsCapacity = reader.ReadInt32();
|
||||
entries = new ShaderSubProgramEntry[subProgramsCapacity];
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off && !m_Sprite.akSplitAlpha)
|
||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
|
||||
{
|
||||
Image<Bgra32> tex = null;
|
||||
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user