11 Commits

Author SHA1 Message Date
VaDiM
171962e61f Update version to v0.17.2
- Updated projects and dependencies
2023-08-27 01:47:06 +03:00
VaDiM
c8a21838c9 Some changes to motion list for l2d models
- Motion list is now sorted
- Motions divided into groups (each motion is a separate group)
- Motion names are used as group names
2023-08-27 01:46:06 +03:00
VaDiM
cf67815d53 Minor fixes 2023-08-26 03:22:19 +03:00
VaDiM
94c8b355fe [CLI] Fix asset filter
- Fixed sprite export in sprite only mode
2023-08-14 00:46:27 +03:00
VaDiM
4e41caf203 [CLI] Refactor 2023-08-13 20:58:26 +03:00
VaDiM
74a8555514 Merge branch 'relatedAssets' into AssetStudioMod 2023-08-07 23:20:11 +03:00
VaDiM
e1d883adf6 [CLI] Refactor
- Made some classes static
2023-08-07 23:10:57 +03:00
VaDiM
9784df0e16 [GUI] Add app.manifest for net472 build
- Added long paths support (win10 v1607+)
- Fixed blurring at high DPI with scaling
2023-08-06 20:08:05 +03:00
VaDiM
4d919a2bfe [GUI] Improve Scene Hierarchy tab context menu
- Added "Related assets" item to the context menu
2023-08-05 18:10:36 +03:00
VaDiM
6701f467b7 [CLI] Show the number of successfully loaded assets 2023-07-14 20:20:58 +03:00
VaDiM
50f5da5554 [GUI] Don't count Shaders in unity 2021+ assets 2023-07-14 19:17:56 +03:00
22 changed files with 607 additions and 371 deletions

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks> <TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright> <Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>

View File

@@ -2,13 +2,13 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks> <TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022</Copyright> <Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' "> <ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.5" /> <PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">

View File

