mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-23 21:30:21 -04:00
Add AssetStudioCLI project
- Updated projects and dependencies
This commit is contained in:
parent
5c662d64e4
commit
c52940abc4
3
.gitignore
vendored
3
.gitignore
vendored
@ -35,6 +35,9 @@ bld/
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# Launch Settings
|
||||
*launchSettings.json
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
@ -4,33 +4,29 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
public static class DllLoader
|
||||
{
|
||||
|
||||
public static void PreloadDll(string dllName)
|
||||
{
|
||||
var dllDir = GetDirectedDllDirectory();
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
// Not using OperatingSystem.Platform.
|
||||
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Win32.LoadDll(dllDir, dllName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Posix.LoadDll(dllDir, dllName);
|
||||
Win32.LoadDll(GetDirectedDllDirectory(localDir), dllName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDirectedDllDirectory()
|
||||
private static string GetDirectedDllDirectory(string localDir)
|
||||
{
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
var win32Path = Path.Combine("runtimes", "win-x86", "native");
|
||||
var win64Path = Path.Combine("runtimes", "win-x64", "native");
|
||||
var subDir = Environment.Is64BitProcess ? win64Path : win32Path;
|
||||
|
||||
var directedDllDir = Path.Combine(localDir, subDir);
|
||||
|
||||
@ -64,61 +60,7 @@ namespace AssetStudio.PInvoke
|
||||
|
||||
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
|
||||
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
|
||||
|
||||
}
|
||||
|
||||
private static class Posix
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
string dllExtension;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
dllExtension = ".so";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
dllExtension = ".dylib";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var dllFileName = $"lib{dllName}{dllExtension}";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
|
||||
var hLibrary = DlOpen(directedDllPath, ldFlags);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var pErrStr = DlError();
|
||||
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
|
||||
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
|
||||
// the codepage is UTF-8 so the error message should be handled correctly.
|
||||
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
|
||||
|
||||
throw new DllNotFoundException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
|
||||
// void *dlopen(const char *filename, int flag);
|
||||
[DllImport("libdl", EntryPoint = "dlopen")]
|
||||
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
|
||||
|
||||
// char *dlerror(void);
|
||||
[DllImport("libdl", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlError();
|
||||
|
||||
private const int RTLD_LAZY = 0x1;
|
||||
private const int RTLD_NOW = 0x2;
|
||||
private const int RTLD_GLOBAL = 0x100;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31410.357
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33414.496
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{422FEC21-EF60-4F29-AA56-95DFDA23C913}"
|
||||
EndProject
|
||||
@ -25,6 +25,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBXNative", "Ass
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Texture2DDecoderNative", "Texture2DDecoderNative\Texture2DDecoderNative.vcxproj", "{29356642-C46E-4144-83D8-22DC09D0D7FD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioCLI", "AssetStudioCLI\AssetStudioCLI.csproj", "{34B6329B-0E73-45AC-B8CC-015F119F63DC}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913} = {422FEC21-EF60-4F29-AA56-95DFDA23C913}
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF} = {65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -131,6 +137,18 @@ Global
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.Build.0 = Release|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.Build.0 = Release|Win32
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{34B6329B-0E73-45AC-B8CC-015F119F63DC}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
|
99
AssetStudioCLI/AssetStudioCLI.csproj
Normal file
99
AssetStudioCLI/AssetStudioCLI.csproj
Normal file
@ -0,0 +1,99 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<AssemblyTitle>AssetStudio Mod by VaDiM</AssemblyTitle>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- 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)' == '' ">
|
||||
<Message Text="Copying extra files for $(TargetFramework)... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\win-x64\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesPortableNet" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
|
||||
<Message Text="Copying extra files for .NET ($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x86\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)runtimes\linux-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libfmod.dylib" DestinationFolder="$(TargetDir)runtimes\osx-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\osx-arm64\libfmod.dylib" DestinationFolder="$(TargetDir)runtimes\osx-arm64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesPortable" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' ">
|
||||
<Message Text="Publishing extra files for Portable build ($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesPortableNet" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' AND '$(TargetFramework)' != 'net472' ">
|
||||
<Message Text="Publishing extra files for Portable .NET build ($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\linux-x86\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\linux-x64\native\libfmod.so" DestinationFolder="$(PublishDir)runtimes\linux-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\osx-x64\native\libfmod.dylib" DestinationFolder="$(PublishDir)runtimes\osx-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\osx-arm64\native\libfmod.dylib" DestinationFolder="$(PublishDir)runtimes\osx-arm64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesWin86" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x86' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$$(ProjectDir)Libraries\win-x86\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesWin64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x64' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\win-x64\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesWin" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('win-x')) ">
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)\fmod.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesLinux64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\linux-x64\libfmod.so" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesLinux64" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' ">
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)\libfmod.so" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesMac64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'osx-x64' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\osx-x64\libfmod.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesMacArm64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'osx-arm64' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\osx-arm64\libfmod.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesMac" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)\libfmod.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
117
AssetStudioCLI/CLILogger.cs
Normal file
117
AssetStudioCLI/CLILogger.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AssetStudioCLI.Options;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal enum LogOutputMode
|
||||
{
|
||||
Console,
|
||||
File,
|
||||
Both,
|
||||
}
|
||||
|
||||
internal class CLILogger : ILogger
|
||||
{
|
||||
private readonly LogOutputMode logOutput;
|
||||
private readonly LoggerEvent logMinLevel;
|
||||
public string LogName;
|
||||
public string LogPath;
|
||||
|
||||
public CLILogger(CLIOptions options)
|
||||
{
|
||||
logOutput = options.o_logOutput.Value;
|
||||
logMinLevel = options.o_logLevel.Value;
|
||||
LogName = $"AssetStudioCLI_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
|
||||
LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName);
|
||||
|
||||
var ver = typeof(Program).Assembly.GetName().Version;
|
||||
LogToFile(LoggerEvent.Verbose, $"---AssetStudioCLI v{ver} | Logger launched---\n" +
|
||||
$"CMD Args: {string.Join(" ", options.cliArgs)}");
|
||||
}
|
||||
|
||||
private static string ColorLogLevel(LoggerEvent logLevel)
|
||||
{
|
||||
string formattedLevel = $"[{logLevel}]";
|
||||
switch (logLevel)
|
||||
{
|
||||
case LoggerEvent.Info:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightCyan)}";
|
||||
case LoggerEvent.Warning:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightYellow)}";
|
||||
case LoggerEvent.Error:
|
||||
return $"{formattedLevel.Color(CLIAnsiColors.BrightRed)}";
|
||||
default:
|
||||
return formattedLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatMessage(LoggerEvent logMsgLevel, string message, bool consoleMode = false)
|
||||
{
|
||||
var curTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
message = message.TrimEnd();
|
||||
var multiLine = message.Contains('\n');
|
||||
|
||||
string formattedMessage;
|
||||
if (consoleMode)
|
||||
{
|
||||
string colorLogLevel = ColorLogLevel(logMsgLevel);
|
||||
formattedMessage = $"{colorLogLevel} {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{colorLogLevel} ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message = Regex.Replace(message, @"\e\[[0-9;]*m(?:\e\[K)?", ""); //Delete ANSI colors
|
||||
var logLevel = $"{logMsgLevel.ToString().ToUpper(),-7}";
|
||||
formattedMessage = $"{curTime} | {logLevel} | {message}";
|
||||
if (multiLine)
|
||||
{
|
||||
formattedMessage = formattedMessage.Replace("\n", $"\n{curTime} | {logLevel} | ");
|
||||
}
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
public void LogToConsole(LoggerEvent logMsgLevel, string message)
|
||||
{
|
||||
if (logOutput != LogOutputMode.File)
|
||||
{
|
||||
Console.WriteLine(FormatMessage(logMsgLevel, message, consoleMode: true));
|
||||
}
|
||||
}
|
||||
|
||||
public async void LogToFile(LoggerEvent logMsgLevel, string message)
|
||||
{
|
||||
if (logOutput != LogOutputMode.Console)
|
||||
{
|
||||
using (var sw = new StreamWriter(LogPath, append: true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
await sw.WriteLineAsync(FormatMessage(logMsgLevel, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(LoggerEvent logMsgLevel, string message)
|
||||
{
|
||||
if (logMsgLevel < logMinLevel || string.IsNullOrEmpty(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (logOutput != LogOutputMode.File)
|
||||
{
|
||||
LogToConsole(logMsgLevel, message);
|
||||
}
|
||||
if (logOutput != LogOutputMode.Console)
|
||||
{
|
||||
LogToFile(logMsgLevel, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
AssetStudioCLI/Components/AssetItem.cs
Normal file
27
AssetStudioCLI/Components/AssetItem.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using AssetStudio;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal class AssetItem
|
||||
{
|
||||
public Object Asset;
|
||||
public SerializedFile SourceFile;
|
||||
public string Container = string.Empty;
|
||||
public string TypeString;
|
||||
public long m_PathID;
|
||||
public long FullSize;
|
||||
public ClassIDType Type;
|
||||
public string Text;
|
||||
public string UniqueID;
|
||||
|
||||
public AssetItem(Object asset)
|
||||
{
|
||||
Asset = asset;
|
||||
SourceFile = asset.assetsFile;
|
||||
Type = asset.type;
|
||||
TypeString = Type.ToString();
|
||||
m_PathID = asset.m_PathID;
|
||||
FullSize = asset.byteSize;
|
||||
}
|
||||
}
|
||||
}
|
49
AssetStudioCLI/Components/CLIAnsiColors.cs
Normal file
49
AssetStudioCLI/Components/CLIAnsiColors.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
// Represents set with 16 base colors using ANSI escape codes, which should be supported in most terminals
|
||||
// (well, except for windows editions before windows 10)
|
||||
public static class CLIAnsiColors
|
||||
{
|
||||
public static readonly string
|
||||
Black = "\u001b[30m",
|
||||
Red = "\u001b[31m",
|
||||
Green = "\u001b[32m",
|
||||
Yellow = "\u001b[33m", //remapped to ~BrightWhite in Windows PowerShell 6
|
||||
Blue = "\u001b[34m",
|
||||
Magenta = "\u001b[35m", //remapped to ~Blue in Windows PowerShell 6
|
||||
Cyan = "\u001b[36m",
|
||||
White = "\u001b[37m",
|
||||
BrightBlack = "\u001b[30;1m",
|
||||
BrightRed = "\u001b[31;1m",
|
||||
BrightGreen = "\u001b[32;1m",
|
||||
BrightYellow = "\u001b[33;1m",
|
||||
BrightBlue = "\u001b[34;1m",
|
||||
BrightMagenta = "\u001b[35;1m",
|
||||
BrightCyan = "\u001b[36;1m",
|
||||
BrightWhite = "\u001b[37;1m";
|
||||
private static readonly string Reset = "\u001b[0m";
|
||||
|
||||
public static string Color(this string str, string ansiColor)
|
||||
{
|
||||
if (!CLIWinAnsiFix.isAnsiSupported)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
return $"{ansiColor}{str}{Reset}";
|
||||
}
|
||||
|
||||
public static void ANSICodesTest()
|
||||
{
|
||||
Console.WriteLine("ANSI escape codes test");
|
||||
Console.WriteLine($"Supported: {CLIWinAnsiFix.isAnsiSupported}");
|
||||
Console.WriteLine("\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m");
|
||||
Console.WriteLine("\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m");
|
||||
Console.WriteLine("\u001b[30;1m A \u001b[31;1m B \u001b[32;1m C \u001b[33;1m D \u001b[0m");
|
||||
Console.WriteLine("\u001b[34;1m E \u001b[35;1m F \u001b[36;1m G \u001b[37;1m H \u001b[0m");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
AssetStudioCLI/Components/CLIWinAnsiFix.cs
Normal file
62
AssetStudioCLI/Components/CLIWinAnsiFix.cs
Normal file
@ -0,0 +1,62 @@
|
||||
// Based on code by tomzorz (https://gist.github.com/tomzorz/6142d69852f831fb5393654c90a1f22e)
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
static class CLIWinAnsiFix
|
||||
{
|
||||
public static readonly bool isAnsiSupported;
|
||||
private const int STD_OUTPUT_HANDLE = -11;
|
||||
private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GetStdHandle(int nStdHandle);
|
||||
|
||||
static CLIWinAnsiFix()
|
||||
{
|
||||
bool isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
if (isWin)
|
||||
{
|
||||
isAnsiSupported = TryEnableVTMode();
|
||||
if (!isAnsiSupported)
|
||||
{
|
||||
//Check for bash terminal emulator. E.g., Git Bash, Cmder
|
||||
isAnsiSupported = Environment.GetEnvironmentVariable("TERM") != null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isAnsiSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable support for ANSI escape codes
|
||||
// (but probably only suitable for windows 10+)
|
||||
// https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
|
||||
private static bool TryEnableVTMode()
|
||||
{
|
||||
var iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (!GetConsoleMode(iStdOut, out uint outConsoleMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
if (!SetConsoleMode(iStdOut, outConsoleMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
289
AssetStudioCLI/Exporter.cs
Normal file
289
AssetStudioCLI/Exporter.cs
Normal file
@ -0,0 +1,289 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal static class Exporter
|
||||
{
|
||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
var m_Texture2D = (Texture2D)item.Asset;
|
||||
if (options.convertTexture)
|
||||
{
|
||||
var type = options.o_imageFormat.Value;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
var image = m_Texture2D.ConvertToImage(flip: true);
|
||||
if (image == null)
|
||||
{
|
||||
Logger.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, CLIOptions options)
|
||||
{
|
||||
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($"[{item.Text}]: AudioData was not found");
|
||||
return false;
|
||||
}
|
||||
var converter = new AudioClipConverter(m_AudioClip);
|
||||
if (options.o_audioFormat.Value != AudioFormat.None && converter.IsSupport)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
|
||||
return false;
|
||||
|
||||
Logger.Debug($"Converting \"{m_AudioClip.m_Name}\" to wav..\n" +
|
||||
$"AudioClip sound compression: {m_AudioClip.m_CompressionFormat}\n" +
|
||||
$"AudioClip channel count: {m_AudioClip.m_Channels}\n" +
|
||||
$"AudioClip sample rate: {m_AudioClip.m_Frequency}\n" +
|
||||
$"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
|
||||
|
||||
var buffer = converter.ConvertToWav(m_AudioData);
|
||||
if (buffer == null)
|
||||
{
|
||||
Logger.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;
|
||||
if (m_VideoClip.m_ExternalResources.m_Size > 0)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
|
||||
return false;
|
||||
m_VideoClip.m_VideoData.WriteData(exportFullPath);
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportShader(AssetItem item, string exportPath)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
|
||||
return false;
|
||||
var m_Shader = (Shader)item.Asset;
|
||||
var str = m_Shader.Convert();
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportTextAsset(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
var m_TextAsset = (TextAsset)item.Asset;
|
||||
var extension = ".txt";
|
||||
if (!options.f_notRestoreExtensionName.Value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.Container))
|
||||
{
|
||||
extension = Path.GetExtension(item.Container);
|
||||
}
|
||||
}
|
||||
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
|
||||
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportMonoBehaviour(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
|
||||
return false;
|
||||
var m_MonoBehaviour = (MonoBehaviour)item.Asset;
|
||||
var type = m_MonoBehaviour.ToType();
|
||||
if (type == null)
|
||||
{
|
||||
var m_Type = MonoBehaviourToTypeTree(m_MonoBehaviour, options);
|
||||
type = m_MonoBehaviour.ToType(m_Type);
|
||||
}
|
||||
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportFont(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_Font = (Font)item.Asset;
|
||||
if (m_Font.m_FontData != null)
|
||||
{
|
||||
var extension = ".ttf";
|
||||
if (m_Font.m_FontData[0] == 79 && m_Font.m_FontData[1] == 84 && m_Font.m_FontData[2] == 84 && m_Font.m_FontData[3] == 79)
|
||||
{
|
||||
extension = ".otf";
|
||||
}
|
||||
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
|
||||
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportSprite(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
var type = options.o_imageFormat.Value;
|
||||
var alphaMask = SpriteMaskMode.On;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
var image = ((Sprite)item.Asset).GetImage(alphaMask);
|
||||
if (image != null)
|
||||
{
|
||||
using (image)
|
||||
{
|
||||
using (var file = File.OpenWrite(exportFullPath))
|
||||
{
|
||||
image.WriteToStream(file, type);
|
||||
}
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportRawFile(AssetItem item, string exportPath)
|
||||
{
|
||||
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 bool ExportDumpFile(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
|
||||
return false;
|
||||
var str = item.Asset.Dump();
|
||||
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
var m_Type = MonoBehaviourToTypeTree(m_MonoBehaviour, options);
|
||||
str = m_MonoBehaviour.Dump(m_Type);
|
||||
}
|
||||
if (str != null)
|
||||
{
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
Logger.Debug($"{item.TypeString}: \"{item.Text}\" saved to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
|
||||
{
|
||||
var fileName = FixFileName(item.Text);
|
||||
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))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
return true;
|
||||
}
|
||||
Logger.Error($"Export error. File \"{fullPath.Color(CLIAnsiColors.BrightRed)}\" already exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportConvertFile(AssetItem item, string exportPath, CLIOptions options)
|
||||
{
|
||||
switch (item.Type)
|
||||
{
|
||||
case ClassIDType.Texture2D:
|
||||
return ExportTexture2D(item, exportPath, options);
|
||||
case ClassIDType.AudioClip:
|
||||
return ExportAudioClip(item, exportPath, options);
|
||||
case ClassIDType.VideoClip:
|
||||
return ExportVideoClip(item, exportPath);
|
||||
case ClassIDType.Shader:
|
||||
return ExportShader(item, exportPath);
|
||||
case ClassIDType.TextAsset:
|
||||
return ExportTextAsset(item, exportPath, options);
|
||||
case ClassIDType.MonoBehaviour:
|
||||
return ExportMonoBehaviour(item, exportPath, options);
|
||||
case ClassIDType.Font:
|
||||
return ExportFont(item, exportPath);
|
||||
case ClassIDType.Sprite:
|
||||
return ExportSprite(item, exportPath, options);
|
||||
default:
|
||||
return ExportRawFile(item, exportPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeTree MonoBehaviourToTypeTree(MonoBehaviour m_MonoBehaviour, CLIOptions options)
|
||||
{
|
||||
if (!assemblyLoader.Loaded)
|
||||
{
|
||||
var assemblyFolder = options.o_assemblyPath.Value;
|
||||
if (assemblyFolder != "")
|
||||
{
|
||||
assemblyLoader.Load(assemblyFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
assemblyLoader.Loaded = true;
|
||||
}
|
||||
}
|
||||
return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
|
||||
}
|
||||
|
||||
public static string FixFileName(string str)
|
||||
{
|
||||
if (str.Length >= 260) return Path.GetRandomFileName();
|
||||
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
|
||||
}
|
||||
}
|
||||
}
|
BIN
AssetStudioCLI/Libraries/linux-x64/libTexture2DDecoderNative.so
Normal file
BIN
AssetStudioCLI/Libraries/linux-x64/libTexture2DDecoderNative.so
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/linux-x64/libfmod.so
Normal file
BIN
AssetStudioCLI/Libraries/linux-x64/libfmod.so
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/linux-x86/libfmod.so
Normal file
BIN
AssetStudioCLI/Libraries/linux-x86/libfmod.so
Normal file
Binary file not shown.
Binary file not shown.
BIN
AssetStudioCLI/Libraries/osx-arm64/libfmod.dylib
Normal file
BIN
AssetStudioCLI/Libraries/osx-arm64/libfmod.dylib
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/osx-x64/libTexture2DDecoderNative.dylib
Normal file
BIN
AssetStudioCLI/Libraries/osx-x64/libTexture2DDecoderNative.dylib
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/osx-x64/libfmod.dylib
Normal file
BIN
AssetStudioCLI/Libraries/osx-x64/libfmod.dylib
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/win-x64/fmod.dll
Normal file
BIN
AssetStudioCLI/Libraries/win-x64/fmod.dll
Normal file
Binary file not shown.
BIN
AssetStudioCLI/Libraries/win-x86/fmod.dll
Normal file
BIN
AssetStudioCLI/Libraries/win-x86/fmod.dll
Normal file
Binary file not shown.
790
AssetStudioCLI/Options/CLIOptions.cs
Normal file
790
AssetStudioCLI/Options/CLIOptions.cs
Normal file
@ -0,0 +1,790 @@
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudioCLI.Options
|
||||
{
|
||||
internal enum HelpGroups
|
||||
{
|
||||
General,
|
||||
Convert,
|
||||
Logger,
|
||||
Advanced,
|
||||
}
|
||||
|
||||
internal enum WorkMode
|
||||
{
|
||||
Export,
|
||||
ExportRaw,
|
||||
Dump,
|
||||
Info,
|
||||
}
|
||||
|
||||
internal enum AssetGroupOption
|
||||
{
|
||||
None,
|
||||
TypeName,
|
||||
ContainerPath,
|
||||
SourceFileName,
|
||||
}
|
||||
|
||||
internal enum ExportListType
|
||||
{
|
||||
None,
|
||||
XML,
|
||||
}
|
||||
|
||||
internal enum AudioFormat
|
||||
{
|
||||
None,
|
||||
Wav,
|
||||
}
|
||||
|
||||
internal enum FilterBy
|
||||
{
|
||||
None,
|
||||
Name,
|
||||
Container,
|
||||
PathID,
|
||||
NameOrContainer,
|
||||
NameAndContainer,
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CLIOptions.OptionGrouping(optionName, optionDescription, optionHelpGroup, isFlag);
|
||||
}
|
||||
}
|
||||
|
||||
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> flagsDict;
|
||||
private static Dictionary<HelpGroups, Dictionary<string, string>> optionGroups;
|
||||
private List<ClassIDType> supportedAssetTypes;
|
||||
//general
|
||||
public Option<WorkMode> o_workMode;
|
||||
public Option<List<ClassIDType>> o_exportAssetTypes;
|
||||
public Option<AssetGroupOption> o_groupAssetsBy;
|
||||
public Option<string> o_outputFolder;
|
||||
public Option<bool> o_displayHelp;
|
||||
//logger
|
||||
public Option<LoggerEvent> o_logLevel;
|
||||
public Option<LogOutputMode> o_logOutput;
|
||||
//convert
|
||||
public bool convertTexture;
|
||||
public Option<ImageFormat> o_imageFormat;
|
||||
public Option<AudioFormat> o_audioFormat;
|
||||
//advanced
|
||||
public Option<ExportListType> o_exportAssetList;
|
||||
public Option<List<string>> o_filterByName;
|
||||
public Option<List<string>> o_filterByContainer;
|
||||
public Option<List<string>> o_filterByPathID;
|
||||
public Option<List<string>> o_filterByText;
|
||||
public Option<string> o_assemblyPath;
|
||||
public Option<string> o_unityVersion;
|
||||
public Option<bool> f_notRestoreExtensionName;
|
||||
|
||||
public CLIOptions(string[] args)
|
||||
{
|
||||
cliArgs = args;
|
||||
InitOptions();
|
||||
ParseArgs(args);
|
||||
}
|
||||
|
||||
private void InitOptions()
|
||||
{
|
||||
isParsed = false;
|
||||
showHelp = false;
|
||||
inputPath = "";
|
||||
filterBy = FilterBy.None;
|
||||
optionsDict = new Dictionary<string, string>();
|
||||
flagsDict = new Dictionary<string, string>();
|
||||
optionGroups = new Dictionary<HelpGroups, Dictionary<string, string>>();
|
||||
supportedAssetTypes = new List<ClassIDType>
|
||||
{
|
||||
ClassIDType.Texture2D,
|
||||
ClassIDType.Sprite,
|
||||
ClassIDType.TextAsset,
|
||||
ClassIDType.MonoBehaviour,
|
||||
ClassIDType.Font,
|
||||
ClassIDType.Shader,
|
||||
ClassIDType.AudioClip,
|
||||
ClassIDType.VideoClip,
|
||||
};
|
||||
|
||||
#region Init General Options
|
||||
o_workMode = new GroupedOption<WorkMode>
|
||||
(
|
||||
optionDefaultValue: WorkMode.Export,
|
||||
optionName: "-m, --mode <value>",
|
||||
optionDescription: "Specify working mode\n" +
|
||||
"<Value: export(default) | exportRaw | dump | info>\n" +
|
||||
"Export - Exports converted assets\n" +
|
||||
"ExportRaw - Exports raw data\n" +
|
||||
"Dump - Makes asset dumps\n" +
|
||||
"Info - Loads file(s), shows the number of supported for export assets and exits\n" +
|
||||
"Example: \"-m info\"\n",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
o_exportAssetTypes = new GroupedOption<List<ClassIDType>>
|
||||
(
|
||||
optionDefaultValue: supportedAssetTypes,
|
||||
optionName: "-t, --asset-type <value(s)>",
|
||||
optionDescription: "Specify asset type(s) to export\n" +
|
||||
"<Value(s): tex2d, sprite, textAsset, monoBehaviour, font, shader, \naudio, video | all(default)>\n" +
|
||||
"All - export all asset types, which are listed in the values\n" +
|
||||
"*To specify multiple asset types, write them separated by ',' or ';' without spaces\n" +
|
||||
"Examples: \"-t sprite\" or \"-t all\" or \"-t tex2d,sprite,audio\" or \"-t tex2d;sprite;font\"\n",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
o_groupAssetsBy = new GroupedOption<AssetGroupOption>
|
||||
(
|
||||
optionDefaultValue: AssetGroupOption.ContainerPath,
|
||||
optionName: "-g, --group-option <value>",
|
||||
optionDescription: "Specify the way in which exported assets should be grouped\n" +
|
||||
"<Value: none | type | container(default) | filename>\n" +
|
||||
"None - Do not group exported assets\n" +
|
||||
"Type - Group exported assets by type name\n" +
|
||||
"Container - Group exported assets by container path\n" +
|
||||
"Filename - Group exported assets by source file name\n" +
|
||||
"Example: \"-g container\"\n",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
o_outputFolder = new GroupedOption<string>
|
||||
(
|
||||
optionDefaultValue: "",
|
||||
optionName: "-o, --output <path>",
|
||||
optionDescription: "Specify path to the output folder\n" +
|
||||
"If path isn't specifyed, 'ASExport' folder will be created in the program's work folder\n",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
o_displayHelp = new GroupedOption<bool>
|
||||
(
|
||||
optionDefaultValue: false,
|
||||
optionName: "-h, --help",
|
||||
optionDescription: "Display help and exit",
|
||||
optionHelpGroup: HelpGroups.General
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Init Logger Options
|
||||
o_logLevel = new GroupedOption<LoggerEvent>
|
||||
(
|
||||
optionDefaultValue: LoggerEvent.Info,
|
||||
optionName: "--log-level <value>",
|
||||
optionDescription: "Specify the log level\n" +
|
||||
"<Value: verbose | debug | info(default) | warning | error>\n" +
|
||||
"Example: \"--log-level warning\"\n",
|
||||
optionHelpGroup: HelpGroups.Logger
|
||||
);
|
||||
o_logOutput = new GroupedOption<LogOutputMode>
|
||||
(
|
||||
optionDefaultValue: LogOutputMode.Console,
|
||||
optionName: "--log-output <value>",
|
||||
optionDescription: "Specify the log output\n" +
|
||||
"<Value: console(default) | file | both>\n" +
|
||||
"Example: \"--log-output both\"",
|
||||
optionHelpGroup: HelpGroups.Logger
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Init Convert Options
|
||||
convertTexture = true;
|
||||
o_imageFormat = new GroupedOption<ImageFormat>
|
||||
(
|
||||
optionDefaultValue: ImageFormat.Png,
|
||||
optionName: "--image-format <value>",
|
||||
optionDescription: "Specify the format for converting image assets\n" +
|
||||
"<Value: none | jpg | png(default) | bmp | tga | webp>\n" +
|
||||
"None - Do not convert images and export them as texture data (.tex)\n" +
|
||||
"Example: \"--image-format jpg\"\n",
|
||||
optionHelpGroup: HelpGroups.Convert
|
||||
);
|
||||
o_audioFormat = new GroupedOption<AudioFormat>
|
||||
(
|
||||
optionDefaultValue: AudioFormat.Wav,
|
||||
optionName: "--audio-format <value>",
|
||||
optionDescription: "Specify the format for converting audio assets\n" +
|
||||
"<Value: none | wav(default)>\n" +
|
||||
"None - Do not convert audios and export them in their own format\n" +
|
||||
"Example: \"--audio-format wav\"",
|
||||
optionHelpGroup: HelpGroups.Convert
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Init Advanced Options
|
||||
o_exportAssetList = new GroupedOption<ExportListType>
|
||||
(
|
||||
optionDefaultValue: ExportListType.None,
|
||||
optionName: "--export-asset-list <value>",
|
||||
optionDescription: "Specify the format in which you want to export asset list\n" +
|
||||
"<Value: none(default) | xml>\n" +
|
||||
"None - Do not export asset list\n" +
|
||||
"Example: \"--export-asset-list xml\"\n",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_filterByName = new GroupedOption<List<string>>
|
||||
(
|
||||
optionDefaultValue: new List<string>(),
|
||||
optionName: "--filter-by-name <text>",
|
||||
optionDescription: "Specify the name by which assets should be filtered\n" +
|
||||
"*To specify multiple names write them separated by ',' or ';' without spaces\n" +
|
||||
"Example: \"--filter-by-name char\" or \"--filter-by-name char,bg\"\n",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_filterByContainer = new GroupedOption<List<string>>
|
||||
(
|
||||
optionDefaultValue: new List<string>(),
|
||||
optionName: "--filter-by-container <text>",
|
||||
optionDescription: "Specify the container by which assets should be filtered\n" +
|
||||
"*To specify multiple containers write them separated by ',' or ';' without spaces\n" +
|
||||
"Example: \"--filter-by-container arts\" or \"--filter-by-container arts,icons\"\n",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_filterByPathID = new GroupedOption<List<string>>
|
||||
(
|
||||
optionDefaultValue: new List<string>(),
|
||||
optionName: "--filter-by-pathid <text>",
|
||||
optionDescription: "Specify the PathID by which assets should be filtered\n" +
|
||||
"*To specify multiple PathIDs write them separated by ',' or ';' without spaces\n" +
|
||||
"Example: \"--filter-by-pathid 7238605633795851352,-2430306240205277265\"\n",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_filterByText = new GroupedOption<List<string>>
|
||||
(
|
||||
optionDefaultValue: new List<string>(),
|
||||
optionName: "--filter-by-text <text>",
|
||||
optionDescription: "Specify the text by which assets should be filtered\n" +
|
||||
"Looks for assets that contain the specified text in their names or containers\n" +
|
||||
"*To specify multiple values write them separated by ',' or ';' without spaces\n" +
|
||||
"Example: \"--filter-by-text portrait\" or \"--filter-by-text portrait,art\"\n",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_assemblyPath = new GroupedOption<string>
|
||||
(
|
||||
optionDefaultValue: "",
|
||||
optionName: "--assembly-folder <path>",
|
||||
optionDescription: "Specify the path to the assembly folder",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
o_unityVersion = new GroupedOption<string>
|
||||
(
|
||||
optionDefaultValue: "",
|
||||
optionName: "--unity-version <text>",
|
||||
optionDescription: "Specify Unity version. Example: \"--unity-version 2017.4.39f1\"",
|
||||
optionHelpGroup: HelpGroups.Advanced
|
||||
);
|
||||
f_notRestoreExtensionName = new GroupedOption<bool>
|
||||
(
|
||||
optionDefaultValue: false,
|
||||
optionName: "--not-restore-extension",
|
||||
optionDescription: "(Flag) If specified, AssetStudio will not try to restore TextAssets extension name, \nand will just export all TextAssets with the \".txt\" extension",
|
||||
optionHelpGroup: HelpGroups.Advanced,
|
||||
isFlag: true
|
||||
);
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal 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 void ParseArgs(string[] args)
|
||||
{
|
||||
var brightYellow = CLIAnsiColors.BrightYellow;
|
||||
var brightRed = CLIAnsiColors.BrightRed;
|
||||
|
||||
if (args.Length == 0 || args.Any(x => x == "-h" || x == "--help"))
|
||||
{
|
||||
showHelp = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args[0].StartsWith("-"))
|
||||
{
|
||||
inputPath = Path.GetFullPath(args[0]).Replace("\"", "");
|
||||
if (!Directory.Exists(inputPath) && !File.Exists(inputPath))
|
||||
{
|
||||
Console.WriteLine($"{"Error:".Color(brightRed)} Invalid input path \"{args[0].Color(brightRed)}\".\n" +
|
||||
$"Specified file or folder was not found. The input path must be specified as the first argument.");
|
||||
return;
|
||||
}
|
||||
o_outputFolder.Value = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ASExport");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{"Error:".Color(brightRed)} Input path was empty. Specify the input path as the first argument.");
|
||||
return;
|
||||
}
|
||||
|
||||
var resplittedArgs = new List<string>();
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
string arg = args[i];
|
||||
|
||||
if (arg.Contains('='))
|
||||
{
|
||||
var splittedArgs = arg.Split('=');
|
||||
resplittedArgs.Add(splittedArgs[0]);
|
||||
resplittedArgs.Add(splittedArgs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
resplittedArgs.Add(arg);
|
||||
}
|
||||
};
|
||||
|
||||
#region Parse Flags
|
||||
for (int i = 0; i < resplittedArgs.Count; i++)
|
||||
{
|
||||
string flag = resplittedArgs[i].ToLower();
|
||||
|
||||
switch(flag)
|
||||
{
|
||||
case "--not-restore-extension":
|
||||
f_notRestoreExtensionName.Value = true;
|
||||
resplittedArgs.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Parse Options
|
||||
for (int i = 0; i < resplittedArgs.Count; i++)
|
||||
{
|
||||
var option = resplittedArgs[i].ToLower();
|
||||
try
|
||||
{
|
||||
var value = resplittedArgs[i + 1].Replace("\"", "");
|
||||
switch (option)
|
||||
{
|
||||
case "-m":
|
||||
case "--mode":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "export":
|
||||
o_workMode.Value = WorkMode.Export;
|
||||
break;
|
||||
case "raw":
|
||||
case "exportraw":
|
||||
o_workMode.Value = WorkMode.ExportRaw;
|
||||
break;
|
||||
case "dump":
|
||||
o_workMode.Value = WorkMode.Dump;
|
||||
break;
|
||||
case "info":
|
||||
o_workMode.Value = WorkMode.Info;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported working mode: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_workMode.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "-t":
|
||||
case "--asset-type":
|
||||
var splittedTypes = ValueSplitter(value);
|
||||
o_exportAssetTypes.Value = new List<ClassIDType>();
|
||||
foreach (var type in splittedTypes)
|
||||
{
|
||||
switch (type.ToLower())
|
||||
{
|
||||
case "tex2d":
|
||||
case "texture2d":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.Texture2D);
|
||||
break;
|
||||
case "sprite":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.Sprite);
|
||||
break;
|
||||
case "textasset":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.TextAsset);
|
||||
break;
|
||||
case "monobehaviour":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.MonoBehaviour);
|
||||
break;
|
||||
case "font":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.Font);
|
||||
break;
|
||||
case "shader":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.Shader);
|
||||
break;
|
||||
case "audio":
|
||||
case "audioclip":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.AudioClip);
|
||||
break;
|
||||
case "video":
|
||||
case "videoclip":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.VideoClip);
|
||||
break;
|
||||
case "all":
|
||||
o_exportAssetTypes.Value = supportedAssetTypes;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported asset type: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_exportAssetTypes.Description);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "-g":
|
||||
case "--group-option":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "type":
|
||||
o_groupAssetsBy.Value = AssetGroupOption.TypeName;
|
||||
break;
|
||||
case "container":
|
||||
o_groupAssetsBy.Value = AssetGroupOption.ContainerPath;
|
||||
break;
|
||||
case "filename":
|
||||
o_groupAssetsBy.Value = AssetGroupOption.SourceFileName;
|
||||
break;
|
||||
case "none":
|
||||
o_groupAssetsBy.Value = AssetGroupOption.None;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported grouping option: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_groupAssetsBy.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "-o":
|
||||
case "--output":
|
||||
try
|
||||
{
|
||||
value = Path.GetFullPath(value);
|
||||
if (!Directory.Exists(value))
|
||||
{
|
||||
Directory.CreateDirectory(value);
|
||||
}
|
||||
o_outputFolder.Value = value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"{"Warning:".Color(brightYellow)} Invalid output folder \"{value.Color(brightYellow)}\".\n{ex.Message}");
|
||||
Console.WriteLine($"Working folder \"{o_outputFolder.Value.Color(brightYellow)}\" will be used as the output folder.\n");
|
||||
Console.WriteLine("Press ESC to exit or any other key to continue...\n");
|
||||
switch (Console.ReadKey(intercept: true).Key)
|
||||
{
|
||||
case ConsoleKey.Escape:
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "--log-level":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "verbose":
|
||||
o_logLevel.Value = LoggerEvent.Verbose;
|
||||
break;
|
||||
case "debug":
|
||||
o_logLevel.Value = LoggerEvent.Debug;
|
||||
break;
|
||||
case "info":
|
||||
o_logLevel.Value = LoggerEvent.Info;
|
||||
break;
|
||||
case "warning":
|
||||
o_logLevel.Value = LoggerEvent.Warning;
|
||||
break;
|
||||
case "error":
|
||||
o_logLevel.Value = LoggerEvent.Error;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported log level value: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_logLevel.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--log-output":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "console":
|
||||
o_logOutput.Value = LogOutputMode.Console;
|
||||
break;
|
||||
case "file":
|
||||
o_logOutput.Value = LogOutputMode.File;
|
||||
break;
|
||||
case "both":
|
||||
o_logOutput.Value = LogOutputMode.Both;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported log output mode: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_logOutput.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--image-format":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
o_imageFormat.Value = ImageFormat.Jpeg;
|
||||
break;
|
||||
case "png":
|
||||
o_imageFormat.Value = ImageFormat.Png;
|
||||
break;
|
||||
case "bmp":
|
||||
o_imageFormat.Value = ImageFormat.Bmp;
|
||||
break;
|
||||
case "tga":
|
||||
o_imageFormat.Value = ImageFormat.Tga;
|
||||
break;
|
||||
case "webp":
|
||||
o_imageFormat.Value = ImageFormat.Webp;
|
||||
break;
|
||||
case "none":
|
||||
convertTexture = false;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported image format: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_imageFormat.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--audio-format":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "wav":
|
||||
case "wave":
|
||||
o_audioFormat.Value = AudioFormat.Wav;
|
||||
break;
|
||||
case "none":
|
||||
o_audioFormat.Value = AudioFormat.None;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported audio format: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_audioFormat.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--export-asset-list":
|
||||
switch (value.ToLower())
|
||||
{
|
||||
case "xml":
|
||||
o_exportAssetList.Value = ExportListType.XML;
|
||||
break;
|
||||
case "none":
|
||||
o_exportAssetList.Value = ExportListType.None;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported asset list export option: [{value.Color(brightRed)}].\n");
|
||||
Console.WriteLine(o_exportAssetList.Description);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--filter-by-name":
|
||||
o_filterByName.Value.AddRange(ValueSplitter(value));
|
||||
filterBy = filterBy == FilterBy.None ? FilterBy.Name : filterBy == FilterBy.Container ? FilterBy.NameAndContainer : filterBy;
|
||||
break;
|
||||
case "--filter-by-container":
|
||||
o_filterByContainer.Value.AddRange(ValueSplitter(value));
|
||||
filterBy = filterBy == FilterBy.None ? FilterBy.Container : filterBy == FilterBy.Name ? FilterBy.NameAndContainer : filterBy;
|
||||
break;
|
||||
case "--filter-by-pathid":
|
||||
o_filterByPathID.Value.AddRange(ValueSplitter(value));
|
||||
filterBy = FilterBy.PathID;
|
||||
break;
|
||||
case "--filter-by-text":
|
||||
o_filterByText.Value.AddRange(ValueSplitter(value));
|
||||
filterBy = FilterBy.NameOrContainer;
|
||||
break;
|
||||
case "--assembly-folder":
|
||||
if (Directory.Exists(value))
|
||||
{
|
||||
o_assemblyPath.Value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Assembly folder [{value.Color(brightRed)}] was not found.");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "--unity-version":
|
||||
o_unityVersion.Value = value;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"{"Error:".Color(brightRed)} Unknown option [{option.Color(brightRed)}].\n");
|
||||
if (!TryShowOptionDescription(option, optionsDict))
|
||||
{
|
||||
TryShowOptionDescription(option, flagsDict);
|
||||
}
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
if (optionsDict.Any(x => x.Key.Contains(option)))
|
||||
{
|
||||
Console.WriteLine($"{"Error during parsing options:".Color(brightRed)} Value for [{option.Color(brightRed)}] option was not found.\n");
|
||||
TryShowOptionDescription(option, optionsDict);
|
||||
}
|
||||
else if (flagsDict.Any(x => x.Key.Contains(option)))
|
||||
{
|
||||
Console.WriteLine($"{"Error:".Color(brightRed)} Unknown flag [{option.Color(brightRed)}].\n");
|
||||
TryShowOptionDescription(option, flagsDict);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{"Error:".Color(brightRed)} Unknown option [{option.Color(brightRed)}].");
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Unknown Error.".Color(CLIAnsiColors.Red));
|
||||
Console.WriteLine(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
isParsed = true;
|
||||
#endregion
|
||||
}
|
||||
|
||||
private static string[] ValueSplitter(string value)
|
||||
{
|
||||
var separator = value.Contains(';') ? ';' : ',';
|
||||
return value.Split(separator);
|
||||
}
|
||||
|
||||
private bool TryShowOptionDescription(string option, Dictionary<string, string> descDict)
|
||||
{
|
||||
var optionDesc = descDict.Where(x => x.Key.Contains(option));
|
||||
if (optionDesc.Any())
|
||||
{
|
||||
var rand = new Random();
|
||||
var rndOption = optionDesc.ElementAt(rand.Next(0, optionDesc.Count()));
|
||||
Console.WriteLine($"Did you mean [{ $"{rndOption.Key}".Color(CLIAnsiColors.BrightYellow) }] option?");
|
||||
Console.WriteLine($"Here's a description of it: \n\n{rndOption.Value}");
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ShowHelp(bool showUsageOnly = false)
|
||||
{
|
||||
const int indent = 22;
|
||||
var helpMessage = new StringBuilder();
|
||||
var usage = new StringBuilder();
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
usage.Append($"Usage: {appAssembly.Name} <input path to asset file/folder> ");
|
||||
|
||||
var i = 0;
|
||||
foreach (var optionsGroup in optionGroups.Keys)
|
||||
{
|
||||
helpMessage.AppendLine($"{optionsGroup} Options:");
|
||||
foreach (var optionDict in optionGroups[optionsGroup])
|
||||
{
|
||||
var optionName = $"{optionDict.Key,-indent - 8}";
|
||||
var optionDesc = optionDict.Value.Replace("\n", $"{"\n",-indent - 11}");
|
||||
helpMessage.AppendLine($" {optionName}{optionDesc}");
|
||||
|
||||
usage.Append($"[{optionDict.Key}] ");
|
||||
if (i++ % 2 == 0)
|
||||
{
|
||||
usage.Append($"\n{"",indent}");
|
||||
}
|
||||
}
|
||||
helpMessage.AppendLine();
|
||||
}
|
||||
|
||||
if (showUsageOnly)
|
||||
{
|
||||
Console.WriteLine(usage);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"# {appAssembly.Name}\n# Based on AssetStudio Mod v{appAssembly.Version}\n");
|
||||
Console.WriteLine($"{usage}\n\n{helpMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
private string ShowCurrentFilter()
|
||||
{
|
||||
switch (filterBy)
|
||||
{
|
||||
case FilterBy.Name:
|
||||
return $"# Filter by {filterBy}(s): \"{string.Join("\", \"", o_filterByName.Value)}\"";
|
||||
case FilterBy.Container:
|
||||
return $"# Filter by {filterBy}(s): \"{string.Join("\", \"", o_filterByContainer.Value)}\"";
|
||||
case FilterBy.PathID:
|
||||
return $"# Filter by {filterBy}(s): \"{string.Join("\", \"", o_filterByPathID.Value)}\"";
|
||||
case FilterBy.NameOrContainer:
|
||||
return $"# Filter by Text: \"{string.Join("\", \"", o_filterByText.Value)}\"";
|
||||
case FilterBy.NameAndContainer:
|
||||
return $"# Filter by Name(s): \"{string.Join("\", \"", o_filterByName.Value)}\"\n# Filter by Container(s): \"{string.Join("\", \"", o_filterByContainer.Value)}\"";
|
||||
default:
|
||||
return $"# Filter by: {filterBy}";
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowCurrentOptions()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("[Current Options]");
|
||||
sb.AppendLine($"# Working Mode: {o_workMode}");
|
||||
sb.AppendLine($"# Input Path: \"{inputPath}\"");
|
||||
if (o_workMode.Value != WorkMode.Info)
|
||||
{
|
||||
sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
|
||||
sb.AppendLine($"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}");
|
||||
sb.AppendLine($"# Asset Group Option: {o_groupAssetsBy}");
|
||||
sb.AppendLine($"# Export Image Format: {o_imageFormat}");
|
||||
sb.AppendLine($"# Export Audio Format: {o_audioFormat}");
|
||||
sb.AppendLine($"# Log Level: {o_logLevel}");
|
||||
sb.AppendLine($"# Log Output: {o_logOutput}");
|
||||
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
|
||||
sb.AppendLine(ShowCurrentFilter());
|
||||
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
|
||||
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
|
||||
sb.AppendLine($"# Restore TextAsset extension: {!f_notRestoreExtensionName.Value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($"# Export Asset Type(s): {string.Join(", ", o_exportAssetTypes.Value)}");
|
||||
sb.AppendLine($"# Log Level: {o_logLevel}");
|
||||
sb.AppendLine($"# Log Output: {o_logOutput}");
|
||||
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
|
||||
sb.AppendLine(ShowCurrentFilter());
|
||||
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
|
||||
}
|
||||
sb.AppendLine("======");
|
||||
Logger.Info(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
27
AssetStudioCLI/Options/Option.cs
Normal file
27
AssetStudioCLI/Options/Option.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace AssetStudioCLI.Options
|
||||
{
|
||||
internal class Option<T>
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Description { 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)
|
||||
{
|
||||
Name = optionName;
|
||||
Description = optionDescription;
|
||||
DefaultValue = optionDefaultValue;
|
||||
Value = DefaultValue;
|
||||
HelpGroup = optionHelpGroup;
|
||||
IsFlag = isFlag;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value != null ? Value.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
65
AssetStudioCLI/Program.cs
Normal file
65
AssetStudioCLI/Program.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using System;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var options = new CLIOptions(args);
|
||||
if (options.isParsed)
|
||||
{
|
||||
CLIRun(options);
|
||||
}
|
||||
else if (options.showHelp)
|
||||
{
|
||||
options.ShowHelp();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine();
|
||||
options.ShowHelp(showUsageOnly: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CLIRun(CLIOptions options)
|
||||
{
|
||||
var cliLogger = new CLILogger(options);
|
||||
Logger.Default = cliLogger;
|
||||
var studio = new Studio(options);
|
||||
options.ShowCurrentOptions();
|
||||
|
||||
try
|
||||
{
|
||||
if (studio.LoadAssets())
|
||||
{
|
||||
studio.ParseAssets();
|
||||
if (options.filterBy != FilterBy.None)
|
||||
{
|
||||
studio.FilterAssets();
|
||||
}
|
||||
if (options.o_exportAssetList.Value != ExportListType.None)
|
||||
{
|
||||
studio.ExportAssetList();
|
||||
}
|
||||
if (options.o_workMode.Value == WorkMode.Info)
|
||||
{
|
||||
studio.ShowExportableAssetsInfo();
|
||||
return;
|
||||
}
|
||||
studio.ExportAssets();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
cliLogger.LogToFile(LoggerEvent.Verbose, "---Program ended---");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
376
AssetStudioCLI/Studio.cs
Normal file
376
AssetStudioCLI/Studio.cs
Normal file
@ -0,0 +1,376 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using static AssetStudioCLI.Exporter;
|
||||
using Ansi = AssetStudioCLI.CLIAnsiColors;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal class Studio
|
||||
{
|
||||
public AssetsManager assetsManager = new AssetsManager();
|
||||
public List<AssetItem> parsedAssetsList = new List<AssetItem>();
|
||||
private readonly CLIOptions options;
|
||||
|
||||
public Studio(CLIOptions cliOptions)
|
||||
{
|
||||
Progress.Default = new Progress<int>(ShowCurProgressValue);
|
||||
options = cliOptions;
|
||||
}
|
||||
|
||||
private void ShowCurProgressValue(int value)
|
||||
{
|
||||
Console.Write($"[{value:000}%]\r");
|
||||
}
|
||||
|
||||
public bool LoadAssets()
|
||||
{
|
||||
var isLoaded = false;
|
||||
assetsManager.SpecifyUnityVersion = options.o_unityVersion.Value;
|
||||
|
||||
if (Directory.Exists(options.inputPath))
|
||||
{
|
||||
assetsManager.LoadFolder(options.inputPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
assetsManager.LoadFiles(options.inputPath);
|
||||
}
|
||||
if (assetsManager.assetsFileList.Count == 0)
|
||||
{
|
||||
Logger.Warning("No Unity file can be loaded.");
|
||||
}
|
||||
else
|
||||
{
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public void ParseAssets()
|
||||
{
|
||||
Logger.Info("Parse assets...");
|
||||
|
||||
var fileAssetsList = new List<AssetItem>();
|
||||
var containers = new Dictionary<AssetStudio.Object, string>();
|
||||
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
|
||||
|
||||
Progress.Reset();
|
||||
var i = 0;
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
foreach (var asset in assetsFile.Objects)
|
||||
{
|
||||
var assetItem = new AssetItem(asset);
|
||||
assetItem.UniqueID = "_#" + i;
|
||||
var isExportable = false;
|
||||
switch (asset)
|
||||
{
|
||||
case AssetBundle m_AssetBundle:
|
||||
foreach (var m_Container in m_AssetBundle.m_Container)
|
||||
{
|
||||
var preloadIndex = m_Container.Value.preloadIndex;
|
||||
var preloadSize = m_Container.Value.preloadSize;
|
||||
var preloadEnd = preloadIndex + preloadSize;
|
||||
for (int k = preloadIndex; k < preloadEnd; k++)
|
||||
{
|
||||
var pptr = m_AssetBundle.m_PreloadTable[k];
|
||||
if (pptr.TryGet(out var obj))
|
||||
{
|
||||
containers[obj] = m_Container.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ResourceManager m_ResourceManager:
|
||||
foreach (var m_Container in m_ResourceManager.m_Container)
|
||||
{
|
||||
if (m_Container.Value.TryGet(out var obj))
|
||||
{
|
||||
containers[obj] = m_Container.Key;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Texture2D m_Texture2D:
|
||||
if (!string.IsNullOrEmpty(m_Texture2D.m_StreamData?.path))
|
||||
assetItem.FullSize = asset.byteSize + m_Texture2D.m_StreamData.size;
|
||||
assetItem.Text = m_Texture2D.m_Name;
|
||||
break;
|
||||
case AudioClip m_AudioClip:
|
||||
if (!string.IsNullOrEmpty(m_AudioClip.m_Source))
|
||||
assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size;
|
||||
assetItem.Text = m_AudioClip.m_Name;
|
||||
break;
|
||||
case VideoClip m_VideoClip:
|
||||
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
|
||||
assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size;
|
||||
assetItem.Text = m_VideoClip.m_Name;
|
||||
break;
|
||||
case TextAsset _:
|
||||
case Font _:
|
||||
case Sprite _:
|
||||
assetItem.Text = ((NamedObject)asset).m_Name;
|
||||
break;
|
||||
case Shader m_Shader:
|
||||
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
|
||||
break;
|
||||
case MonoBehaviour m_MonoBehaviour:
|
||||
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
assetItem.Text = m_Script.m_ClassName;
|
||||
}
|
||||
else
|
||||
{
|
||||
assetItem.Text = m_MonoBehaviour.m_Name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (assetItem.Text == "")
|
||||
{
|
||||
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
|
||||
}
|
||||
|
||||
isExportable = options.o_exportAssetTypes.Value.Contains(asset.type);
|
||||
if (isExportable)
|
||||
{
|
||||
fileAssetsList.Add(assetItem);
|
||||
}
|
||||
|
||||
Progress.Report(++i, objectCount);
|
||||
}
|
||||
foreach (var asset in fileAssetsList)
|
||||
{
|
||||
if (containers.ContainsKey(asset.Asset))
|
||||
{
|
||||
asset.Container = containers[asset.Asset];
|
||||
}
|
||||
}
|
||||
parsedAssetsList.AddRange(fileAssetsList);
|
||||
containers.Clear();
|
||||
fileAssetsList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowExportableAssetsInfo()
|
||||
{
|
||||
var exportableAssetsCountDict = new Dictionary<ClassIDType, int>();
|
||||
if (parsedAssetsList.Count > 0)
|
||||
{
|
||||
foreach (var asset in parsedAssetsList)
|
||||
{
|
||||
if (exportableAssetsCountDict.ContainsKey(asset.Type))
|
||||
{
|
||||
exportableAssetsCountDict[asset.Type] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
exportableAssetsCountDict.Add(asset.Type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
var info = "\n[Exportable Assets Count]\n";
|
||||
foreach (var assetType in exportableAssetsCountDict.Keys)
|
||||
{
|
||||
info += $"# {assetType}: {exportableAssetsCountDict[assetType]}\n";
|
||||
}
|
||||
if (exportableAssetsCountDict.Count > 1)
|
||||
{
|
||||
info += $"#\n# Total: {parsedAssetsList.Count} assets";
|
||||
}
|
||||
|
||||
if (options.o_logLevel.Value > LoggerEvent.Info)
|
||||
{
|
||||
Console.WriteLine(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FilterAssets()
|
||||
{
|
||||
var assetsCount = parsedAssetsList.Count;
|
||||
var filteredAssets = new List<AssetItem>();
|
||||
|
||||
switch(options.filterBy)
|
||||
{
|
||||
case FilterBy.Name:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => options.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", options.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
|
||||
);
|
||||
break;
|
||||
case FilterBy.Container:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => options.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", options.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers."
|
||||
);
|
||||
break;
|
||||
case FilterBy.PathID:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => options.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("\", \"", options.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs."
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameOrContainer:
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
options.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)
|
||||
);
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", options.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Contaniers."
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameAndContainer:
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
options.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)
|
||||
);
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", options.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers " +
|
||||
$"and {$"\"{string.Join("\", \"", options.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
|
||||
);
|
||||
break;
|
||||
}
|
||||
parsedAssetsList.Clear();
|
||||
parsedAssetsList = filteredAssets;
|
||||
}
|
||||
|
||||
public void ExportAssets()
|
||||
{
|
||||
var savePath = options.o_outputFolder.Value;
|
||||
var toExportCount = parsedAssetsList.Count;
|
||||
var exportedCount = 0;
|
||||
|
||||
foreach (var asset in parsedAssetsList)
|
||||
{
|
||||
string exportPath;
|
||||
switch (options.o_groupAssetsBy.Value)
|
||||
{
|
||||
case AssetGroupOption.TypeName:
|
||||
exportPath = Path.Combine(savePath, asset.TypeString);
|
||||
break;
|
||||
case AssetGroupOption.ContainerPath:
|
||||
if (!string.IsNullOrEmpty(asset.Container))
|
||||
{
|
||||
exportPath = Path.Combine(savePath, Path.GetDirectoryName(asset.Container));
|
||||
}
|
||||
else
|
||||
{
|
||||
exportPath = savePath;
|
||||
}
|
||||
break;
|
||||
case AssetGroupOption.SourceFileName:
|
||||
if (string.IsNullOrEmpty(asset.SourceFile.originalPath))
|
||||
{
|
||||
exportPath = Path.Combine(savePath, asset.SourceFile.fileName + "_export");
|
||||
}
|
||||
else
|
||||
{
|
||||
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
exportPath = savePath;
|
||||
break;
|
||||
}
|
||||
|
||||
exportPath += Path.DirectorySeparatorChar;
|
||||
try
|
||||
{
|
||||
switch (options.o_workMode.Value)
|
||||
{
|
||||
case WorkMode.ExportRaw:
|
||||
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportRawFile(asset, exportPath))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
case WorkMode.Dump:
|
||||
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportDumpFile(asset, exportPath, options))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
case WorkMode.Export:
|
||||
Logger.Debug($"{options.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportConvertFile(asset, exportPath, options))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"{asset.SourceFile.originalPath}: [{$"{asset.Type}: {asset.Text}".Color(Ansi.BrightRed)}] : Export error\n{ex}");
|
||||
}
|
||||
Console.Write($"Exported [{exportedCount}/{toExportCount}]\r");
|
||||
}
|
||||
Console.WriteLine("");
|
||||
|
||||
if (exportedCount == 0)
|
||||
{
|
||||
Logger.Info("Nothing exported.");
|
||||
}
|
||||
else if (toExportCount > exportedCount)
|
||||
{
|
||||
Logger.Info($"Finished exporting {exportedCount} asset(s) to \"{options.o_outputFolder.Value.Color(Ansi.BrightYellow)}\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"Finished exporting {exportedCount} asset(s) to \"{options.o_outputFolder.Value.Color(Ansi.BrightGreen)}\".");
|
||||
}
|
||||
|
||||
if (toExportCount > exportedCount)
|
||||
{
|
||||
Logger.Info($"{toExportCount - exportedCount} asset(s) skipped (not extractable or file(s) already exist).");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExportAssetList()
|
||||
{
|
||||
var savePath = options.o_outputFolder.Value;
|
||||
|
||||
switch (options.o_exportAssetList.Value)
|
||||
{
|
||||
case ExportListType.XML:
|
||||
var filename = Path.Combine(savePath, "assets.xml");
|
||||
var doc = new XDocument(
|
||||
new XElement("Assets",
|
||||
new XAttribute("filename", filename),
|
||||
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
|
||||
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("Size", asset.FullSize)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
doc.Save(filename);
|
||||
|
||||
break;
|
||||
}
|
||||
Logger.Info($"Finished exporting asset list with {parsedAssetsList.Count} items.");
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
@ -1,16 +1,20 @@
|
||||
using AssetStudio.FbxInterop;
|
||||
using AssetStudio.PInvoke;
|
||||
using System.IO;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using AssetStudio.PInvoke;
|
||||
#endif
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static partial class Fbx
|
||||
{
|
||||
|
||||
#if NETFRAMEWORK
|
||||
static Fbx()
|
||||
{
|
||||
DllLoader.PreloadDll(FbxDll.DllName);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Vector3 QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||
<AssemblyTitle>AssetStudio Mod by VaDiM</AssemblyTitle>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
@ -40,44 +40,76 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="Libraries\x86\fmod.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x86\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x64\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="OpenTK" Version="4.6.7" />
|
||||
<PackageReference Include="OpenTK" Version="4.7.7" />
|
||||
<Reference Include="OpenTK.WinForms">
|
||||
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<PackageReference Include="OpenTK" Version="3.1.0" />
|
||||
<PackageReference Include="OpenTK.GLControl" Version="3.1.0" />
|
||||
<PackageReference Include="OpenTK" Version="3.3.3" />
|
||||
<PackageReference Include="OpenTK.GLControl" Version="3.3.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyExtraFiles" AfterTargets="AfterBuild">
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
|
||||
<!-- 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' ">
|
||||
<Message Text="Copying extra files for $(TargetFramework)... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\x86\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\x64\fmod.dll" DestinationFolder="$(TargetDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFiles" AfterTargets="Publish">
|
||||
<Copy SourceFiles="$(TargetDir)x86\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(TargetDir)x64\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(TargetDir)x86\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(TargetDir)x64\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
|
||||
<!-- Publishing an app as framework-dependent produces a cross-platform binary as a dll file, and a platform-specific executable that targets your current platform.
|
||||
The dll is cross-platform while the executable isn't -->
|
||||
<Target Name="PublishExtraFilesPortable" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)' == '' ">
|
||||
<Message Text="Publishing extra files for Portable build ($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x64\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x64\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
<!-- Published net472 build of AssetStudioGUI is only suitable for x32(x86)-bit OS -->
|
||||
<Target Name="PublishExtraFilesNet472Warning" AfterTargets="Publish" Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<Message Text="%0a NOTE: Published net472 build of AssetStudioGUI is only suitable for x32(x86)-bit OS." Importance="high" />
|
||||
<Message Text=" If u need cross-architecture support (x32/x64) in net472, using the binaries created after the build is highly recommended (no need to publish).%0a" Importance="high" />
|
||||
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)runtimes\win-x86\native\fmod.dll" DestinationFolder="$(PublishDir)runtimes\win-x86\native" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesWin86" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x86' OR ( '$(RuntimeIdentifier)' == 'win7-x86' AND '$(TargetFramework)' != 'net472' ) ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\x86\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyExtraFilesWin64" AfterTargets="AfterBuild" Condition=" '$(RuntimeIdentifier)' == 'win-x64' ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\x64\fmod.dll" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesWin" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('win-x')) OR ( '$(RuntimeIdentifier)' == 'win7-x86' AND '$(TargetFramework)' != 'net472' ) ">
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
<Copy SourceFiles="$(TargetDir)\fmod.dll" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
45
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
45
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
@ -79,6 +79,7 @@
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.sceneTreeView = new AssetStudioGUI.GOHierarchy();
|
||||
this.treeSearch = new System.Windows.Forms.TextBox();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.filterExcludeMode = new System.Windows.Forms.CheckBox();
|
||||
@ -127,7 +128,6 @@
|
||||
this.dumpSelectedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.goToSceneHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.sceneTreeView = new AssetStudioGUI.GOHierarchy();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
@ -573,6 +573,17 @@
|
||||
this.tabPage1.Text = "Scene Hierarchy";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// sceneTreeView
|
||||
//
|
||||
this.sceneTreeView.CheckBoxes = true;
|
||||
this.sceneTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.sceneTreeView.HideSelection = false;
|
||||
this.sceneTreeView.Location = new System.Drawing.Point(0, 20);
|
||||
this.sceneTreeView.Name = "sceneTreeView";
|
||||
this.sceneTreeView.Size = new System.Drawing.Size(472, 587);
|
||||
this.sceneTreeView.TabIndex = 1;
|
||||
this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck);
|
||||
//
|
||||
// treeSearch
|
||||
//
|
||||
this.treeSearch.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
@ -599,7 +610,7 @@
|
||||
this.tabPage2.Text = "Asset List";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// filterExludeMode
|
||||
// filterExcludeMode
|
||||
//
|
||||
this.filterExcludeMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.filterExcludeMode.AutoSize = true;
|
||||
@ -607,14 +618,15 @@
|
||||
this.filterExcludeMode.Enabled = false;
|
||||
this.filterExcludeMode.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.filterExcludeMode.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
this.filterExcludeMode.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.filterExcludeMode.Location = new System.Drawing.Point(409, 2);
|
||||
this.filterExcludeMode.Name = "filterExludeMode";
|
||||
this.filterExcludeMode.Name = "filterExcludeMode";
|
||||
this.filterExcludeMode.Size = new System.Drawing.Size(61, 17);
|
||||
this.filterExcludeMode.TabIndex = 2;
|
||||
this.filterExcludeMode.Text = "Exclude";
|
||||
this.filterExcludeMode.TextAlign = System.Drawing.ContentAlignment.BottomRight;
|
||||
this.filterExcludeMode.UseVisualStyleBackColor = false;
|
||||
this.filterExcludeMode.CheckedChanged += new System.EventHandler(this.filterExludeMode_CheckedChanged);
|
||||
this.filterExcludeMode.CheckedChanged += new System.EventHandler(this.filterExcludeMode_CheckedChanged);
|
||||
//
|
||||
// assetListView
|
||||
//
|
||||
@ -731,6 +743,7 @@
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.progressBar1.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.progressBar1.Location = new System.Drawing.Point(1, 3);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(478, 18);
|
||||
@ -782,6 +795,7 @@
|
||||
this.assetInfoLabel.AutoSize = true;
|
||||
this.assetInfoLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.assetInfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.assetInfoLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.assetInfoLabel.Location = new System.Drawing.Point(4, 8);
|
||||
this.assetInfoLabel.Name = "assetInfoLabel";
|
||||
this.assetInfoLabel.Size = new System.Drawing.Size(0, 13);
|
||||
@ -811,6 +825,7 @@
|
||||
//
|
||||
this.FMODcopyright.AutoSize = true;
|
||||
this.FMODcopyright.ForeColor = System.Drawing.SystemColors.ControlLight;
|
||||
this.FMODcopyright.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODcopyright.Location = new System.Drawing.Point(214, 365);
|
||||
this.FMODcopyright.Name = "FMODcopyright";
|
||||
this.FMODcopyright.Size = new System.Drawing.Size(283, 13);
|
||||
@ -821,6 +836,7 @@
|
||||
//
|
||||
this.FMODinfoLabel.AutoSize = true;
|
||||
this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODinfoLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODinfoLabel.Location = new System.Drawing.Point(275, 255);
|
||||
this.FMODinfoLabel.Name = "FMODinfoLabel";
|
||||
this.FMODinfoLabel.Size = new System.Drawing.Size(0, 13);
|
||||
@ -830,6 +846,7 @@
|
||||
//
|
||||
this.FMODtimerLabel.AutoSize = true;
|
||||
this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODtimerLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODtimerLabel.Location = new System.Drawing.Point(457, 253);
|
||||
this.FMODtimerLabel.Name = "FMODtimerLabel";
|
||||
this.FMODtimerLabel.Size = new System.Drawing.Size(102, 13);
|
||||
@ -840,6 +857,7 @@
|
||||
//
|
||||
this.FMODstatusLabel.AutoSize = true;
|
||||
this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODstatusLabel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODstatusLabel.Location = new System.Drawing.Point(214, 255);
|
||||
this.FMODstatusLabel.Name = "FMODstatusLabel";
|
||||
this.FMODstatusLabel.Size = new System.Drawing.Size(47, 13);
|
||||
@ -849,6 +867,7 @@
|
||||
// FMODprogressBar
|
||||
//
|
||||
this.FMODprogressBar.AutoSize = false;
|
||||
this.FMODprogressBar.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODprogressBar.Location = new System.Drawing.Point(213, 274);
|
||||
this.FMODprogressBar.Maximum = 1000;
|
||||
this.FMODprogressBar.Name = "FMODprogressBar";
|
||||
@ -861,6 +880,7 @@
|
||||
//
|
||||
// FMODvolumeBar
|
||||
//
|
||||
this.FMODvolumeBar.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODvolumeBar.LargeChange = 2;
|
||||
this.FMODvolumeBar.Location = new System.Drawing.Point(460, 303);
|
||||
this.FMODvolumeBar.Name = "FMODvolumeBar";
|
||||
@ -873,6 +893,7 @@
|
||||
// FMODloopButton
|
||||
//
|
||||
this.FMODloopButton.Appearance = System.Windows.Forms.Appearance.Button;
|
||||
this.FMODloopButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODloopButton.Location = new System.Drawing.Point(399, 303);
|
||||
this.FMODloopButton.Name = "FMODloopButton";
|
||||
this.FMODloopButton.Size = new System.Drawing.Size(55, 46);
|
||||
@ -884,6 +905,7 @@
|
||||
//
|
||||
// FMODstopButton
|
||||
//
|
||||
this.FMODstopButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODstopButton.Location = new System.Drawing.Point(338, 303);
|
||||
this.FMODstopButton.Name = "FMODstopButton";
|
||||
this.FMODstopButton.Size = new System.Drawing.Size(55, 46);
|
||||
@ -894,6 +916,7 @@
|
||||
//
|
||||
// FMODpauseButton
|
||||
//
|
||||
this.FMODpauseButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODpauseButton.Location = new System.Drawing.Point(277, 303);
|
||||
this.FMODpauseButton.Name = "FMODpauseButton";
|
||||
this.FMODpauseButton.Size = new System.Drawing.Size(55, 46);
|
||||
@ -904,6 +927,7 @@
|
||||
//
|
||||
// FMODplayButton
|
||||
//
|
||||
this.FMODplayButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
|
||||
this.FMODplayButton.Location = new System.Drawing.Point(216, 303);
|
||||
this.FMODplayButton.Name = "FMODplayButton";
|
||||
this.FMODplayButton.Size = new System.Drawing.Size(55, 46);
|
||||
@ -945,7 +969,7 @@
|
||||
// textPreviewBox
|
||||
//
|
||||
this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F);
|
||||
this.textPreviewBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.textPreviewBox.Multiline = true;
|
||||
this.textPreviewBox.Name = "textPreviewBox";
|
||||
@ -1080,17 +1104,6 @@
|
||||
this.showOriginalFileToolStripMenuItem.Visible = false;
|
||||
this.showOriginalFileToolStripMenuItem.Click += new System.EventHandler(this.showOriginalFileToolStripMenuItem_Click);
|
||||
//
|
||||
// sceneTreeView
|
||||
//
|
||||
this.sceneTreeView.CheckBoxes = true;
|
||||
this.sceneTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.sceneTreeView.HideSelection = false;
|
||||
this.sceneTreeView.Location = new System.Drawing.Point(0, 20);
|
||||
this.sceneTreeView.Name = "sceneTreeView";
|
||||
this.sceneTreeView.Size = new System.Drawing.Size(472, 587);
|
||||
this.sceneTreeView.TabIndex = 1;
|
||||
this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck);
|
||||
//
|
||||
// AssetStudioGUIForm
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
|
@ -1579,7 +1579,7 @@ namespace AssetStudioGUI
|
||||
return selectedAssets;
|
||||
}
|
||||
|
||||
private void filterExludeMode_CheckedChanged(object sender, EventArgs e)
|
||||
private void filterExcludeMode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
FilterAssetList();
|
||||
}
|
||||
|
@ -1,22 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj" />
|
||||
<ProjectReference Include="..\AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
<ProjectReference Include="..\Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" !$(TargetFramework.Contains('windows')) ">
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder.Linux" Version="0.1.0" />
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder.macOS" Version="0.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder.Windows" Version="0.1.0" />
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder">
|
||||
<Version>0.17.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj" />
|
||||
<ProjectReference Include="..\AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<ProjectReference Include="..\Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -10,7 +10,10 @@ using System;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using AssetStudio.PInvoke;
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
@ -749,10 +752,12 @@ namespace FMOD
|
||||
*/
|
||||
public struct Factory
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
static Factory()
|
||||
{
|
||||
DllLoader.PreloadDll(VERSION.dll);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static RESULT System_Create(out System system)
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.47.1</Version>
|
||||
<Version>0.16.48.1</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
@ -1,16 +1,20 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using AssetStudio.PInvoke;
|
||||
#endif
|
||||
|
||||
namespace Texture2DDecoder
|
||||
{
|
||||
public static unsafe partial class TextureDecoder
|
||||
{
|
||||
|
||||
#if NETFRAMEWORK
|
||||
static TextureDecoder()
|
||||
{
|
||||
DllLoader.PreloadDll(T2DDll.DllName);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool DecodeDXT1(byte[] data, int width, int height, byte[] image)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user