@@ -12,7 +12,7 @@ namespace AssetStudio
{ {
public string SpecifyUnityVersion; public string SpecifyUnityVersion;
public List<SerializedFile> assetsFileList = new List<SerializedFile>(); public List<SerializedFile> assetsFileList = new List<SerializedFile>();
private List<ClassIDType> filteredAssetTypesList = new List<ClassIDType>(); private HashSet<ClassIDType> filteredAssetTypesList = new HashSet<ClassIDType>();
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase); internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
@@ -22,35 +22,32 @@ namespace AssetStudio
private HashSet<string> noexistFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private HashSet<string> noexistFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public void SetAssetFilter(ClassIDType classIDType) public void SetAssetFilter(params ClassIDType[] classIDTypes)
{ {
if (filteredAssetTypesList.Count == 0) if (filteredAssetTypesList.Count == 0)
{ {
filteredAssetTypesList.AddRange(new List<ClassIDType> filteredAssetTypesList.UnionWith(new HashSet<ClassIDType>
{ {
ClassIDType.AssetBundle, ClassIDType.AssetBundle,
ClassIDType.ResourceManager, ClassIDType.ResourceManager,
}); });
} }
if (classIDType == ClassIDType.MonoBehaviour) if (classIDTypes.Contains(ClassIDType.MonoBehaviour))
{ {
filteredAssetTypesList.AddRange(new List<ClassIDType> filteredAssetTypesList.Add(ClassIDType.MonoScript);
{
ClassIDType.MonoScript,
ClassIDType.MonoBehaviour
});
} }
else if (classIDTypes.Contains(ClassIDType.Sprite))
{ {
filteredAssetTypesList.Add(classIDType); filteredAssetTypesList.Add(ClassIDType.Texture2D);
} }
filteredAssetTypesList.UnionWith(classIDTypes);
} }
public void SetAssetFilter(List<ClassIDType> classIDTypeList) public void SetAssetFilter(List<ClassIDType> classIDTypeList)
{ {
foreach (ClassIDType classIDType in classIDTypeList) SetAssetFilter(classIDTypeList.ToArray());
SetAssetFilter(classIDType);
} }
public void LoadFilesAndFolders(params string[] path) public void LoadFilesAndFolders(params string[] path)

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle> <AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModCLI</AssemblyName> <AssemblyName>AssetStudioModCLI</AssemblyName>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright> <Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>

View File

@@ -1,9 +1,9 @@
using AssetStudio; using AssetStudio;
using AssetStudioCLI.Options;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using AssetStudioCLI.Options;
namespace AssetStudioCLI namespace AssetStudioCLI
{ {
@@ -21,16 +21,17 @@ namespace AssetStudioCLI
public string LogName; public string LogName;
public string LogPath; public string LogPath;
public CLILogger(CLIOptions options) public CLILogger()
{ {
logOutput = options.o_logOutput.Value; logOutput = CLIOptions.o_logOutput.Value;
logMinLevel = options.o_logLevel.Value; logMinLevel = CLIOptions.o_logLevel.Value;
LogName = $"AssetStudioCLI_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"; var appAssembly = typeof(Program).Assembly.GetName();
LogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName); LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName);
var arch = Environment.Is64BitProcess ? "x64" : "x32";
var ver = typeof(Program).Assembly.GetName().Version; LogToFile(LoggerEvent.Verbose, $"---{appAssembly.Name} v{appAssembly.Version} [{arch}] | Logger launched---\n" +
LogToFile(LoggerEvent.Verbose, $"---AssetStudioCLI v{ver} | Logger launched---\n" + $"CMD Args: {string.Join(" ", CLIOptions.cliArgs)}");
$"CMD Args: {string.Join(" ", options.cliArgs)}");
} }
private static string ColorLogLevel(LoggerEvent logLevel) private static string ColorLogLevel(LoggerEvent logLevel)

View File

@@ -9,14 +9,38 @@ namespace AssetStudioCLI
{ {
internal static class Exporter internal static class Exporter
{ {
public static bool ExportTexture2D(AssetItem item, string exportPath, CLIOptions options) public static bool ExportTexture2D(AssetItem item, string exportPath)
{ {
var m_Texture2D = (Texture2D)item.Asset; var m_Texture2D = (Texture2D)item.Asset;
if (options.convertTexture) if (CLIOptions.convertTexture)
{ {
var type = options.o_imageFormat.Value; var type = CLIOptions.o_imageFormat.Value;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath)) if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false; 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); var image = m_Texture2D.ConvertToImage(flip: true);
if (image == null) if (image == null)
{ {
@@ -29,7 +53,7 @@ namespace AssetStudioCLI
{ {
image.WriteToStream(file, type); image.WriteToStream(file, type);
} }
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
} }
@@ -38,12 +62,12 @@ namespace AssetStudioCLI
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath)) if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
return false; return false;
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData()); File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
} }
public static bool ExportAudioClip(AssetItem item, string exportPath, CLIOptions options) public static bool ExportAudioClip(AssetItem item, string exportPath)
{ {
string exportFullPath; string exportFullPath;
var m_AudioClip = (AudioClip)item.Asset; var m_AudioClip = (AudioClip)item.Asset;
@@ -54,11 +78,13 @@ namespace AssetStudioCLI
return false; return false;
} }
var converter = new AudioClipConverter(m_AudioClip); var converter = new AudioClipConverter(m_AudioClip);
if (options.o_audioFormat.Value != AudioFormat.None && converter.IsSupport) if (CLIOptions.o_audioFormat.Value != AudioFormat.None && converter.IsSupport)
{ {
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath)) if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false; return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Converting \"{m_AudioClip.m_Name}\" to wav.."); 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(m_AudioClip.version[0] < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
@@ -66,6 +92,7 @@ namespace AssetStudioCLI
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}"); sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}"); sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
Logger.Debug(sb.ToString()); Logger.Debug(sb.ToString());
}
var buffer = converter.ConvertToWav(m_AudioData); var buffer = converter.ConvertToWav(m_AudioData);
if (buffer == null) if (buffer == null)
@@ -82,7 +109,7 @@ namespace AssetStudioCLI
File.WriteAllBytes(exportFullPath, m_AudioData); File.WriteAllBytes(exportFullPath, m_AudioData);
} }
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
@@ -94,16 +121,19 @@ namespace AssetStudioCLI
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath)) if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
return false; return false;
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
{
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"VideoClip format: {m_VideoClip.m_Format}"); sb.AppendLine($"VideoClip format: {m_VideoClip.m_Format}");
sb.AppendLine($"VideoClip width: {m_VideoClip.Width}"); sb.AppendLine($"VideoClip width: {m_VideoClip.Width}");
sb.AppendLine($"VideoClip height: {m_VideoClip.Height}"); sb.AppendLine($"VideoClip height: {m_VideoClip.Height}");
sb.AppendLine($"VideoClip frame rate: {m_VideoClip.m_FrameRate}"); sb.AppendLine($"VideoClip frame rate: {m_VideoClip.m_FrameRate:.0##}");
sb.AppendLine($"VideoClip split alpha: {m_VideoClip.m_HasSplitAlpha}"); sb.AppendLine($"VideoClip split alpha: {m_VideoClip.m_HasSplitAlpha}");
Logger.Debug(sb.ToString()); Logger.Debug(sb.ToString());
}
m_VideoClip.m_VideoData.WriteData(exportFullPath); m_VideoClip.m_VideoData.WriteData(exportFullPath);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
return false; return false;
@@ -116,7 +146,7 @@ namespace AssetStudioCLI
return false; return false;
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData); File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
@@ -128,16 +158,16 @@ namespace AssetStudioCLI
var str = m_Shader.Convert(); var str = m_Shader.Convert();
File.WriteAllText(exportFullPath, str); File.WriteAllText(exportFullPath, str);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
public static bool ExportTextAsset(AssetItem item, string exportPath, CLIOptions options) public static bool ExportTextAsset(AssetItem item, string exportPath)
{ {
var m_TextAsset = (TextAsset)item.Asset; var m_TextAsset = (TextAsset)item.Asset;
var extension = ".txt"; var extension = ".txt";
var assetExtension = Path.GetExtension(m_TextAsset.m_Name); var assetExtension = Path.GetExtension(m_TextAsset.m_Name);
if (!options.f_notRestoreExtensionName.Value) if (!CLIOptions.f_notRestoreExtensionName.Value)
{ {
if (!string.IsNullOrEmpty(assetExtension)) if (!string.IsNullOrEmpty(assetExtension))
{ {
@@ -156,11 +186,11 @@ namespace AssetStudioCLI
return false; return false;
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script); File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
public static bool ExportMonoBehaviour(AssetItem item, string exportPath, AssemblyLoader assemblyLoader) public static bool ExportMonoBehaviour(AssetItem item, string exportPath)
{ {
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath)) if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
return false; return false;
@@ -168,7 +198,7 @@ namespace AssetStudioCLI
var type = m_MonoBehaviour.ToType(); var type = m_MonoBehaviour.ToType();
if (type == null) if (type == null)
{ {
var m_Type = m_MonoBehaviour.ConvertToTypeTree(assemblyLoader); var m_Type = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader);
type = m_MonoBehaviour.ToType(m_Type); type = m_MonoBehaviour.ToType(m_Type);
} }
if (type != null) if (type != null)
@@ -176,7 +206,7 @@ namespace AssetStudioCLI
var str = JsonConvert.SerializeObject(type, Formatting.Indented); var str = JsonConvert.SerializeObject(type, Formatting.Indented);
File.WriteAllText(exportFullPath, str); File.WriteAllText(exportFullPath, str);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
return false; return false;
@@ -196,15 +226,15 @@ namespace AssetStudioCLI
return false; return false;
File.WriteAllBytes(exportFullPath, m_Font.m_FontData); File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
return false; return false;
} }
public static bool ExportSprite(AssetItem item, string exportPath, CLIOptions options) public static bool ExportSprite(AssetItem item, string exportPath)
{ {
var type = options.o_imageFormat.Value; var type = CLIOptions.o_imageFormat.Value;
var alphaMask = SpriteMaskMode.On; var alphaMask = SpriteMaskMode.On;
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath)) if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false; return false;
@@ -217,7 +247,7 @@ namespace AssetStudioCLI
{ {
image.WriteToStream(file, type); image.WriteToStream(file, type);
} }
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
} }
@@ -230,24 +260,24 @@ namespace AssetStudioCLI
return false; return false;
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData()); File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
public static bool ExportDumpFile(AssetItem item, string exportPath, AssemblyLoader assemblyLoader) public static bool ExportDumpFile(AssetItem item, string exportPath)
{ {
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath)) if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
return false; return false;
var str = item.Asset.Dump(); var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour) if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
{ {
var m_Type = m_MonoBehaviour.ConvertToTypeTree(assemblyLoader); var m_Type = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader);
str = m_MonoBehaviour.Dump(m_Type); str = m_MonoBehaviour.Dump(m_Type);
} }
if (str != null) if (str != null)
{ {
File.WriteAllText(exportFullPath, str); File.WriteAllText(exportFullPath, str);
Logger.Debug($"{item.TypeString}: \"{item.Text}\" saved to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" saved to \"{exportFullPath}\"");
return true; return true;
} }
return false; return false;
@@ -365,18 +395,18 @@ namespace AssetStudioCLI
sb.Replace("NaN", "0"); sb.Replace("NaN", "0");
File.WriteAllText(exportFullPath, sb.ToString()); File.WriteAllText(exportFullPath, sb.ToString());
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
return true; return true;
} }
public static bool ExportConvertFile(AssetItem item, string exportPath, CLIOptions options, AssemblyLoader assemblyLoader) public static bool ExportConvertFile(AssetItem item, string exportPath)
{ {
switch (item.Type) switch (item.Type)
{ {
case ClassIDType.Texture2D: case ClassIDType.Texture2D:
return ExportTexture2D(item, exportPath, options); return ExportTexture2D(item, exportPath);
case ClassIDType.AudioClip: case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath, options); return ExportAudioClip(item, exportPath);
case ClassIDType.VideoClip: case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath); return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture: case ClassIDType.MovieTexture:
@@ -384,13 +414,13 @@ namespace AssetStudioCLI
case ClassIDType.Shader: case ClassIDType.Shader:
return ExportShader(item, exportPath); return ExportShader(item, exportPath);
case ClassIDType.TextAsset: case ClassIDType.TextAsset:
return ExportTextAsset(item, exportPath, options); return ExportTextAsset(item, exportPath);
case ClassIDType.MonoBehaviour: case ClassIDType.MonoBehaviour:
return ExportMonoBehaviour(item, exportPath, assemblyLoader); return ExportMonoBehaviour(item, exportPath);
case ClassIDType.Font: case ClassIDType.Font:
return ExportFont(item, exportPath); return ExportFont(item, exportPath);
case ClassIDType.Sprite: case ClassIDType.Sprite:
return ExportSprite(item, exportPath, options); return ExportSprite(item, exportPath);
case ClassIDType.Mesh: case ClassIDType.Mesh:
return ExportMesh(item, exportPath); return ExportMesh(item, exportPath);
default: default:

View File

@@ -55,59 +55,78 @@ namespace AssetStudioCLI.Options
NameAndContainer, NameAndContainer,
} }
internal class GroupedOption<T> : Option<T> internal static class CLIOptions
{ {
public GroupedOption(T optionDefaultValue, string optionName, string optionDescription, HelpGroups optionHelpGroup, bool isFlag = false) : base(optionDefaultValue, optionName, optionDescription, optionHelpGroup, isFlag) public static bool isParsed;
{ public static bool showHelp;
CLIOptions.OptionGrouping(optionName, optionDescription, optionHelpGroup, isFlag); public static string[] cliArgs;
} public static string inputPath;
} public static FilterBy filterBy;
internal class CLIOptions
{
public bool isParsed;
public bool showHelp;
public string[] cliArgs;
public string inputPath;
public FilterBy filterBy;
private static Dictionary<string, string> optionsDict; private static Dictionary<string, string> optionsDict;
private static Dictionary<string, string> flagsDict; private static Dictionary<string, string> flagsDict;
private static Dictionary<HelpGroups, Dictionary<string, string>> optionGroups; private static Dictionary<HelpGroups, Dictionary<string, string>> optionGroups;
private List<ClassIDType> supportedAssetTypes; private static List<ClassIDType> supportedAssetTypes;
//general //general
public Option<WorkMode> o_workMode; public static Option<WorkMode> o_workMode;
public Option<List<ClassIDType>> o_exportAssetTypes; public static Option<List<ClassIDType>> o_exportAssetTypes;
public Option<AssetGroupOption> o_groupAssetsBy; public static Option<AssetGroupOption> o_groupAssetsBy;
public Option<string> o_outputFolder; public static Option<string> o_outputFolder;
public Option<bool> o_displayHelp; public static Option<bool> o_displayHelp;
//logger //logger
public Option<LoggerEvent> o_logLevel; public static Option<LoggerEvent> o_logLevel;
public Option<LogOutputMode> o_logOutput; public static Option<LogOutputMode> o_logOutput;
//convert //convert
public bool convertTexture; public static bool convertTexture;
public Option<ImageFormat> o_imageFormat; public static Option<ImageFormat> o_imageFormat;
public Option<AudioFormat> o_audioFormat; public static Option<AudioFormat> o_audioFormat;
//advanced //advanced
public Option<ExportListType> o_exportAssetList; public static Option<ExportListType> o_exportAssetList;
public Option<List<string>> o_filterByName; public static Option<List<string>> o_filterByName;
public Option<List<string>> o_filterByContainer; public static Option<List<string>> o_filterByContainer;
public Option<List<string>> o_filterByPathID; public static Option<List<string>> o_filterByPathID;
public Option<List<string>> o_filterByText; public static Option<List<string>> o_filterByText;
public Option<string> o_assemblyPath; public static Option<string> o_assemblyPath;
public Option<string> o_unityVersion; public static Option<string> o_unityVersion;
public Option<bool> f_notRestoreExtensionName; public static Option<bool> f_notRestoreExtensionName;
public CLIOptions(string[] args) static CLIOptions()
{ {
cliArgs = args; OptionExtensions.OptionGrouping = OptionGrouping;
InitOptions(); InitOptions();
ParseArgs(args);
} }
private void InitOptions() private static void OptionGrouping(string name, string desc, HelpGroups group, bool isFlag)
{
if (string.IsNullOrEmpty(name))
{
return;
}
var optionDict = new Dictionary<string, string>() { { name, desc } };
if (!optionGroups.ContainsKey(group))
{
optionGroups.Add(group, optionDict);
}
else
{
optionGroups[group].Add(name, desc);
}
if (isFlag)
{
flagsDict.Add(name, desc);
}
else
{
optionsDict.Add(name, desc);
}
}
private static void InitOptions()
{ {
isParsed = false; isParsed = false;
showHelp = false; showHelp = false;
cliArgs = null;
inputPath = ""; inputPath = "";
filterBy = FilterBy.None; filterBy = FilterBy.None;
optionsDict = new Dictionary<string, string>(); optionsDict = new Dictionary<string, string>();
@@ -303,35 +322,10 @@ namespace AssetStudioCLI.Options
#endregion #endregion
} }
internal static void OptionGrouping(string name, string desc, HelpGroups group, bool isFlag) public static void ParseArgs(string[] args)
{ {
if (string.IsNullOrEmpty(name)) cliArgs = args;
{
return;
}
var optionDict = new Dictionary<string, string>() { { name, desc } };
if (!optionGroups.ContainsKey(group))
{
optionGroups.Add(group, optionDict);
}
else
{
optionGroups[group].Add(name, desc);
}
if (isFlag)
{
flagsDict.Add(name, desc);
}
else
{
optionsDict.Add(name, desc);
}
}
private void ParseArgs(string[] args)
{
var brightYellow = CLIAnsiColors.BrightYellow; var brightYellow = CLIAnsiColors.BrightYellow;
var brightRed = CLIAnsiColors.BrightRed; var brightRed = CLIAnsiColors.BrightRed;
@@ -658,6 +652,7 @@ namespace AssetStudioCLI.Options
if (Directory.Exists(value)) if (Directory.Exists(value))
{ {
o_assemblyPath.Value = value; o_assemblyPath.Value = value;
Studio.assemblyLoader.Load(value);
} }
else else
{ {
@@ -703,8 +698,13 @@ namespace AssetStudioCLI.Options
return; return;
} }
} }
isParsed = true;
#endregion #endregion
if (!Studio.assemblyLoader.Loaded)
{
Studio.assemblyLoader.Loaded = true;
}
isParsed = true;
} }
private static string[] ValueSplitter(string value) private static string[] ValueSplitter(string value)
@@ -713,7 +713,7 @@ namespace AssetStudioCLI.Options
return value.Split(separator); return value.Split(separator);
} }
private bool TryShowOptionDescription(string option, Dictionary<string, string> descDict) private static bool TryShowOptionDescription(string option, Dictionary<string, string> descDict)
{ {
var optionDesc = descDict.Where(x => x.Key.Contains(option)); var optionDesc = descDict.Where(x => x.Key.Contains(option));
if (optionDesc.Any()) if (optionDesc.Any())
@@ -728,7 +728,7 @@ namespace AssetStudioCLI.Options
return false; return false;
} }
public void ShowHelp(bool showUsageOnly = false) public static void ShowHelp(bool showUsageOnly = false)
{ {
const int indent = 22; const int indent = 22;
var helpMessage = new StringBuilder(); var helpMessage = new StringBuilder();
@@ -761,12 +761,13 @@ namespace AssetStudioCLI.Options
} }
else else
{ {
Console.WriteLine($"# {appAssembly.Name}\n# Based on AssetStudioMod v{appAssembly.Version}\n"); var arch = Environment.Is64BitProcess ? "x64" : "x32";
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# Based on AssetStudioMod v{appAssembly.Version}\n");
Console.WriteLine($"{usage}\n\n{helpMessage}"); Console.WriteLine($"{usage}\n\n{helpMessage}");
} }
} }
private string ShowCurrentFilter() private static string ShowCurrentFilter()
{ {
switch (filterBy) switch (filterBy)
{ {
@@ -785,7 +786,7 @@ namespace AssetStudioCLI.Options
} }
} }
public void ShowCurrentOptions() public static void ShowCurrentOptions()
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("[Current Options]"); sb.AppendLine("[Current Options]");
@@ -821,7 +822,7 @@ namespace AssetStudioCLI.Options
sb.AppendLine(ShowCurrentFilter()); sb.AppendLine(ShowCurrentFilter());
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\""); sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\""); sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
sb.AppendLine($"# Restore TextAsset extension: {!f_notRestoreExtensionName.Value}"); sb.AppendLine($"# Restore TextAsset Extension: {!f_notRestoreExtensionName.Value}");
break; break;
} }
sb.AppendLine("======"); sb.AppendLine("======");

View File

@@ -0,0 +1,17 @@
using System;
namespace AssetStudioCLI.Options
{
internal static class OptionExtensions
{
public static Action<string, string, HelpGroups, bool> OptionGrouping = (name, desc, 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)
{
OptionExtensions.OptionGrouping(optionName, optionDescription, optionHelpGroup, isFlag);
}
}
}

View File

@@ -8,52 +8,51 @@ namespace AssetStudioCLI
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var options = new CLIOptions(args); CLIOptions.ParseArgs(args);
if (options.isParsed) if (CLIOptions.isParsed)
{ {
CLIRun(options); CLIRun();
} }
else if (options.showHelp) else if (CLIOptions.showHelp)
{ {
options.ShowHelp(); CLIOptions.ShowHelp();
} }
else else
{ {
Console.WriteLine(); Console.WriteLine();
options.ShowHelp(showUsageOnly: true); CLIOptions.ShowHelp(showUsageOnly: true);
} }
} }
private static void CLIRun(CLIOptions options) private static void CLIRun()
{ {
var cliLogger = new CLILogger(options); var cliLogger = new CLILogger();
Logger.Default = cliLogger; Logger.Default = cliLogger;
var studio = new Studio(options); CLIOptions.ShowCurrentOptions();
options.ShowCurrentOptions();
try try
{ {
if (studio.LoadAssets()) if (Studio.LoadAssets())
{ {
studio.ParseAssets(); Studio.ParseAssets();
if (options.filterBy != FilterBy.None && options.o_workMode.Value != WorkMode.ExportLive2D) if (CLIOptions.filterBy != FilterBy.None && CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
{ {
studio.FilterAssets(); Studio.FilterAssets();
} }
if (options.o_exportAssetList.Value != ExportListType.None) if (CLIOptions.o_exportAssetList.Value != ExportListType.None)
{ {
studio.ExportAssetList(); Studio.ExportAssetList();
} }
switch (options.o_workMode.Value) switch (CLIOptions.o_workMode.Value)
{ {
case WorkMode.Info: case WorkMode.Info:
studio.ShowExportableAssetsInfo(); Studio.ShowExportableAssetsInfo();
break; break;
case WorkMode.ExportLive2D: case WorkMode.ExportLive2D:
studio.ExportLive2D(); Studio.ExportLive2D();
break; break;
default: default:
studio.ExportAssets(); Studio.ExportAssets();
break; break;
} }
} }

View File

@@ -11,40 +11,30 @@ using Ansi = AssetStudioCLI.CLIAnsiColors;
namespace AssetStudioCLI namespace AssetStudioCLI
{ {
internal class Studio internal static class Studio
{ {
public AssetsManager assetsManager = new AssetsManager(); public static AssetsManager assetsManager = new AssetsManager();
public List<AssetItem> parsedAssetsList = new List<AssetItem>(); public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>(); private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
private static AssemblyLoader assemblyLoader = new AssemblyLoader();
private readonly CLIOptions options;
public Studio(CLIOptions cliOptions) static Studio()
{ {
Progress.Default = new Progress<int>(ShowCurProgressValue); Progress.Default = new Progress<int>(ShowCurProgressValue);
options = cliOptions;
if (options.o_assemblyPath.Value != "")
{
assemblyLoader.Load(options.o_assemblyPath.Value);
}
else
{
assemblyLoader.Loaded = true;
}
} }
private void ShowCurProgressValue(int value) private static void ShowCurProgressValue(int value)
{ {
Console.Write($"[{value:000}%]\r"); Console.Write($"[{value:000}%]\r");
} }
public bool LoadAssets() public static bool LoadAssets()
{ {
var isLoaded = false; var isLoaded = false;
assetsManager.SpecifyUnityVersion = options.o_unityVersion.Value; assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.Value;
assetsManager.SetAssetFilter(options.o_exportAssetTypes.Value); assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
assetsManager.LoadFilesAndFolders(options.inputPath); assetsManager.LoadFilesAndFolders(CLIOptions.inputPath);
if (assetsManager.assetsFileList.Count == 0) if (assetsManager.assetsFileList.Count == 0)
{ {
Logger.Warning("No Unity file can be loaded."); Logger.Warning("No Unity file can be loaded.");
@@ -57,7 +47,7 @@ namespace AssetStudioCLI
return isLoaded; return isLoaded;
} }
public void ParseAssets() public static void ParseAssets()
{ {
Logger.Info("Parse assets..."); Logger.Info("Parse assets...");
@@ -141,7 +131,7 @@ namespace AssetStudioCLI
assetItem.Text = assetItem.TypeString + assetItem.UniqueID; assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
} }
isExportable = options.o_exportAssetTypes.Value.Contains(asset.type); isExportable = CLIOptions.o_exportAssetTypes.Value.Contains(asset.type);
if (isExportable) if (isExportable)
{ {
fileAssetsList.Add(assetItem); fileAssetsList.Add(assetItem);
@@ -158,14 +148,34 @@ namespace AssetStudioCLI
} }
parsedAssetsList.AddRange(fileAssetsList); parsedAssetsList.AddRange(fileAssetsList);
fileAssetsList.Clear(); fileAssetsList.Clear();
if (options.o_workMode.Value != WorkMode.ExportLive2D) if (CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
{ {
containers.Clear(); containers.Clear();
} }
} }
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)
{
m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y =>
y.classID != (int)ClassIDType.Shader
&& CLIOptions.o_exportAssetTypes.Value.Any(k => (int)k == y.classID))
);
}
else
{
m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y => CLIOptions.o_exportAssetTypes.Value.Any(k => (int)k == y.classID)));
}
var objectsCount = assetsManager.assetsFileList.Sum(x => x.Objects.LongCount(y => CLIOptions.o_exportAssetTypes.Value.Any(k => k == y.type)));
if (m_ObjectsCount != objectsCount)
{
log += $" and {m_ObjectsCount - objectsCount} assets failed to read";
}
Logger.Info(log);
} }
public void ShowExportableAssetsInfo() public static void ShowExportableAssetsInfo()
{ {
var exportableAssetsCountDict = new Dictionary<ClassIDType, int>(); var exportableAssetsCountDict = new Dictionary<ClassIDType, int>();
string info = ""; string info = "";
@@ -198,7 +208,7 @@ namespace AssetStudioCLI
info += "No exportable assets found."; info += "No exportable assets found.";
} }
if (options.o_logLevel.Value > LoggerEvent.Info) if (CLIOptions.o_logLevel.Value > LoggerEvent.Info)
{ {
Console.WriteLine(info); Console.WriteLine(info);
} }
@@ -208,53 +218,53 @@ namespace AssetStudioCLI
} }
} }
public void FilterAssets() public static void FilterAssets()
{ {
var assetsCount = parsedAssetsList.Count; var assetsCount = parsedAssetsList.Count;
var filteredAssets = new List<AssetItem>(); var filteredAssets = new List<AssetItem>();
switch(options.filterBy) switch(CLIOptions.filterBy)
{ {
case FilterBy.Name: case FilterBy.Name:
filteredAssets = parsedAssetsList.FindAll(x => options.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)); filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info( Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", options.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names." $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
); );
break; break;
case FilterBy.Container: case FilterBy.Container:
filteredAssets = parsedAssetsList.FindAll(x => options.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)); filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
Logger.Info( Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", options.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers." $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers."
); );
break; break;
case FilterBy.PathID: case FilterBy.PathID:
filteredAssets = parsedAssetsList.FindAll(x => options.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( Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", options.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs." $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs."
); );
break; break;
case FilterBy.NameOrContainer: case FilterBy.NameOrContainer:
filteredAssets = parsedAssetsList.FindAll(x => filteredAssets = parsedAssetsList.FindAll(x =>
options.o_filterByText.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) || CLIOptions.o_filterByText.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
options.o_filterByText.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) CLIOptions.o_filterByText.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
); );
Logger.Info( Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", options.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Contaniers." $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Contaniers."
); );
break; break;
case FilterBy.NameAndContainer: case FilterBy.NameAndContainer:
filteredAssets = parsedAssetsList.FindAll(x => filteredAssets = parsedAssetsList.FindAll(x =>
options.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) && CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
options.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
); );
Logger.Info( Logger.Info(
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
$"that contain {$"\"{string.Join("\", \"", options.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers " + $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers " +
$"and {$"\"{string.Join("\", \"", options.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names." $"and {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
); );
break; break;
} }
@@ -262,13 +272,13 @@ namespace AssetStudioCLI
parsedAssetsList = filteredAssets; parsedAssetsList = filteredAssets;
} }
public void ExportAssets() public static void ExportAssets()
{ {
var savePath = options.o_outputFolder.Value; var savePath = CLIOptions.o_outputFolder.Value;
var toExportCount = parsedAssetsList.Count; var toExportCount = parsedAssetsList.Count;
var exportedCount = 0; var exportedCount = 0;
var groupOption = options.o_groupAssetsBy.Value; var groupOption = CLIOptions.o_groupAssetsBy.Value;
foreach (var asset in parsedAssetsList) foreach (var asset in parsedAssetsList)
{ {
string exportPath; string exportPath;
@@ -310,25 +320,25 @@ namespace AssetStudioCLI
exportPath += Path.DirectorySeparatorChar; exportPath += Path.DirectorySeparatorChar;
try try
{ {
switch (options.o_workMode.Value) switch (CLIOptions.o_workMode.Value)
{ {
case WorkMode.ExportRaw: case WorkMode.ExportRaw:
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}"); Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportRawFile(asset, exportPath)) if (ExportRawFile(asset, exportPath))
{ {
exportedCount++; exportedCount++;
} }
break; break;
case WorkMode.Dump: case WorkMode.Dump:
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}"); Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportDumpFile(asset, exportPath, assemblyLoader)) if (ExportDumpFile(asset, exportPath))
{ {
exportedCount++; exportedCount++;
} }
break; break;
case WorkMode.Export: case WorkMode.Export:
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}"); Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
if (ExportConvertFile(asset, exportPath, options, assemblyLoader)) if (ExportConvertFile(asset, exportPath))
{ {
exportedCount++; exportedCount++;
} }
@@ -349,11 +359,11 @@ namespace AssetStudioCLI
} }
else if (toExportCount > exportedCount) else if (toExportCount > exportedCount)
{ {
Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{options.o_outputFolder.Value.Color(Ansi.BrightYellow)}\".", ignoreLevel: true); Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightYellow)}\".", ignoreLevel: true);
} }
else else
{ {
Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{options.o_outputFolder.Value.Color(Ansi.BrightGreen)}\".", ignoreLevel: true); Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightGreen)}\".", ignoreLevel: true);
} }
if (toExportCount > exportedCount) if (toExportCount > exportedCount)
@@ -362,11 +372,11 @@ namespace AssetStudioCLI
} }
} }
public void ExportAssetList() public static void ExportAssetList()
{ {
var savePath = options.o_outputFolder.Value; var savePath = CLIOptions.o_outputFolder.Value;
switch (options.o_exportAssetList.Value) switch (CLIOptions.o_exportAssetList.Value)
{ {
case ExportListType.XML: case ExportListType.XML:
var filename = Path.Combine(savePath, "assets.xml"); var filename = Path.Combine(savePath, "assets.xml");
@@ -393,9 +403,9 @@ namespace AssetStudioCLI
Logger.Info($"Finished exporting asset list with {parsedAssetsList.Count} items."); Logger.Info($"Finished exporting asset list with {parsedAssetsList.Count} items.");
} }
public void ExportLive2D() public static void ExportLive2D()
{ {
var baseDestPath = Path.Combine(options.o_outputFolder.Value, "Live2DOutput"); var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
var useFullContainerPath = false; var useFullContainerPath = false;
Progress.Reset(); Progress.Reset();
@@ -461,7 +471,7 @@ namespace AssetStudioCLI
Progress.Report(modelCounter, (int)totalModelCount); Progress.Report(modelCounter, (int)totalModelCount);
} }
var status = modelCounter > 0 ? var status = modelCounter > 0 ?
$"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s) to \"{options.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" : $"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" :
"Nothing exported."; "Nothing exported.";
Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true); Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true);
} }

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks> <TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright> <Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,14 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
namespace AssetStudioGUI namespace AssetStudioGUI

View File

@@ -7,13 +7,14 @@
<ApplicationIcon>Resources\as.ico</ApplicationIcon> <ApplicationIcon>Resources\as.ico</ApplicationIcon>
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle> <AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
<AssemblyName>AssetStudioModGUI</AssemblyName> <AssemblyName>AssetStudioModGUI</AssemblyName>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright> <Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2021-2023</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net472' "> <PropertyGroup Condition=" '$(TargetFramework)' == 'net472' ">
<IsPublishable>false</IsPublishable> <IsPublishable>false</IsPublishable>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -52,8 +53,15 @@
</ContentWithTargetPath> </ContentWithTargetPath>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' "> <ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<PackageReference Include="OpenTK" Version="4.7.7" /> <PackageReference Include="OpenTK.Graphics" Version="4.8.0" />
<PackageReference Include="OpenTK.Windowing.Desktop" Version="4.8.0" />
<Reference Include="OpenTK.WinForms"> <Reference Include="OpenTK.WinForms">
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath> <HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
</Reference> </Reference>
@@ -64,12 +72,6 @@
<PackageReference Include="OpenTK.GLControl" Version="3.3.3" /> <PackageReference Include="OpenTK.GLControl" Version="3.3.3" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft-WindowsAPICodePack-Core-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell-6.0" Version="1.1.6-preview.2.24bd88f" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<!-- Use local compiled win-x86 and win-x64 Texture2DDecoder libs, because libs from Kyaru.Texture2DDecoder.Windows were compiled with /MD flag --> <!-- Use local compiled win-x86 and win-x64 Texture2DDecoder libs, because libs from Kyaru.Texture2DDecoder.Windows were compiled with /MD flag -->
<Target Name="CopyExtraFilesPortable" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' OR '$(TargetFramework)' == 'net472' "> <Target Name="CopyExtraFilesPortable" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' OR '$(TargetFramework)' == 'net472' ">

View File

@@ -125,6 +125,8 @@
this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.contextMenuStrip2 = new System.Windows.Forms.ContextMenuStrip(this.components); this.contextMenuStrip2 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.showRelatedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
this.selectAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.selectAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.clearSelectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.clearSelectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
@@ -526,7 +528,7 @@
this.allToolStripMenuItem.CheckOnClick = true; this.allToolStripMenuItem.CheckOnClick = true;
this.allToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.allToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.allToolStripMenuItem.Name = "allToolStripMenuItem"; this.allToolStripMenuItem.Name = "allToolStripMenuItem";
this.allToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.allToolStripMenuItem.Size = new System.Drawing.Size(88, 22);
this.allToolStripMenuItem.Text = "All"; this.allToolStripMenuItem.Text = "All";
this.allToolStripMenuItem.Click += new System.EventHandler(this.typeToolStripMenuItem_Click); this.allToolStripMenuItem.Click += new System.EventHandler(this.typeToolStripMenuItem_Click);
// //
@@ -620,7 +622,7 @@
this.sceneTreeView.Size = new System.Drawing.Size(472, 587); this.sceneTreeView.Size = new System.Drawing.Size(472, 587);
this.sceneTreeView.TabIndex = 1; this.sceneTreeView.TabIndex = 1;
this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck); this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck);
this.sceneTreeView.MouseClick += new System.Windows.Forms.MouseEventHandler(this.sceneTreeView_MouseClick); this.sceneTreeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.sceneTreeView_NodeMouseClick);
// //
// treeSearch // treeSearch
// //
@@ -629,7 +631,7 @@
this.treeSearch.Location = new System.Drawing.Point(0, 0); this.treeSearch.Location = new System.Drawing.Point(0, 0);
this.treeSearch.Name = "treeSearch"; this.treeSearch.Name = "treeSearch";
this.treeSearch.Size = new System.Drawing.Size(472, 20); this.treeSearch.Size = new System.Drawing.Size(472, 20);
this.treeSearch.TabIndex = 0; this.treeSearch.TabIndex = 2;
this.treeSearch.Text = " Search "; this.treeSearch.Text = " Search ";
this.treeSearch.TextChanged += new System.EventHandler(this.treeSearch_TextChanged); this.treeSearch.TextChanged += new System.EventHandler(this.treeSearch_TextChanged);
this.treeSearch.Enter += new System.EventHandler(this.treeSearch_Enter); this.treeSearch.Enter += new System.EventHandler(this.treeSearch_Enter);
@@ -1115,13 +1117,28 @@
// contextMenuStrip2 // contextMenuStrip2
// //
this.contextMenuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.contextMenuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showRelatedAssetsToolStripMenuItem,
this.toolStripSeparator7,
this.selectAllToolStripMenuItem, this.selectAllToolStripMenuItem,
this.clearSelectionToolStripMenuItem, this.clearSelectionToolStripMenuItem,
this.toolStripSeparator5, this.toolStripSeparator5,
this.expandAllToolStripMenuItem, this.expandAllToolStripMenuItem,
this.collapseAllToolStripMenuItem}); this.collapseAllToolStripMenuItem});
this.contextMenuStrip2.Name = "contextMenuStrip2"; this.contextMenuStrip2.Name = "contextMenuStrip2";
this.contextMenuStrip2.Size = new System.Drawing.Size(152, 98); this.contextMenuStrip2.Size = new System.Drawing.Size(152, 126);
this.contextMenuStrip2.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip2_Opening);
//
// showRelatedAssetsToolStripMenuItem
//
this.showRelatedAssetsToolStripMenuItem.Name = "showRelatedAssetsToolStripMenuItem";
this.showRelatedAssetsToolStripMenuItem.Size = new System.Drawing.Size(151, 22);
this.showRelatedAssetsToolStripMenuItem.Text = "Related assets";
this.showRelatedAssetsToolStripMenuItem.Click += new System.EventHandler(this.showRelatedAssetsToolStripMenuItem_Click);
//
// toolStripSeparator7
//
this.toolStripSeparator7.Name = "toolStripSeparator7";
this.toolStripSeparator7.Size = new System.Drawing.Size(148, 6);
// //
// selectAllToolStripMenuItem // selectAllToolStripMenuItem
// //
@@ -1286,7 +1303,6 @@
private System.Windows.Forms.TextBox treeSearch; private System.Windows.Forms.TextBox treeSearch;
private System.Windows.Forms.ToolStripMenuItem loadFileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem loadFileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem loadFolderToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem loadFolderToolStripMenuItem;
private System.Windows.Forms.ListView assetListView;
private System.Windows.Forms.ColumnHeader columnHeaderName; private System.Windows.Forms.ColumnHeader columnHeaderName;
private System.Windows.Forms.ColumnHeader columnHeaderSize; private System.Windows.Forms.ColumnHeader columnHeaderSize;
private System.Windows.Forms.ColumnHeader columnHeaderType; private System.Windows.Forms.ColumnHeader columnHeaderType;
@@ -1386,6 +1402,9 @@
private System.Windows.Forms.RichTextBox listSearch; private System.Windows.Forms.RichTextBox listSearch;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; private System.Windows.Forms.ToolStripSeparator toolStripSeparator6;
private System.Windows.Forms.ToolStripMenuItem allLive2DModelsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem allLive2DModelsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem showRelatedAssetsToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator7;
private System.Windows.Forms.ListView assetListView;
} }
} }

View File

@@ -1,6 +1,5 @@
using AssetStudio; using AssetStudio;
using Newtonsoft.Json; using Newtonsoft.Json;
using OpenTK;
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -21,6 +20,7 @@ using static AssetStudioGUI.Studio;
using Font = AssetStudio.Font; using Font = AssetStudio.Font;
using Microsoft.WindowsAPICodePack.Taskbar; using Microsoft.WindowsAPICodePack.Taskbar;
#if NET472 #if NET472
using OpenTK;
using Vector3 = OpenTK.Vector3; using Vector3 = OpenTK.Vector3;
using Vector4 = OpenTK.Vector4; using Vector4 = OpenTK.Vector4;
#else #else
@@ -267,7 +267,10 @@ namespace AssetStudioGUI
} }
allToolStripMenuItem.Checked = true; allToolStripMenuItem.Checked = true;
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {assetListView.Items.Count} exportable assets"; var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {assetListView.Items.Count} exportable assets";
var m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.Count); var unityVer = assetsManager.assetsFileList[0].version;
var m_ObjectsCount = unityVer[0] > 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); var objectsCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
if (m_ObjectsCount != objectsCount) if (m_ObjectsCount != objectsCount)
{ {
@@ -499,10 +502,10 @@ namespace AssetStudioGUI
switch (e.TabPageIndex) switch (e.TabPageIndex)
{ {
case 0: case 0:
treeSearch.Select(); sceneTreeView.Select();
break; break;
case 1: case 1:
listSearch.Select(); assetListView.Select();
break; break;
} }
} }
@@ -782,42 +785,42 @@ namespace AssetStudioGUI
return; return;
try try
{ {
switch (assetItem.Asset) switch (assetItem.Type)
{ {
case Texture2D m_Texture2D: case ClassIDType.Texture2D:
PreviewTexture2D(assetItem, m_Texture2D); PreviewTexture2D(assetItem, assetItem.Asset as Texture2D);
break; break;
case AudioClip m_AudioClip: case ClassIDType.AudioClip:
PreviewAudioClip(assetItem, m_AudioClip); PreviewAudioClip(assetItem, assetItem.Asset as AudioClip);
break; break;
case Shader m_Shader: case ClassIDType.Shader:
PreviewShader(m_Shader); PreviewShader(assetItem.Asset as Shader);
break; break;
case TextAsset m_TextAsset: case ClassIDType.TextAsset:
PreviewTextAsset(m_TextAsset); PreviewTextAsset(assetItem.Asset as TextAsset);
break; break;
case MonoBehaviour m_MonoBehaviour: case ClassIDType.MonoBehaviour:
PreviewMonoBehaviour(m_MonoBehaviour); PreviewMonoBehaviour(assetItem.Asset as MonoBehaviour);
break; break;
case Font m_Font: case ClassIDType.Font:
PreviewFont(m_Font); PreviewFont(assetItem.Asset as Font);
break; break;
case Mesh m_Mesh: case ClassIDType.Mesh:
PreviewMesh(m_Mesh); PreviewMesh(assetItem.Asset as Mesh);
break; break;
case VideoClip m_VideoClip: case ClassIDType.VideoClip:
PreviewVideoClip(assetItem, m_VideoClip); PreviewVideoClip(assetItem, assetItem.Asset as VideoClip);
break; break;
case MovieTexture _: case ClassIDType.MovieTexture:
StatusStripUpdate("Only supported export."); StatusStripUpdate("Only supported export.");
break; break;
case Sprite m_Sprite: case ClassIDType.Sprite:
PreviewSprite(assetItem, m_Sprite); PreviewSprite(assetItem, assetItem.Asset as Sprite);
break; break;
case Animator _: case ClassIDType.Animator:
StatusStripUpdate("Can be exported to FBX file."); StatusStripUpdate("Can be exported to FBX file.");
break; break;
case AnimationClip _: case ClassIDType.AnimationClip:
StatusStripUpdate("Can be exported with Animator or Objects"); StatusStripUpdate("Can be exported with Animator or Objects");
break; break;
default: default:
@@ -1026,7 +1029,7 @@ namespace AssetStudioGUI
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Width: {m_VideoClip.Width}"); sb.AppendLine($"Width: {m_VideoClip.Width}");
sb.AppendLine($"Height: {m_VideoClip.Height}"); sb.AppendLine($"Height: {m_VideoClip.Height}");
sb.AppendLine($"Frame rate: {m_VideoClip.m_FrameRate}"); sb.AppendLine($"Frame rate: {m_VideoClip.m_FrameRate:.0##}");
sb.AppendLine($"Split alpha: {m_VideoClip.m_HasSplitAlpha}"); sb.AppendLine($"Split alpha: {m_VideoClip.m_HasSplitAlpha}");
assetItem.InfoText = sb.ToString(); assetItem.InfoText = sb.ToString();
@@ -1809,10 +1812,11 @@ namespace AssetStudioGUI
logger.ShowErrorMessage = toolStripMenuItem15.Checked; logger.ShowErrorMessage = toolStripMenuItem15.Checked;
} }
private void sceneTreeView_MouseClick(object sender, MouseEventArgs e) private void sceneTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{ {
if (e.Button == MouseButtons.Right && sceneTreeView.Nodes.Count > 0) if (e.Button == MouseButtons.Right)
{ {
sceneTreeView.SelectedNode = e.Node;
contextMenuStrip2.Show(sceneTreeView, e.Location.X, e.Location.Y); contextMenuStrip2.Show(sceneTreeView, e.Location.X, e.Location.Y);
} }
} }
@@ -1921,6 +1925,77 @@ namespace AssetStudioGUI
} }
} }
private void selectRelatedAsset(object sender, EventArgs e)
{
var selectedItem = (ToolStripMenuItem)sender;
var index = int.Parse(selectedItem.Name.Split('_')[0]);
assetListView.SelectedIndices.Clear();
tabControl1.SelectedTab = tabPage2;
var assetItem = assetListView.Items[index];
assetItem.Selected = true;
assetItem.EnsureVisible();
}
private void selectAllRelatedAssets(object sender, EventArgs e)
{
var selectedNode = sceneTreeView.SelectedNode;
var relatedAssets = visibleAssets.FindAll(x => x.TreeNode == selectedNode);
if (relatedAssets.Count > 0)
{
assetListView.SelectedIndices.Clear();
tabControl1.SelectedTab = tabPage2;
foreach (var asset in relatedAssets)
{
var assetItem = assetListView.Items[assetListView.Items.IndexOf(asset)];
assetItem.Selected = true;
}
assetListView.Items[assetListView.Items.IndexOf(relatedAssets[0])].EnsureVisible();
}
}
private void showRelatedAssetsToolStripMenuItem_Click(object sender, EventArgs e)
{
var selectedNode = sceneTreeView.SelectedNode;
var relatedAssets = visibleAssets.FindAll(x => x.TreeNode == selectedNode);
if (relatedAssets.Count == 0)
{
StatusStripUpdate("No related assets were found among the visible assets.");
}
}
private void contextMenuStrip2_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
var selectedNode = sceneTreeView.SelectedNode;
var relatedAssets = visibleAssets.FindAll(x => x.TreeNode == selectedNode);
showRelatedAssetsToolStripMenuItem.DropDownItems.Clear();
if (relatedAssets.Count > 1)
{
var assetItem = new ToolStripMenuItem
{
CheckOnClick = false,
Name = "selectAllRelatedAssetsToolStripMenuItem",
Size = new Size(180, 22),
Text = "Select all"
};
assetItem.Click += selectAllRelatedAssets;
showRelatedAssetsToolStripMenuItem.DropDownItems.Add(assetItem);
}
foreach (var asset in relatedAssets)
{
var index = assetListView.Items.IndexOf(asset);
var assetItem = new ToolStripMenuItem
{
CheckOnClick = false,
Name = $"{index}_{asset.TypeString}",
Size = new Size(180, 22),
Text = $"({asset.TypeString}) {asset.Text}"
};
assetItem.Click += selectRelatedAsset;
showRelatedAssetsToolStripMenuItem.DropDownItems.Add(assetItem);
}
}
#region FMOD #region FMOD
private void FMODinit() private void FMODinit()
{ {

View File

@@ -120,9 +120,6 @@
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>312, 17</value> <value>312, 17</value>
</metadata> </metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<data name="fontPreviewBox.Text" xml:space="preserve"> <data name="fontPreviewBox.Text" xml:space="preserve">
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ <value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
1234567890.:,;'\"(!?)+-*/= 1234567890.:,;'\"(!?)+-*/=
@@ -141,6 +138,9 @@ The quick brown fox jumps over the lazy dog. 1234567890
The quick brown fox jumps over the lazy dog. 1234567890</value> The quick brown fox jumps over the lazy dog. 1234567890</value>
</data> </data>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>432, 17</value>
</metadata>
<metadata name="contextMenuStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="contextMenuStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>775, 21</value> <value>775, 21</value>
</metadata> </metadata>

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="AssetStudioMod.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel element will disable file and registry virtualization.
Remove this element if your application requires this virtualization for backwards
compatibility.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config.
Makes the application long-path aware. See https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">system</dpiAwareness>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -2,15 +2,14 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks> <TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2018-2022</Copyright> <Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.3" /> <PackageReference Include="Mono.Cecil" Version="0.11.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" !$(TargetFramework.Contains('windows')) "> <ItemGroup Condition=" !$(TargetFramework.Contains('windows')) ">
@@ -23,6 +22,11 @@
<PackageReference Include="Kyaru.Texture2DDecoder"> <PackageReference Include="Kyaru.Texture2DDecoder">
<Version>0.17.0</Version> <Version>0.17.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -99,7 +99,7 @@ namespace CubismLive2DExtractor
} }
//motion //motion
var motions = new JArray(); var motions = new SortedDictionary<string, JArray>();
if (gameObjects.Count > 0) if (gameObjects.Count > 0)
{ {
@@ -205,11 +205,8 @@ namespace CubismLive2DExtractor
} }
json.Meta.TotalUserDataSize = totalUserDataSize; json.Meta.TotalUserDataSize = totalUserDataSize;
motions.Add(new JObject var motionPath = new JObject(new JProperty("File", $"motions/{animation.Name}.motion3.json"));
{ motions.Add(animation.Name, new JArray(motionPath));
{ "Name", animation.Name },
{ "File", $"motions/{animation.Name}.motion3.json" }
});
File.WriteAllText($"{destMotionPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter())); File.WriteAllText($"{destMotionPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter()));
} }
} }
@@ -307,7 +304,7 @@ namespace CubismLive2DExtractor
{ {
Moc = $"{modelName}.moc3", Moc = $"{modelName}.moc3",
Textures = textures.ToArray(), Textures = textures.ToArray(),
Motions = new JObject { { "", motions } }, Motions = JObject.FromObject(motions),
Expressions = expressions, Expressions = expressions,
}, },
Groups = groups.ToArray() Groups = groups.ToArray()

View File

@@ -34,7 +34,11 @@ namespace AssetStudio
{ {
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off) if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
{ {
var tex = CutImage(m_Sprite, m_Texture2D, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.downscaleMultiplier, m_Sprite.m_RD.settingsRaw); Image<Bgra32> tex = null;
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
{
tex = CutImage(m_Sprite, m_Texture2D, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.downscaleMultiplier, m_Sprite.m_RD.settingsRaw);
}
var alphaTex = CutImage(m_Sprite, m_AlphaTexture2D, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.downscaleMultiplier, m_Sprite.m_RD.settingsRaw); var alphaTex = CutImage(m_Sprite, m_AlphaTexture2D, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.downscaleMultiplier, m_Sprite.m_RD.settingsRaw);
switch (spriteMaskMode) switch (spriteMaskMode)
@@ -46,7 +50,6 @@ namespace AssetStudio
tex.ApplyRGBMask(alphaTex); tex.ApplyRGBMask(alphaTex);
return tex; return tex;
case SpriteMaskMode.MaskOnly: case SpriteMaskMode.MaskOnly:
tex.Dispose();
return alphaTex; return alphaTex;
} }
} }
@@ -88,8 +91,6 @@ namespace AssetStudio
{ {
var originalImage = m_Texture2D.ConvertToImage(false); var originalImage = m_Texture2D.ConvertToImage(false);
if (originalImage != null) if (originalImage != null)
{
using (originalImage)
{ {
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f) if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
{ {
@@ -105,6 +106,7 @@ namespace AssetStudio
rectBottom = Math.Min(rectBottom, originalImage.Height); rectBottom = Math.Min(rectBottom, originalImage.Height);
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY); var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
var spriteImage = originalImage.Clone(x => x.Crop(rect)); var spriteImage = originalImage.Clone(x => x.Crop(rect));
originalImage.Dispose();
if (settingsRaw.packed == 1) if (settingsRaw.packed == 1)
{ {
//RotateAndFlip //RotateAndFlip
@@ -175,7 +177,6 @@ namespace AssetStudio
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical)); spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
return spriteImage; return spriteImage;
} }
}
return null; return null;
} }

View File

@@ -1,5 +1,19 @@
# Changelog # Changelog
## v0.17.2.0 [27-08-2023]
- [GUI] Improved Scene Hierarchy tab
- Added "Related assets" item to the context menu (https://github.com/aelurum/AssetStudio/issues/7)
- [GUI] Added app.manifest for net472 build
- Added long paths support (win10 v1607+)
- Fixed blurring at high DPI with scaling
- [CLI] Fixed sprite export in sprite only mode
- Made some changes to motion list for live2d models
- Motion list is now sorted
- Motions divided into groups (each motion is a separate group)
- Motion names are used as group names
- Updated dependencies
- Made some other minor fixes and improvements
## v0.17.1.0 [12-07-2023] ## v0.17.1.0 [12-07-2023]
#### Breaking Changes #### Breaking Changes
- With the drag&drop fix (https://github.com/aelurum/AssetStudio/commit/2f8f57c1a63893c0b0d2a55349d6cb6d8f8a5a3b), functions `LoadFiles` and `LoadFolder` in AssetsManager have been replaced with one universal function `LoadFilesAndFolders` - With the drag&drop fix (https://github.com/aelurum/AssetStudio/commit/2f8f57c1a63893c0b0d2a55349d6cb6d8f8a5a3b), functions `LoadFiles` and `LoadFolder` in AssetsManager have been replaced with one universal function `LoadFilesAndFolders`

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.17.1.0</Version> <Version>0.17.2.0</Version>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright> <Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>