Compare commits
225 Commits
v0.14.38-m
...
v0.17.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
171962e61f | ||
|
|
c8a21838c9 | ||
|
|
cf67815d53 | ||
|
|
94c8b355fe | ||
|
|
4e41caf203 | ||
|
|
74a8555514 | ||
|
|
e1d883adf6 | ||
|
|
9784df0e16 | ||
|
|
4d919a2bfe | ||
|
|
6701f467b7 | ||
|
|
50f5da5554 | ||
|
|
2b6dcca9c8 | ||
|
|
0bdcb89b08 | ||
|
|
dcd7b98229 | ||
|
|
007e5c7e4d | ||
|
|
63564d5fff | ||
|
|
aea6cbc97f | ||
|
|
6d41693b85 | ||
|
|
5695afae7b | ||
|
|
bb9ea7d86b | ||
|
|
547659e151 | ||
|
|
2f8f57c1a6 | ||
|
|
b7d5d73f23 | ||
|
|
f0c237473c | ||
|
|
09947fd14f | ||
|
|
da216dace8 | ||
|
|
c7356875f9 | ||
|
|
02e46eaa0d | ||
|
|
b0bf5e0cfd | ||
|
|
11b9ca37da | ||
|
|
5944dd8c58 | ||
|
|
1c67e39504 | ||
|
|
2d81007556 | ||
|
|
4bae98813b | ||
|
|
90ec395b2a | ||
|
|
af3684bab8 | ||
|
|
1da51ac95b | ||
|
|
9e14f1ef00 | ||
|
|
4edadb19f8 | ||
|
|
44a1240f5f | ||
|
|
01957a9443 | ||
|
|
ad1b3b4911 | ||
|
|
0925751776 | ||
|
|
b59ba3ba94 | ||
|
|
67898c72ca | ||
|
|
0425423ca9 | ||
|
|
16a7107d4e | ||
|
|
10b7e84ffb | ||
|
|
679e7041a6 | ||
|
|
629c6248a4 | ||
|
|
7674081df7 | ||
|
|
fb574064c9 | ||
|
|
c52940abc4 | ||
|
|
5c662d64e4 | ||
|
|
b9cf95616b | ||
|
|
39490d4e03 | ||
|
|
a96d1a5d5d | ||
|
|
568daafc7f | ||
|
|
2a2216e2bf | ||
|
|
dfbe46e1e5 | ||
|
|
6a9aad510c | ||
|
|
fd21cafd29 | ||
|
|
ea09a8de64 | ||
|
|
7fa5b4f355 | ||
|
|
c22d92009a | ||
|
|
53f3e8232a | ||
|
|
2fe57a1c5d | ||
|
|
ded2dcd54e | ||
|
|
8ae3df6197 | ||
|
|
64d9718c34 | ||
|
|
220004c976 | ||
|
|
a324366be9 | ||
|
|
06b4ae9ffe | ||
|
|
77b056de5e | ||
|
|
344edb722f | ||
|
|
98c4d0c3ab | ||
|
|
23ac590648 | ||
|
|
54445475a3 | ||
|
|
7299bcba6d | ||
|
|
5487ff4e60 | ||
|
|
b3621a75b0 | ||
|
|
8b048b9e1e | ||
|
|
41a79f485f | ||
|
|
a060a392e7 | ||
|
|
0798af7c5c | ||
|
|
8ebfa16e19 | ||
|
|
d158e864b5 | ||
|
|
b70b5196e3 | ||
|
|
4f88841026 | ||
|
|
dc9429feac | ||
|
|
a3c16ed3d6 | ||
|
|
5b83eebdda | ||
|
|
1fcf7a4364 | ||
|
|
973d50ce8b | ||
|
|
50485a9bd3 | ||
|
|
dbb3d3fef7 | ||
|
|
e1cfff63c3 | ||
|
|
44514a4e10 | ||
|
|
b1205808e2 | ||
|
|
7d3a4a10fc | ||
|
|
b909857820 | ||
|
|
b674e66407 | ||
|
|
d7dcd3f405 | ||
|
|
44145e0b9c | ||
|
|
d4e21f824c | ||
|
|
e7a4604a65 | ||
|
|
74f2c3190b | ||
|
|
8d193a63cd | ||
|
|
e61a317185 | ||
|
|
f67965b1dd | ||
|
|
07a81d9bfe | ||
|
|
95fd1823c8 | ||
|
|
d25451d5b9 | ||
|
|
0e1a886e0b | ||
|
|
97b5f51f3a | ||
|
|
7295feda72 | ||
|
|
fe95c91759 | ||
|
|
d220315d9b | ||
|
|
a94caa5e34 | ||
|
|
3660b4ed67 | ||
|
|
3370f93037 | ||
|
|
80653711cd | ||
|
|
f0b23bbfe7 | ||
|
|
88c5804586 | ||
|
|
e501940f03 | ||
|
|
d4060cde6d | ||
|
|
582a779441 | ||
|
|
5fa4934787 | ||
|
|
18277fbea8 | ||
|
|
571ea2da4a | ||
|
|
9cbe91decb | ||
|
|
19c6c5fe73 | ||
|
|
792850dbb2 | ||
|
|
2ce9cae957 | ||
|
|
af5e50cfa9 | ||
|
|
ce1172ca9a | ||
|
|
a7e6d91f5b | ||
|
|
34a0af683a | ||
|
|
91410a33b1 | ||
|
|
d08b78c2cf | ||
|
|
2ef52afe1e | ||
|
|
05a41d2f1e | ||
|
|
34c38e1415 | ||
|
|
c85873b729 | ||
|
|
b146d251a7 | ||
|
|
3129d67fc1 | ||
|
|
850ba63a10 | ||
|
|
17b91984d6 | ||
|
|
7ab2cda120 | ||
|
|
4345885cc9 | ||
|
|
53720e37ab | ||
|
|
7c3cb36630 | ||
|
|
c1cddce031 | ||
|
|
973a1076e4 | ||
|
|
089e164756 | ||
|
|
c2b6691fd9 | ||
|
|
8dec094304 | ||
|
|
bedee240be | ||
|
|
d963d71b12 | ||
|
|
77a0c9c40a | ||
|
|
f3e406983b | ||
|
|
08b7bfcf9a | ||
|
|
57e4f7cefd | ||
|
|
c9cf2d188e | ||
|
|
ab98585b6a | ||
|
|
075d53a455 | ||
|
|
432116d834 | ||
|
|
caa45216ef | ||
|
|
c9394cd957 | ||
|
|
46c0e8ffe1 | ||
|
|
d14c232015 | ||
|
|
4002bdecb8 | ||
|
|
17259e00c7 | ||
|
|
44b02b92d8 | ||
|
|
251854cc41 | ||
|
|
6f7b77245d | ||
|
|
6d99f5ebf6 | ||
|
|
f1f2430f97 | ||
|
|
b52696c965 | ||
|
|
5fba52dc83 | ||
|
|
dfb74baf79 | ||
|
|
978e90a403 | ||
|
|
c17d7d6331 | ||
|
|
9fef18d6ea | ||
|
|
ee0cd4ab52 | ||
|
|
f904bc138b | ||
|
|
7ed5345b1b | ||
|
|
d7f652d572 | ||
|
|
32ce032655 | ||
|
|
e1cf36aa3c | ||
|
|
f644396a15 | ||
|
|
3e77c34bd5 | ||
|
|
052c60f629 | ||
|
|
a1f2e3e7fe | ||
|
|
32ee8b326f | ||
|
|
06ce479eb6 | ||
|
|
03f74bac64 | ||
|
|
344b675745 | ||
|
|
86590d95a5 | ||
|
|
bbea1341b2 | ||
|
|
ca60dd9834 | ||
|
|
7aa35b5b8c | ||
|
|
bd2decdb8f | ||
|
|
9b2c85bcae | ||
|
|
efbab7c43a | ||
|
|
729a8a8263 | ||
|
|
0ec29f62ca | ||
|
|
796317f9d9 | ||
|
|
7596dcc7cd | ||
|
|
422851cdab | ||
|
|
ec0a2a47f1 | ||
|
|
8ce5b947f6 | ||
|
|
419ca63f9d | ||
|
|
6fdb0c7b0e | ||
|
|
4e97b4b898 | ||
|
|
1766dcbdeb | ||
|
|
ef38471ff1 | ||
|
|
217a7993e9 | ||
|
|
0a41615763 | ||
|
|
9d34f668d5 | ||
|
|
9269a36725 | ||
|
|
813e8b10a6 | ||
|
|
84c75fadf5 | ||
|
|
c76e41b1ab | ||
|
|
fefeea5f35 |
57
.github/workflows/build.yml
vendored
Normal file
57
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: AssetStudioBuild
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/setup-msbuild@v1.1
|
||||
|
||||
- name: Download FBX SDK
|
||||
run: |
|
||||
md fbx
|
||||
cd fbx
|
||||
Invoke-WebRequest "https://damassets.autodesk.net/content/dam/autodesk/www/adn/fbx/2020-2-1/fbx202021_fbxsdk_vs2019_win.exe" -OutFile "fbxsdk.exe"
|
||||
Start-Process -FilePath "fbxsdk.exe" /S -Wait
|
||||
Invoke-WebRequest "https://damassets.autodesk.net/content/dam/autodesk/www/adn/fbx/2020-2-1/fbx202021_fbxsdk_vs2019_pdbs.exe" -OutFile "fbxpdb.exe"
|
||||
Start-Process -FilePath "fbxpdb.exe" /S -Wait
|
||||
cd ..
|
||||
|
||||
- name: Nuget Restore
|
||||
run: nuget restore
|
||||
|
||||
- name: Build .Net472
|
||||
run: msbuild /p:Configuration=Release /p:TargetFramework=net472 /verbosity:minimal
|
||||
|
||||
- name: Build .Net5
|
||||
run: msbuild /t:AssetStudioGUI:publish /p:Configuration=Release /p:TargetFramework=net5.0-windows /p:SelfContained=false /verbosity:minimal
|
||||
|
||||
- name: Build .Net6
|
||||
run: msbuild /t:AssetStudioGUI:publish /p:Configuration=Release /p:TargetFramework=net6.0-windows /p:SelfContained=false /verbosity:minimal
|
||||
|
||||
- name: Upload .Net472 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net472
|
||||
path: AssetStudioGUI/bin/Release/net472
|
||||
|
||||
- name: Upload .Net5 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net5
|
||||
path: AssetStudioGUI/bin/Release/net5.0-windows/publish
|
||||
|
||||
- name: Upload .Net6 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net6
|
||||
path: AssetStudioGUI/bin/Release/net6.0-windows/publish
|
||||
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.*
|
||||
|
||||
11
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
11
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.17.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
66
AssetStudio.PInvoke/DllLoader.cs
Normal file
66
AssetStudio.PInvoke/DllLoader.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
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 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(GetDirectedDllDirectory(localDir), dllName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDirectedDllDirectory(string localDir)
|
||||
{
|
||||
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);
|
||||
|
||||
return directedDllDir;
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
var dllFileName = $"{dllName}.dll";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
// Specify SEARCH_DLL_LOAD_DIR to load dependent libraries located in the same platform-specific directory.
|
||||
var hLibrary = LoadLibraryEx(directedDllPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
var exception = new Win32Exception(errorCode);
|
||||
|
||||
throw new DllNotFoundException(exception.Message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
// HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
// HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags);
|
||||
|
||||
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
|
||||
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
// Generally the technique from Steamworks.NET
|
||||
public class Utf8StringHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
|
||||
static Utf8StringHandle()
|
||||
{
|
||||
Utf8 = new UTF8Encoding(false);
|
||||
}
|
||||
|
||||
public Utf8StringHandle(string str)
|
||||
: base(true)
|
||||
{
|
||||
IntPtr buffer;
|
||||
|
||||
if (str == null)
|
||||
{
|
||||
buffer = IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str.Length == 0)
|
||||
{
|
||||
buffer = Marshal.AllocHGlobal(1);
|
||||
|
||||
unsafe
|
||||
{
|
||||
*(byte*)buffer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var strlen = Utf8.GetByteCount(str);
|
||||
var strBuffer = new byte[strlen + 1];
|
||||
|
||||
Utf8.GetBytes(str, 0, str.Length, strBuffer, 0);
|
||||
|
||||
buffer = Marshal.AllocHGlobal(strBuffer.Length);
|
||||
|
||||
Marshal.Copy(strBuffer, 0, buffer, strBuffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
SetHandle(buffer);
|
||||
}
|
||||
|
||||
public static string ReadUtf8StringFromPointer(IntPtr lpstr)
|
||||
{
|
||||
if (lpstr == IntPtr.Zero || lpstr == new IntPtr(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var byteCount = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var p = (byte*)lpstr.ToPointer();
|
||||
|
||||
while (*p != 0)
|
||||
{
|
||||
byteCount += 1;
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteCount == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var strBuffer = new byte[byteCount];
|
||||
|
||||
Marshal.Copy(lpstr, strBuffer, 0, byteCount);
|
||||
|
||||
var str = Utf8.GetString(strBuffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
if (!IsInvalid)
|
||||
{
|
||||
Marshal.FreeHGlobal(handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly UTF8Encoding Utf8;
|
||||
|
||||
}
|
||||
}
|
||||
184
AssetStudio.sln
184
AssetStudio.sln
@@ -1,71 +1,159 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29920.165
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33414.496
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{422FEC21-EF60-4F29-AA56-95DFDA23C913}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio.PInvoke", "AssetStudio.PInvoke\AssetStudio.PInvoke.csproj", "{0B2BE613-3049-4021-85D1-21C325F729F4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Texture2DDecoder", "Texture2DDecoder\Texture2DDecoder.vcxproj", "{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioFBXWrapper", "AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj", "{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027} = {11EA25A3-ED68-40EE-A9D0-7FDE3B583027}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{80AEC261-21EE-4E4F-A93B-7A744DC84888}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{29EAD018-1C67-497A-AB8E-727D595AD756}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Texture2DDecoderWrapper", "Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj", "{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD} = {29356642-C46E-4144-83D8-22DC09D0D7FD}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBXNative", "AssetStudioFBXNative\AssetStudioFBXNative.vcxproj", "{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}"
|
||||
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
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x64.Build.0 = Debug|x64
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x86.Build.0 = Debug|Win32
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x64.ActiveCfg = Release|x64
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x64.Build.0 = Release|x64
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x86.Build.0 = Release|Win32
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x64.Build.0 = Debug|x64
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x64.ActiveCfg = Release|x64
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x64.Build.0 = Release|x64
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x86.Build.0 = Release|Win32
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x64.Build.0 = Debug|x64
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x86.Build.0 = Debug|x86
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x64.ActiveCfg = Release|x64
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x64.Build.0 = Release|x64
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x86.ActiveCfg = Release|x86
|
||||
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x86.Build.0 = Release|x86
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x64.Build.0 = Debug|x64
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x86.Build.0 = Debug|x86
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x64.ActiveCfg = Release|x64
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x64.Build.0 = Release|x64
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x86.ActiveCfg = Release|x86
|
||||
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x86.Build.0 = Release|x86
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.Build.0 = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.ActiveCfg = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.Build.0 = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.Build.0 = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.ActiveCfg = Release|x64
|
||||
{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
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F8734F96-97B6-40CA-B791-6D5467F2F713}
|
||||
SolutionGuid = {3C074481-9CDD-4780-B9F6-57BBC5092EA2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,154 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AssetStudio</RootNamespace>
|
||||
<AssemblyName>AssetStudio</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworks>net472;net6.0;net6.0-windows;net7.0;net7.0-windows</TargetFrameworks>
|
||||
<Version>0.17.2.0</Version>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © aelurum 2023</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="7zip\Common\CommandLineParser.cs" />
|
||||
<Compile Include="7zip\Common\CRC.cs" />
|
||||
<Compile Include="7zip\Common\InBuffer.cs" />
|
||||
<Compile Include="7zip\Common\OutBuffer.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaBase.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaDecoder.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaEncoder.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\IMatchFinder.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzBinTree.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzInWindow.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzOutWindow.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoder.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoderBit.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoderBitTree.cs" />
|
||||
<Compile Include="7zip\ICoder.cs" />
|
||||
<Compile Include="AssetsManager.cs" />
|
||||
<Compile Include="Brotli\BitReader.cs" />
|
||||
<Compile Include="Brotli\BrotliInputStream.cs" />
|
||||
<Compile Include="Brotli\BrotliRuntimeException.cs" />
|
||||
<Compile Include="Brotli\Context.cs" />
|
||||
<Compile Include="Brotli\Decode.cs" />
|
||||
<Compile Include="Brotli\Dictionary.cs" />
|
||||
<Compile Include="Brotli\Huffman.cs" />
|
||||
<Compile Include="Brotli\HuffmanTreeGroup.cs" />
|
||||
<Compile Include="Brotli\IntReader.cs" />
|
||||
<Compile Include="Brotli\Prefix.cs" />
|
||||
<Compile Include="Brotli\RunningState.cs" />
|
||||
<Compile Include="Brotli\State.cs" />
|
||||
<Compile Include="Brotli\Transform.cs" />
|
||||
<Compile Include="Brotli\Utils.cs" />
|
||||
<Compile Include="Brotli\WordTransformType.cs" />
|
||||
<Compile Include="BuildTarget.cs" />
|
||||
<Compile Include="BuildType.cs" />
|
||||
<Compile Include="BundleFile.cs" />
|
||||
<Compile Include="Classes\Animation.cs" />
|
||||
<Compile Include="Classes\AnimationClip.cs" />
|
||||
<Compile Include="Classes\Animator.cs" />
|
||||
<Compile Include="Classes\AnimatorController.cs" />
|
||||
<Compile Include="Classes\AnimatorOverrideController.cs" />
|
||||
<Compile Include="Classes\AssetBundle.cs" />
|
||||
<Compile Include="Classes\AudioClip.cs" />
|
||||
<Compile Include="Classes\Avatar.cs" />
|
||||
<Compile Include="Classes\Behaviour.cs" />
|
||||
<Compile Include="Classes\BuildSettings.cs" />
|
||||
<Compile Include="Classes\Component.cs" />
|
||||
<Compile Include="Classes\EditorExtension.cs" />
|
||||
<Compile Include="Classes\Font.cs" />
|
||||
<Compile Include="Classes\GameObject.cs" />
|
||||
<Compile Include="Classes\Material.cs" />
|
||||
<Compile Include="Classes\Mesh.cs" />
|
||||
<Compile Include="Classes\MeshFilter.cs" />
|
||||
<Compile Include="Classes\MeshRenderer.cs" />
|
||||
<Compile Include="Classes\MonoBehaviour.cs" />
|
||||
<Compile Include="Classes\MonoScript.cs" />
|
||||
<Compile Include="Classes\MovieTexture.cs" />
|
||||
<Compile Include="Classes\NamedObject.cs" />
|
||||
<Compile Include="Classes\Object.cs" />
|
||||
<Compile Include="Classes\PlayerSettings.cs" />
|
||||
<Compile Include="Classes\PPtr.cs" />
|
||||
<Compile Include="Classes\RectTransform.cs" />
|
||||
<Compile Include="Classes\Renderer.cs" />
|
||||
<Compile Include="Classes\RuntimeAnimatorController.cs" />
|
||||
<Compile Include="Classes\Shader.cs" />
|
||||
<Compile Include="Classes\SkinnedMeshRenderer.cs" />
|
||||
<Compile Include="Classes\Sprite.cs" />
|
||||
<Compile Include="Classes\SpriteAtlas.cs" />
|
||||
<Compile Include="Classes\TextAsset.cs" />
|
||||
<Compile Include="Classes\Texture.cs" />
|
||||
<Compile Include="Classes\Texture2D.cs" />
|
||||
<Compile Include="Classes\Transform.cs" />
|
||||
<Compile Include="Classes\VideoClip.cs" />
|
||||
<Compile Include="ClassIDType.cs" />
|
||||
<Compile Include="CommonString.cs" />
|
||||
<Compile Include="EndianBinaryReader.cs" />
|
||||
<Compile Include="Extensions\BinaryReaderExtensions.cs" />
|
||||
<Compile Include="Extensions\BinaryWriterExtensions.cs" />
|
||||
<Compile Include="Extensions\StreamExtensions.cs" />
|
||||
<Compile Include="FileIdentifier.cs" />
|
||||
<Compile Include="IImported.cs" />
|
||||
<Compile Include="ILogger.cs" />
|
||||
<Compile Include="ImportHelper.cs" />
|
||||
<Compile Include="IProgress.cs" />
|
||||
<Compile Include="LocalSerializedObjectIdentifier.cs" />
|
||||
<Compile Include="Logger.cs" />
|
||||
<Compile Include="Lz4DecoderStream.cs" />
|
||||
<Compile Include="Math\Color.cs" />
|
||||
<Compile Include="Math\Half.cs" />
|
||||
<Compile Include="Math\HalfHelper.cs" />
|
||||
<Compile Include="Math\Matrix4x4.cs" />
|
||||
<Compile Include="Math\Quaternion.cs" />
|
||||
<Compile Include="Math\Vector2.cs" />
|
||||
<Compile Include="Math\Vector3.cs" />
|
||||
<Compile Include="Math\Vector4.cs" />
|
||||
<Compile Include="ObjectInfo.cs" />
|
||||
<Compile Include="ObjectReader.cs" />
|
||||
<Compile Include="Progress.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ResourceReader.cs" />
|
||||
<Compile Include="SerializedFile.cs" />
|
||||
<Compile Include="SerializedFileHeader.cs" />
|
||||
<Compile Include="SerializedType.cs" />
|
||||
<Compile Include="SevenZipHelper.cs" />
|
||||
<Compile Include="StreamFile.cs" />
|
||||
<Compile Include="TypeTreeHelper.cs" />
|
||||
<Compile Include="TypeTreeNode.cs" />
|
||||
<Compile Include="UType.cs" />
|
||||
<Compile Include="WebFile.cs" />
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.1.11" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,34 +1,102 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetsManager
|
||||
{
|
||||
public string SpecifyUnityVersion;
|
||||
public List<SerializedFile> assetsFileList = new List<SerializedFile>();
|
||||
private HashSet<ClassIDType> filteredAssetTypesList = new HashSet<ClassIDType>();
|
||||
|
||||
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private List<string> importFiles = new List<string>();
|
||||
private HashSet<string> importFilesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
private HashSet<string> noexistFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void LoadFiles(params string[] files)
|
||||
public void SetAssetFilter(params ClassIDType[] classIDTypes)
|
||||
{
|
||||
var path = Path.GetDirectoryName(files[0]);
|
||||
MergeSplitAssets(path);
|
||||
var toReadFile = ProcessingSplitFiles(files.ToList());
|
||||
Load(toReadFile);
|
||||
if (filteredAssetTypesList.Count == 0)
|
||||
{
|
||||
filteredAssetTypesList.UnionWith(new HashSet<ClassIDType>
|
||||
{
|
||||
ClassIDType.AssetBundle,
|
||||
ClassIDType.ResourceManager,
|
||||
});
|
||||
}
|
||||
|
||||
if (classIDTypes.Contains(ClassIDType.MonoBehaviour))
|
||||
{
|
||||
filteredAssetTypesList.Add(ClassIDType.MonoScript);
|
||||
}
|
||||
if (classIDTypes.Contains(ClassIDType.Sprite))
|
||||
{
|
||||
filteredAssetTypesList.Add(ClassIDType.Texture2D);
|
||||
}
|
||||
|
||||
filteredAssetTypesList.UnionWith(classIDTypes);
|
||||
}
|
||||
|
||||
public void LoadFolder(string path)
|
||||
public void SetAssetFilter(List<ClassIDType> classIDTypeList)
|
||||
{
|
||||
MergeSplitAssets(path, true);
|
||||
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).ToList();
|
||||
var toReadFile = ProcessingSplitFiles(files);
|
||||
SetAssetFilter(classIDTypeList.ToArray());
|
||||
}
|
||||
|
||||
public void LoadFilesAndFolders(params string[] path)
|
||||
{
|
||||
List<string> pathList = new List<string>();
|
||||
pathList.AddRange(path);
|
||||
LoadFilesAndFolders(out _, pathList);
|
||||
}
|
||||
|
||||
public void LoadFilesAndFolders(out string parentPath, params string[] path)
|
||||
{
|
||||
List<string> pathList = new List<string>();
|
||||
pathList.AddRange(path);
|
||||
LoadFilesAndFolders(out parentPath, pathList);
|
||||
}
|
||||
|
||||
public void LoadFilesAndFolders(out string parentPath, List<string> pathList)
|
||||
{
|
||||
List<string> fileList = new List<string>();
|
||||
bool filesInPath = false;
|
||||
parentPath = "";
|
||||
foreach (var path in pathList)
|
||||
{
|
||||
var fullPath = Path.GetFullPath(path);
|
||||
if (Directory.Exists(fullPath))
|
||||
{
|
||||
var parent = Directory.GetParent(fullPath).FullName;
|
||||
if (!filesInPath && (parentPath == "" || parentPath.Length > parent.Length))
|
||||
{
|
||||
parentPath = parent;
|
||||
}
|
||||
MergeSplitAssets(fullPath, true);
|
||||
fileList.AddRange(Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories));
|
||||
}
|
||||
else
|
||||
{
|
||||
parentPath = Path.GetDirectoryName(fullPath);
|
||||
fileList.Add(fullPath);
|
||||
filesInPath = true;
|
||||
}
|
||||
}
|
||||
if (filesInPath)
|
||||
{
|
||||
MergeSplitAssets(parentPath);
|
||||
}
|
||||
var toReadFile = ProcessingSplitFiles(fileList);
|
||||
fileList.Clear();
|
||||
pathList.Clear();
|
||||
|
||||
Load(toReadFile);
|
||||
}
|
||||
|
||||
@@ -50,6 +118,7 @@ namespace AssetStudio
|
||||
|
||||
importFiles.Clear();
|
||||
importFilesHash.Clear();
|
||||
noexistFiles.Clear();
|
||||
assetsFileListHash.Clear();
|
||||
|
||||
ReadAssets();
|
||||
@@ -58,121 +127,158 @@ namespace AssetStudio
|
||||
|
||||
private void LoadFile(string fullName)
|
||||
{
|
||||
switch (CheckFileType(fullName, out var reader))
|
||||
var reader = new FileReader(fullName);
|
||||
LoadFile(reader);
|
||||
}
|
||||
|
||||
private void LoadFile(FileReader reader)
|
||||
{
|
||||
switch (reader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(fullName, reader);
|
||||
LoadAssetsFile(reader);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(fullName, reader);
|
||||
LoadBundleFile(reader);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(fullName, reader);
|
||||
LoadWebFile(reader);
|
||||
break;
|
||||
case FileType.GZipFile:
|
||||
LoadFile(DecompressGZip(reader));
|
||||
break;
|
||||
case FileType.BrotliFile:
|
||||
LoadFile(DecompressBrotli(reader));
|
||||
break;
|
||||
case FileType.ZipFile:
|
||||
LoadZipFile(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFile(string fullName, EndianBinaryReader reader)
|
||||
private void LoadAssetsFile(FileReader reader)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
if (!assetsFileListHash.Contains(fileName))
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
Logger.Info($"Loading {fileName}");
|
||||
Logger.Info($"Loading {reader.FullPath}");
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(this, fullName, reader);
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
|
||||
foreach (var sharedFile in assetsFile.m_Externals)
|
||||
{
|
||||
var sharedFilePath = Path.GetDirectoryName(fullName) + "\\" + sharedFile.fileName;
|
||||
var sharedFileName = sharedFile.fileName;
|
||||
|
||||
if (!importFilesHash.Contains(sharedFileName))
|
||||
{
|
||||
if (!File.Exists(sharedFilePath))
|
||||
var sharedFilePath = Path.Combine(Path.GetDirectoryName(reader.FullPath), sharedFileName);
|
||||
if (!noexistFiles.Contains(sharedFilePath))
|
||||
{
|
||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(fullName), sharedFileName, SearchOption.AllDirectories);
|
||||
if (findFiles.Length > 0)
|
||||
if (!File.Exists(sharedFilePath))
|
||||
{
|
||||
sharedFilePath = findFiles[0];
|
||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
|
||||
if (findFiles.Length > 0)
|
||||
{
|
||||
sharedFilePath = findFiles[0];
|
||||
}
|
||||
}
|
||||
if (File.Exists(sharedFilePath))
|
||||
{
|
||||
importFiles.Add(sharedFilePath);
|
||||
importFilesHash.Add(sharedFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
noexistFiles.Add(sharedFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(sharedFilePath))
|
||||
{
|
||||
importFiles.Add(sharedFilePath);
|
||||
importFilesHash.Add(sharedFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (NotSupportedException e)
|
||||
{
|
||||
Logger.Error(e.Message);
|
||||
reader.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Error while reading assets file {reader.FullPath}\r\n{e}");
|
||||
reader.Dispose();
|
||||
//Logger.Warning($"Unable to load assets file {fileName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"Skipping {reader.FullPath}");
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFromMemory(string fullName, EndianBinaryReader reader, string originalPath, string unityVersion = null)
|
||||
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
if (!assetsFileListHash.Contains(fileName))
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(this, fullName, reader);
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
assetsFile.originalPath = originalPath;
|
||||
if (assetsFile.header.m_Version < 7)
|
||||
if (!string.IsNullOrEmpty(unityVersion) && assetsFile.header.m_Version < SerializedFileFormatVersion.Unknown_7)
|
||||
{
|
||||
assetsFile.SetVersion(unityVersion);
|
||||
}
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch
|
||||
catch (NotSupportedException e)
|
||||
{
|
||||
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}");
|
||||
resourceFileReaders.Add(fileName, reader);
|
||||
Logger.Error(e.Message);
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Error while reading assets file {reader.FullPath} from {Path.GetFileName(originalPath)}\r\n{e}");
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
}
|
||||
else
|
||||
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
|
||||
}
|
||||
|
||||
private void LoadBundleFile(string fullName, EndianBinaryReader reader, string parentPath = null)
|
||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
Logger.Info("Loading " + fileName);
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var bundleFile = new BundleFile(reader, fullName);
|
||||
var bundleFile = new BundleFile(reader, SpecifyUnityVersion);
|
||||
foreach (var file in bundleFile.fileList)
|
||||
{
|
||||
var subReader = new EndianBinaryReader(file.stream);
|
||||
if (SerializedFile.IsSerializedFile(subReader))
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
if (subReader.FileType == FileType.AssetsFile)
|
||||
{
|
||||
var dummyPath = Path.GetDirectoryName(fullName) + Path.DirectorySeparatorChar + file.fileName;
|
||||
LoadAssetsFromMemory(dummyPath, subReader, parentPath ?? fullName, bundleFile.m_Header.unityRevision);
|
||||
LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision);
|
||||
}
|
||||
else
|
||||
else if (!resourceFileReaders.ContainsKey(file.fileName))
|
||||
{
|
||||
resourceFileReaders.Add(file.fileName, subReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (NotSupportedException e)
|
||||
{
|
||||
/*var str = $"Unable to load bundle file {fileName}";
|
||||
if (parentPath != null)
|
||||
Logger.Error(e.Message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var str = $"Error while reading bundle file {reader.FullPath}";
|
||||
if (originalPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(parentPath)}";
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
}
|
||||
Logger.Error(str);*/
|
||||
Logger.Warning($"{str}\r\n{e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -180,36 +286,36 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadWebFile(string fullName, EndianBinaryReader reader)
|
||||
private void LoadWebFile(FileReader reader)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
Logger.Info("Loading " + fileName);
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var webFile = new WebFile(reader);
|
||||
foreach (var file in webFile.fileList)
|
||||
{
|
||||
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
|
||||
switch (CheckFileType(file.stream, out var fileReader))
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
switch (subReader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFromMemory(dummyPath, fileReader, fullName);
|
||||
LoadAssetsFromMemory(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(dummyPath, fileReader, fullName);
|
||||
LoadBundleFile(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(dummyPath, fileReader);
|
||||
LoadWebFile(subReader);
|
||||
break;
|
||||
case FileType.ResourceFile:
|
||||
resourceFileReaders.Add(file.fileName, fileReader);
|
||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
//Logger.Error($"Unable to load web file {fileName}");
|
||||
Logger.Error($"Error while reading web file {reader.FullPath}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -217,6 +323,122 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadZipFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Reading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
using (ZipArchive archive = new ZipArchive(reader.BaseStream, ZipArchiveMode.Read))
|
||||
{
|
||||
List<string> splitFiles = new List<string>();
|
||||
// register all files before parsing the assets so that the external references can be found
|
||||
// and find split files
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
if (entry.Name.Contains(".split"))
|
||||
{
|
||||
string baseName = Path.GetFileNameWithoutExtension(entry.Name);
|
||||
string basePath = Path.Combine(Path.GetDirectoryName(entry.FullName), baseName);
|
||||
if (!splitFiles.Contains(basePath))
|
||||
{
|
||||
splitFiles.Add(basePath);
|
||||
importFilesHash.Add(baseName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
importFilesHash.Add(entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// merge split files and load the result
|
||||
foreach (string basePath in splitFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream splitStream = new MemoryStream();
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
string path = $"{basePath}.split{i++}";
|
||||
ZipArchiveEntry entry = archive.GetEntry(path);
|
||||
if (entry == null)
|
||||
break;
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(splitStream);
|
||||
}
|
||||
}
|
||||
splitStream.Seek(0, SeekOrigin.Begin);
|
||||
FileReader entryReader = new FileReader(basePath, splitStream);
|
||||
LoadFile(entryReader);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Error while reading zip split file {basePath}\r\n{e}");
|
||||
}
|
||||
}
|
||||
|
||||
// load all entries
|
||||
var progressCount = archive.Entries.Count;
|
||||
int k = 0;
|
||||
Progress.Reset();
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), reader.FileName, entry.FullName);
|
||||
// create a new stream
|
||||
// - to store the deflated stream in
|
||||
// - to keep the data for later extraction
|
||||
Stream streamReader = new MemoryStream();
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(streamReader);
|
||||
}
|
||||
streamReader.Position = 0;
|
||||
|
||||
FileReader entryReader = new FileReader(dummyPath, streamReader);
|
||||
LoadFile(entryReader);
|
||||
if (entryReader.FileType == FileType.ResourceFile)
|
||||
{
|
||||
entryReader.Position = 0;
|
||||
if (!resourceFileReaders.ContainsKey(entry.Name))
|
||||
{
|
||||
resourceFileReaders.Add(entry.Name, entryReader);
|
||||
}
|
||||
}
|
||||
Progress.Report(++k, progressCount);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Error while reading zip entry {entry.FullName}\r\n{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip file {reader.FileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckStrippedVersion(SerializedFile assetsFile)
|
||||
{
|
||||
if (assetsFile.IsVersionStripped && string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
throw new NotSupportedException("The Unity version has been stripped, please set the version in the options");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
assetsFile.SetVersion(SpecifyUnityVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
@@ -247,9 +469,13 @@ namespace AssetStudio
|
||||
foreach (var objectInfo in assetsFile.m_Objects)
|
||||
{
|
||||
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo);
|
||||
if (filteredAssetTypesList.Count > 0 && !filteredAssetTypesList.Contains(objectReader.type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
Object obj;
|
||||
Object obj = null;
|
||||
switch (objectReader.type)
|
||||
{
|
||||
case ClassIDType.Animation:
|
||||
@@ -310,7 +536,8 @@ namespace AssetStudio
|
||||
obj = new RectTransform(objectReader);
|
||||
break;
|
||||
case ClassIDType.Shader:
|
||||
obj = new Shader(objectReader);
|
||||
if (objectReader.version[0] < 2021)
|
||||
obj = new Shader(objectReader);
|
||||
break;
|
||||
case ClassIDType.SkinnedMeshRenderer:
|
||||
obj = new SkinnedMeshRenderer(objectReader);
|
||||
@@ -333,21 +560,26 @@ namespace AssetStudio
|
||||
case ClassIDType.VideoClip:
|
||||
obj = new VideoClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.ResourceManager:
|
||||
obj = new ResourceManager(objectReader);
|
||||
break;
|
||||
default:
|
||||
obj = new Object(objectReader);
|
||||
break;
|
||||
}
|
||||
assetsFile.AddObject(obj);
|
||||
if (obj != null)
|
||||
assetsFile.AddObject(obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
/*var sb = new StringBuilder();
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Unable to load object")
|
||||
.AppendLine($"Assets {assetsFile.fileName}")
|
||||
.AppendLine($"Path {assetsFile.originalPath}")
|
||||
.AppendLine($"Type {objectReader.type}")
|
||||
.AppendLine($"PathID {objectInfo.m_PathID}")
|
||||
.Append(e);
|
||||
Logger.Error(sb.ToString());*/
|
||||
Logger.Warning(sb.ToString());
|
||||
}
|
||||
|
||||
Progress.Report(++i, progressCount);
|
||||
@@ -357,7 +589,7 @@ namespace AssetStudio
|
||||
|
||||
private void ProcessAssets()
|
||||
{
|
||||
Logger.Info("Process Assets...");
|
||||
Logger.Info("Process assets...");
|
||||
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
@@ -403,6 +635,14 @@ namespace AssetStudio
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
||||
if (m_SpriteAtlaOld.m_IsVariant)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,4 +650,4 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
AssetStudio/BigArrayPool.cs
Normal file
10
AssetStudio/BigArrayPool.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Buffers;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BigArrayPool<T>
|
||||
{
|
||||
private static readonly ArrayPool<T> s_shared = ArrayPool<T>.Create(64 * 1024 * 1024, 3);
|
||||
public static ArrayPool<T> Shared => s_shared;
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,9 @@ namespace AssetStudio
|
||||
{
|
||||
public enum BuildTarget
|
||||
{
|
||||
UnknownPlatform = 3716,
|
||||
DashboardWidget = 1,
|
||||
NoTarget = -2,
|
||||
AnyPlayer = -1,
|
||||
ValidPlayer = 1,
|
||||
StandaloneOSX = 2,
|
||||
StandaloneOSXPPC = 3,
|
||||
StandaloneOSXIntel = 4,
|
||||
@@ -19,8 +20,10 @@ namespace AssetStudio
|
||||
iOS = 9,
|
||||
PS3,
|
||||
XBOX360,
|
||||
Broadcom = 12,
|
||||
Android = 13,
|
||||
StandaloneGLESEmu = 14,
|
||||
StandaloneGLES20Emu = 15,
|
||||
NaCl = 16,
|
||||
StandaloneLinux = 17,
|
||||
FlashPlayer = 18,
|
||||
@@ -42,6 +45,14 @@ namespace AssetStudio
|
||||
WiiU,
|
||||
tvOS,
|
||||
Switch,
|
||||
NoTarget = -2
|
||||
Lumin,
|
||||
Stadia,
|
||||
CloudRendering,
|
||||
GameCoreXboxSeries,
|
||||
GameCoreXboxOne,
|
||||
PS5,
|
||||
EmbeddedLinux,
|
||||
QNX,
|
||||
UnknownPlatform = 9999
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using K4os.Compression.LZ4;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Lz4;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[Flags]
|
||||
public enum ArchiveFlags
|
||||
{
|
||||
CompressionTypeMask = 0x3f,
|
||||
BlocksAndDirectoryInfoCombined = 0x40,
|
||||
BlocksInfoAtTheEnd = 0x80,
|
||||
OldWebPluginCompatibility = 0x100,
|
||||
BlockInfoNeedPaddingAtStart = 0x200
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CnEncryptionFlags
|
||||
{
|
||||
OldFlag = 0x200,
|
||||
NewFlag = 0x400
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum StorageBlockFlags
|
||||
{
|
||||
CompressionTypeMask = 0x3f,
|
||||
Streamed = 0x40
|
||||
}
|
||||
|
||||
public enum CompressionType
|
||||
{
|
||||
None,
|
||||
Lzma,
|
||||
Lz4,
|
||||
Lz4HC,
|
||||
Lzham
|
||||
}
|
||||
|
||||
public class BundleFile
|
||||
{
|
||||
public class Header
|
||||
@@ -17,14 +49,14 @@ namespace AssetStudio
|
||||
public long size;
|
||||
public uint compressedBlocksInfoSize;
|
||||
public uint uncompressedBlocksInfoSize;
|
||||
public uint flags;
|
||||
public ArchiveFlags flags;
|
||||
}
|
||||
|
||||
public class StorageBlock
|
||||
{
|
||||
public uint compressedSize;
|
||||
public uint uncompressedSize;
|
||||
public ushort flags;
|
||||
public StorageBlockFlags flags;
|
||||
}
|
||||
|
||||
public class Node
|
||||
@@ -41,30 +73,61 @@ namespace AssetStudio
|
||||
|
||||
public StreamFile[] fileList;
|
||||
|
||||
public BundleFile(EndianBinaryReader reader, string path)
|
||||
public BundleFile(FileReader reader, string specUnityVer = "")
|
||||
{
|
||||
m_Header = new Header();
|
||||
m_Header.signature = reader.ReadStringToNull();
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
switch (m_Header.signature)
|
||||
{
|
||||
case "UnityArchive":
|
||||
break; //TODO
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
if (m_Header.version == 6)
|
||||
{
|
||||
goto case "UnityFS";
|
||||
}
|
||||
ReadHeaderAndBlocksInfo(reader);
|
||||
using (var blocksStream = CreateBlocksStream(path))
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocksAndDirectory(reader, blocksStream);
|
||||
ReadFiles(blocksStream, path);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
case "UnityFS":
|
||||
ReadHeader(reader);
|
||||
ReadBlocksInfoAndDirectory(reader);
|
||||
using (var blocksStream = CreateBlocksStream(path))
|
||||
|
||||
bool isUnityCnEnc = false;
|
||||
string unityVer = string.IsNullOrEmpty(specUnityVer) ? m_Header.unityRevision : specUnityVer;
|
||||
int[] ver = new string(unityVer.SkipWhile(x => !char.IsDigit(x)).TakeWhile(x => char.IsDigit(x) || x == '.').ToArray()).Split('.').Select(x => int.Parse(x)).ToArray();
|
||||
if (ver[0] != 0)
|
||||
{
|
||||
// https://issuetracker.unity3d.com/issues/files-within-assetbundles-do-not-start-on-aligned-boundaries-breaking-patching-on-nintendo-switch
|
||||
if (ver[0] < 2020 ||
|
||||
(ver[0] == 2020 && ver[1] <= 3 && ver[2] < 34) ||
|
||||
(ver[0] == 2021 && ver[1] <= 3 && ver[2] < 2) ||
|
||||
(ver[0] == 2022 && ver[1] <= 1 && ver[2] < 1))
|
||||
{
|
||||
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.OldFlag) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.NewFlag) != 0;
|
||||
}
|
||||
}
|
||||
if (isUnityCnEnc)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported bundle file. UnityCN encryption was detected.");
|
||||
}
|
||||
|
||||
ReadBlocksInfoAndDirectory(reader, ver);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocks(reader, blocksStream);
|
||||
ReadFiles(blocksStream, path);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -72,17 +135,13 @@ namespace AssetStudio
|
||||
|
||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
||||
{
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
if (m_Header.version >= 4)
|
||||
{
|
||||
var hash = reader.ReadBytes(16);
|
||||
var crc = reader.ReadUInt32();
|
||||
}
|
||||
var minimumStreamedBytes = reader.ReadUInt32();
|
||||
var headerSize = reader.ReadUInt32();
|
||||
m_Header.size = reader.ReadUInt32();
|
||||
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
|
||||
var levelCount = reader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[1];
|
||||
@@ -92,7 +151,6 @@ namespace AssetStudio
|
||||
{
|
||||
compressedSize = reader.ReadUInt32(),
|
||||
uncompressedSize = reader.ReadUInt32(),
|
||||
flags = (ushort)(isCompressed ? 1 : 0)
|
||||
};
|
||||
if (i == levelCount - 1)
|
||||
{
|
||||
@@ -107,7 +165,7 @@ namespace AssetStudio
|
||||
{
|
||||
var fileInfoHeaderSize = reader.ReadUInt32();
|
||||
}
|
||||
reader.Position = headerSize;
|
||||
reader.Position = m_Header.size;
|
||||
}
|
||||
|
||||
private Stream CreateBlocksStream(string path)
|
||||
@@ -116,7 +174,7 @@ namespace AssetStudio
|
||||
var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
|
||||
if (uncompressedSizeSum >= int.MaxValue)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(Path.GetFileName(path), uncompressedSizeSum);
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
|
||||
assetsDataStream = memoryMappedFile.CreateViewStream();*/
|
||||
blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
@@ -129,10 +187,11 @@ namespace AssetStudio
|
||||
|
||||
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
||||
if (blockInfo.flags == 1)
|
||||
if (isCompressed)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(uncompressedBytes))
|
||||
{
|
||||
@@ -167,14 +226,15 @@ namespace AssetStudio
|
||||
var node = m_DirectoryInfo[i];
|
||||
var file = new StreamFile();
|
||||
fileList[i] = file;
|
||||
file.path = node.path;
|
||||
file.fileName = Path.GetFileName(node.path);
|
||||
if (node.size >= int.MaxValue)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(file.fileName, entryinfo_size);
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, entryinfo_size);
|
||||
file.stream = memoryMappedFile.CreateViewStream();*/
|
||||
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(extractPath);
|
||||
file.stream = File.Create(extractPath + file.fileName);
|
||||
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -188,59 +248,82 @@ namespace AssetStudio
|
||||
|
||||
private void ReadHeader(EndianBinaryReader reader)
|
||||
{
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
m_Header.size = reader.ReadInt64();
|
||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.flags = reader.ReadUInt32();
|
||||
m_Header.flags = (ArchiveFlags)reader.ReadUInt32();
|
||||
if (m_Header.signature != "UnityFS")
|
||||
{
|
||||
reader.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
|
||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader, int[] unityVer)
|
||||
{
|
||||
byte[] blocksInfoBytes;
|
||||
if ((m_Header.flags & 0x80) != 0) //kArchiveBlocksInfoAtTheEnd
|
||||
|
||||
if (m_Header.version >= 7)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
else if (unityVer[0] >= 2019 && unityVer[1] >= 4)
|
||||
{
|
||||
//check if we need to align the reader
|
||||
//- align to 16 bytes and check if all are 0
|
||||
//- if not, reset the reader to the previous position
|
||||
var preAlign = reader.Position;
|
||||
var alignData = reader.ReadBytes((16 - (int)(preAlign % 16)) % 16);
|
||||
if (alignData.Any(x => x != 0))
|
||||
{
|
||||
reader.Position = preAlign;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_Header.flags & ArchiveFlags.BlocksInfoAtTheEnd) != 0)
|
||||
{
|
||||
var position = reader.Position;
|
||||
reader.Position = reader.BaseStream.Length - m_Header.compressedBlocksInfoSize;
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
reader.Position = position;
|
||||
}
|
||||
else //0x40 kArchiveBlocksAndDirectoryInfoCombined
|
||||
else //0x40 BlocksAndDirectoryInfoCombined
|
||||
{
|
||||
if (m_Header.version >= 7)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
}
|
||||
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
|
||||
MemoryStream blocksInfoUncompresseddStream;
|
||||
switch (m_Header.flags & 0x3F) //kArchiveCompressionTypeMask
|
||||
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
||||
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
||||
switch (compressionType)
|
||||
{
|
||||
default: //None
|
||||
case CompressionType.None:
|
||||
{
|
||||
blocksInfoUncompresseddStream = blocksInfoCompressedStream;
|
||||
blocksInfoUncompresseddStream = new MemoryStream(blocksInfoBytes);
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
case CompressionType.Lzma:
|
||||
{
|
||||
blocksInfoUncompresseddStream = SevenZipHelper.StreamDecompress(blocksInfoCompressedStream);
|
||||
blocksInfoCompressedStream.Close();
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
{
|
||||
var uncompressedBytes = new byte[m_Header.uncompressedBlocksInfoSize];
|
||||
using (var decoder = new Lz4DecoderStream(blocksInfoCompressedStream))
|
||||
blocksInfoUncompresseddStream = new MemoryStream((int)(uncompressedSize));
|
||||
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
|
||||
{
|
||||
decoder.Read(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||
}
|
||||
blocksInfoUncompresseddStream.Position = 0;
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lz4:
|
||||
case CompressionType.Lz4HC:
|
||||
{
|
||||
var uncompressedBytes = new byte[uncompressedSize];
|
||||
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
}
|
||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IOException($"Unsupported compression type {compressionType}");
|
||||
}
|
||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
|
||||
{
|
||||
@@ -253,7 +336,7 @@ namespace AssetStudio
|
||||
{
|
||||
uncompressedSize = blocksInfoReader.ReadUInt32(),
|
||||
compressedSize = blocksInfoReader.ReadUInt32(),
|
||||
flags = blocksInfoReader.ReadUInt16()
|
||||
flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -270,34 +353,49 @@ namespace AssetStudio
|
||||
};
|
||||
}
|
||||
}
|
||||
if ((m_Header.flags & ArchiveFlags.BlockInfoNeedPaddingAtStart) != 0)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
switch (blockInfo.flags & 0x3F) //kStorageBlockCompressionTypeMask
|
||||
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
|
||||
switch (compressionType)
|
||||
{
|
||||
default: //None
|
||||
case CompressionType.None:
|
||||
{
|
||||
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
case CompressionType.Lzma:
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
case CompressionType.Lz4:
|
||||
case CompressionType.Lz4HC:
|
||||
{
|
||||
var compressedStream = new MemoryStream(reader.ReadBytes((int)blockInfo.compressedSize));
|
||||
using (var lz4Stream = new Lz4DecoderStream(compressedStream))
|
||||
var compressedSize = (int)blockInfo.compressedSize;
|
||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
||||
reader.Read(compressedBytes, 0, compressedSize);
|
||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
lz4Stream.CopyTo(blocksStream, blockInfo.uncompressedSize);
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
}
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IOException($"Unsupported compression type {compressionType}");
|
||||
}
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace AssetStudio
|
||||
// official Class ID Reference: https://docs.unity3d.com/Manual/ClassIDReference.html
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum ClassIDType
|
||||
{
|
||||
@@ -26,7 +27,7 @@
|
||||
ParticleRenderer = 26,
|
||||
Texture = 27,
|
||||
Texture2D = 28,
|
||||
SceneSettings = 29,
|
||||
OcclusionCullingSettings = 29,
|
||||
GraphicsSettings = 30,
|
||||
MeshFilter = 33,
|
||||
OcclusionPortal = 41,
|
||||
@@ -49,7 +50,7 @@
|
||||
PhysicsMaterial2D = 62,
|
||||
MeshCollider = 64,
|
||||
BoxCollider = 65,
|
||||
SpriteCollider2D = 66,
|
||||
CompositeCollider2D = 66,
|
||||
EdgeCollider2D = 68,
|
||||
CapsuleCollider2D = 70,
|
||||
ComputeShader = 72,
|
||||
@@ -92,6 +93,7 @@
|
||||
FlareLayer = 124,
|
||||
HaloLayer = 125,
|
||||
NavMeshAreas = 126,
|
||||
NavMeshProjectSettings = 126,
|
||||
HaloManager = 127,
|
||||
Font = 128,
|
||||
PlayerSettings = 129,
|
||||
@@ -158,7 +160,7 @@
|
||||
BlendTree = 206,
|
||||
Motion = 207,
|
||||
NavMeshObstacle = 208,
|
||||
TerrainInstance = 210,
|
||||
SortingGroup = 210,
|
||||
SpriteRenderer = 212,
|
||||
Sprite = 213,
|
||||
CachedSpriteAtlas = 214,
|
||||
@@ -216,15 +218,19 @@
|
||||
PerformanceReportingManager = 305,
|
||||
UnityConnectSettings = 310,
|
||||
AvatarMask = 319,
|
||||
PlayableDirector = 320,
|
||||
VideoPlayer = 328,
|
||||
VideoClip = 329,
|
||||
ParticleSystemForceField = 330,
|
||||
SpriteMask = 331,
|
||||
WorldAnchor = 362,
|
||||
OcclusionCullingData = 363,
|
||||
//kLargestRuntimeClassID = 364
|
||||
SmallestEditorClassID = 1000,
|
||||
Prefab = 1001,
|
||||
PrefabInstance = 1001,
|
||||
EditorExtensionImpl = 1002,
|
||||
AssetImporter = 1003,
|
||||
AssetDatabase = 1004,
|
||||
AssetDatabaseV1 = 1004,
|
||||
Mesh3DSImporter = 1005,
|
||||
TextureImporter = 1006,
|
||||
ShaderImporter = 1007,
|
||||
@@ -259,13 +265,13 @@
|
||||
AnimatorState = 1102,
|
||||
HumanTemplate = 1105,
|
||||
AnimatorStateMachine = 1107,
|
||||
PreviewAssetType = 1108,
|
||||
PreviewAnimationClip = 1108,
|
||||
AnimatorTransition = 1109,
|
||||
SpeedTreeImporter = 1110,
|
||||
AnimatorTransitionBase = 1111,
|
||||
SubstanceImporter = 1112,
|
||||
LightmapParameters = 1113,
|
||||
LightmapSnapshot = 1120,
|
||||
LightingDataAsset = 1120,
|
||||
GISRaster = 1121,
|
||||
GISRasterImporter = 1122,
|
||||
CadImporter = 1123,
|
||||
@@ -276,11 +282,98 @@
|
||||
ActivationLogComponent = 2000,
|
||||
//kLargestEditorClassID = 2001
|
||||
//kClassIdOutOfHierarchy = 100000
|
||||
SubDerived = 367388927,
|
||||
//int = 100000,
|
||||
//bool = 100001,
|
||||
//float = 100002,
|
||||
MonoObject = 100003,
|
||||
Collision = 100004,
|
||||
Vector3f = 100005,
|
||||
RootMotionData = 100006,
|
||||
Collision2D = 100007,
|
||||
AudioMixerLiveUpdateFloat = 100008,
|
||||
AudioMixerLiveUpdateBool = 100009,
|
||||
Polygon2D = 100010,
|
||||
//void = 100011,
|
||||
TilemapCollider2D = 19719996,
|
||||
AssetImporterLog = 41386430,
|
||||
VFXRenderer = 73398921,
|
||||
SerializableManagedRefTestClass = 76251197,
|
||||
Grid = 156049354,
|
||||
ScenesUsingAssets = 156483287,
|
||||
ArticulationBody = 171741748,
|
||||
Preset = 181963792,
|
||||
EmptyObject = 277625683,
|
||||
IConstraint = 285090594,
|
||||
TestObjectWithSpecialLayoutOne = 293259124,
|
||||
AssemblyDefinitionReferenceImporter = 294290339,
|
||||
SiblingDerived = 334799969,
|
||||
TestObjectWithSerializedMapStringNonAlignedStruct = 342846651,
|
||||
SubDerived = 367388927,
|
||||
AssetImportInProgressProxy = 369655926,
|
||||
PluginBuildInfo = 382020655,
|
||||
EditorProjectAccess = 426301858,
|
||||
PrefabImporter = 468431735,
|
||||
TestObjectWithSerializedArray = 478637458,
|
||||
TestObjectWithSerializedAnimationCurve = 478637459,
|
||||
TilemapRenderer = 483693784,
|
||||
ScriptableCamera = 488575907,
|
||||
SpriteAtlasAsset = 612988286,
|
||||
SpriteAtlasDatabase = 638013454,
|
||||
AudioBuildInfo = 641289076,
|
||||
CachedSpriteAtlasRuntimeData = 644342135,
|
||||
RendererFake = 646504946,
|
||||
AssemblyDefinitionReferenceAsset = 662584278,
|
||||
BuiltAssetBundleInfoSet = 668709126,
|
||||
SpriteAtlas = 687078895,
|
||||
RayTracingShaderImporter = 747330370,
|
||||
RayTracingShader = 825902497,
|
||||
LightingSettings = 850595691,
|
||||
PlatformModuleSetup = 877146078,
|
||||
VersionControlSettings = 890905787,
|
||||
AimConstraint = 895512359,
|
||||
VFXManager = 937362698,
|
||||
VisualEffectSubgraph = 994735392,
|
||||
VisualEffectSubgraphOperator = 994735403,
|
||||
VisualEffectSubgraphBlock = 994735404,
|
||||
LocalizationImporter = 1027052791,
|
||||
Derived = 1091556383,
|
||||
PropertyModificationsTargetTestObject = 1111377672,
|
||||
ReferencesArtifactGenerator = 1114811875,
|
||||
AssemblyDefinitionAsset = 1152215463,
|
||||
SceneVisibilityState = 1154873562,
|
||||
LookAtConstraint = 1183024399,
|
||||
SpriteAtlasImporter = 1210832254,
|
||||
MultiArtifactTestImporter = 1223240404,
|
||||
GameObjectRecorder = 1268269756,
|
||||
LightingDataAssetParent = 1325145578,
|
||||
PresetManager = 1386491679,
|
||||
TestObjectWithSpecialLayoutTwo = 1392443030,
|
||||
StreamingManager = 1403656975,
|
||||
LowerResBlitTexture = 1480428607,
|
||||
RenderPassAttachment = 1571458007
|
||||
StreamingController = 1542919678,
|
||||
RenderPassAttachment = 1571458007,
|
||||
TestObjectVectorPairStringBool = 1628831178,
|
||||
GridLayout = 1742807556,
|
||||
AssemblyDefinitionImporter = 1766753193,
|
||||
ParentConstraint = 1773428102,
|
||||
FakeComponent = 1803986026,
|
||||
PositionConstraint = 1818360608,
|
||||
RotationConstraint = 1818360609,
|
||||
ScaleConstraint = 1818360610,
|
||||
Tilemap = 1839735485,
|
||||
PackageManifest = 1896753125,
|
||||
PackageManifestImporter = 1896753126,
|
||||
TerrainLayer = 1953259897,
|
||||
SpriteShapeRenderer = 1971053207,
|
||||
NativeObjectType = 1977754360,
|
||||
TestObjectWithSerializedMapStringBool = 1981279845,
|
||||
SerializableManagedHost = 1995898324,
|
||||
VisualEffectAsset = 2058629509,
|
||||
VisualEffectImporter = 2058629510,
|
||||
VisualEffectResource = 2058629511,
|
||||
VisualEffectObject = 2059678085,
|
||||
VisualEffect = 2083052967,
|
||||
LocalizationAsset = 2083778819,
|
||||
ScriptedImporter = 2089858483
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,6 +637,50 @@ namespace AssetStudio
|
||||
m_Binding = new ValueArrayConstant(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public AnimationClipBindingConstant ConvertValueArrayToGenericBinding()
|
||||
{
|
||||
var bindings = new AnimationClipBindingConstant();
|
||||
var genericBindings = new List<GenericBinding>();
|
||||
var values = m_Binding;
|
||||
for (int i = 0; i < values.m_ValueArray.Length;)
|
||||
{
|
||||
var curveID = values.m_ValueArray[i].m_ID;
|
||||
var curveTypeID = values.m_ValueArray[i].m_TypeID;
|
||||
var binding = new GenericBinding();
|
||||
genericBindings.Add(binding);
|
||||
if (curveTypeID == 4174552735) //CRC(PositionX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 1; //kBindTransformPosition
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 3;
|
||||
}
|
||||
else if (curveTypeID == 2211994246) //CRC(QuaternionX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 2; //kBindTransformRotation
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 4;
|
||||
}
|
||||
else if (curveTypeID == 1512518241) //CRC(ScaleX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 3; //kBindTransformScale
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.typeID = ClassIDType.Animator;
|
||||
binding.path = 0;
|
||||
binding.attribute = curveID;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
bindings.genericBindings = genericBindings.ToArray();
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
|
||||
public class ValueDelta
|
||||
@@ -753,6 +797,9 @@ namespace AssetStudio
|
||||
public ClassIDType typeID;
|
||||
public byte customType;
|
||||
public byte isPPtrCurve;
|
||||
public byte isIntCurve;
|
||||
|
||||
public GenericBinding() { }
|
||||
|
||||
public GenericBinding(ObjectReader reader)
|
||||
{
|
||||
@@ -770,6 +817,10 @@ namespace AssetStudio
|
||||
}
|
||||
customType = reader.ReadByte();
|
||||
isPPtrCurve = reader.ReadByte();
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
|
||||
{
|
||||
isIntCurve = reader.ReadByte();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
@@ -779,6 +830,8 @@ namespace AssetStudio
|
||||
public GenericBinding[] genericBindings;
|
||||
public PPtr<Object>[] pptrCurveMapping;
|
||||
|
||||
public AnimationClipBindingConstant() { }
|
||||
|
||||
public AnimationClipBindingConstant(ObjectReader reader)
|
||||
{
|
||||
int numBindings = reader.ReadInt32();
|
||||
@@ -861,9 +914,9 @@ namespace AssetStudio
|
||||
|
||||
public enum AnimationType
|
||||
{
|
||||
kLegacy = 1,
|
||||
kGeneric = 2,
|
||||
kHumanoid = 3
|
||||
Legacy = 1,
|
||||
Generic = 2,
|
||||
Humanoid = 3
|
||||
};
|
||||
|
||||
public sealed class AnimationClip : NamedObject
|
||||
@@ -897,7 +950,7 @@ namespace AssetStudio
|
||||
else if (version[0] >= 4)//4.0 and up
|
||||
{
|
||||
m_AnimationType = (AnimationType)reader.ReadInt32();
|
||||
if (m_AnimationType == AnimationType.kLegacy)
|
||||
if (m_AnimationType == AnimationType.Legacy)
|
||||
m_Legacy = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -31,6 +31,10 @@ namespace AssetStudio
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_LinearVelocityBlending = reader.ReadBoolean();
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
var m_StabilizeFeet = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace AssetStudio
|
||||
public sealed class AudioClip : NamedObject
|
||||
{
|
||||
public int m_Format;
|
||||
public AudioType m_Type;
|
||||
public FMODSoundType m_Type;
|
||||
public bool m_3D;
|
||||
public bool m_UseHardware;
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace AssetStudio
|
||||
public AudioCompressionFormat m_CompressionFormat;
|
||||
|
||||
public string m_Source;
|
||||
public long m_Offset;
|
||||
public long m_Size;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
public ResourceReader m_AudioData;
|
||||
|
||||
public AudioClip(ObjectReader reader) : base(reader)
|
||||
@@ -36,7 +36,7 @@ namespace AssetStudio
|
||||
if (version[0] < 5)
|
||||
{
|
||||
m_Format = reader.ReadInt32();
|
||||
m_Type = (AudioType)reader.ReadInt32();
|
||||
m_Type = (FMODSoundType)reader.ReadInt32();
|
||||
m_3D = reader.ReadBoolean();
|
||||
m_UseHardware = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
@@ -48,7 +48,7 @@ namespace AssetStudio
|
||||
var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size;
|
||||
if (reader.byteSize + reader.byteStart - reader.Position != tsize)
|
||||
{
|
||||
m_Offset = reader.ReadInt32();
|
||||
m_Offset = reader.ReadUInt32();
|
||||
m_Source = assetsFile.fullName + ".resS";
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ namespace AssetStudio
|
||||
m_Legacy3D = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
//StreamedResource m_Resource
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
@@ -81,44 +82,61 @@ namespace AssetStudio
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, (int)m_Size);
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_Size);
|
||||
}
|
||||
m_AudioData = resourceReader;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AudioType
|
||||
public enum FMODSoundType
|
||||
{
|
||||
UNKNOWN,
|
||||
ACC,
|
||||
AIFF,
|
||||
UNKNOWN = 0,
|
||||
ACC = 1,
|
||||
AIFF = 2,
|
||||
ASF = 3,
|
||||
AT3 = 4,
|
||||
CDDA = 5,
|
||||
DLS = 6,
|
||||
FLAC = 7,
|
||||
FSB = 8,
|
||||
GCADPCM = 9,
|
||||
IT = 10,
|
||||
MIDI = 11,
|
||||
MOD = 12,
|
||||
MPEG,
|
||||
OGGVORBIS,
|
||||
MPEG = 13,
|
||||
OGGVORBIS = 14,
|
||||
PLAYLIST = 15,
|
||||
RAW = 16,
|
||||
S3M = 17,
|
||||
SF2 = 18,
|
||||
USER = 19,
|
||||
WAV = 20,
|
||||
XM,
|
||||
XMA,
|
||||
VAG,
|
||||
AUDIOQUEUE
|
||||
XM = 21,
|
||||
XMA = 22,
|
||||
VAG = 23,
|
||||
AUDIOQUEUE = 24,
|
||||
XWMA = 25,
|
||||
BCWAV = 26,
|
||||
AT9 = 27,
|
||||
VORBIS = 28,
|
||||
MEDIA_FOUNDATION = 29
|
||||
}
|
||||
|
||||
public enum AudioCompressionFormat
|
||||
{
|
||||
PCM,
|
||||
Vorbis,
|
||||
ADPCM,
|
||||
MP3,
|
||||
VAG,
|
||||
HEVAG,
|
||||
XMA,
|
||||
AAC,
|
||||
GCADPCM,
|
||||
ATRAC9
|
||||
PCM = 0,
|
||||
Vorbis = 1,
|
||||
ADPCM = 2,
|
||||
MP3 = 3,
|
||||
PSMVAG = 4,
|
||||
HEVAG = 5,
|
||||
XMA = 6,
|
||||
AAC = 7,
|
||||
GCADPCM = 8,
|
||||
ATRAC9 = 9
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@ namespace AssetStudio
|
||||
public class UnityPropertySheet
|
||||
{
|
||||
public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs;
|
||||
public KeyValuePair<string, int>[] m_Ints;
|
||||
public KeyValuePair<string, float>[] m_Floats;
|
||||
public KeyValuePair<string, Color>[] m_Colors;
|
||||
|
||||
public UnityPropertySheet(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int m_TexEnvsSize = reader.ReadInt32();
|
||||
m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize];
|
||||
for (int i = 0; i < m_TexEnvsSize; i++)
|
||||
@@ -31,6 +34,16 @@ namespace AssetStudio
|
||||
m_TexEnvs[i] = new KeyValuePair<string, UnityTexEnv>(reader.ReadAlignedString(), new UnityTexEnv(reader));
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_IntsSize = reader.ReadInt32();
|
||||
m_Ints = new KeyValuePair<string, int>[m_IntsSize];
|
||||
for (int i = 0; i < m_IntsSize; i++)
|
||||
{
|
||||
m_Ints[i] = new KeyValuePair<string, int>(reader.ReadAlignedString(), reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
int m_FloatsSize = reader.ReadInt32();
|
||||
m_Floats = new KeyValuePair<string, float>[m_FloatsSize];
|
||||
for (int i = 0; i < m_FloatsSize; i++)
|
||||
@@ -61,9 +74,18 @@ namespace AssetStudio
|
||||
var m_ShaderKeywords = reader.ReadStringArray();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 3)) //2021.3 and up
|
||||
{
|
||||
var m_ValidKeywords = reader.ReadStringArray();
|
||||
var m_InvalidKeywords = reader.ReadStringArray();
|
||||
}
|
||||
else if (version[0] >= 5) //5.0 ~ 2021.2
|
||||
{
|
||||
var m_ShaderKeywords = reader.ReadAlignedString();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_LightmapFlags = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
@@ -95,6 +117,8 @@ namespace AssetStudio
|
||||
}
|
||||
|
||||
m_SavedProperties = new UnityPropertySheet(reader);
|
||||
|
||||
//vector m_BuildTextureStacks 2020 and up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace AssetStudio
|
||||
GetStreams(version);
|
||||
}
|
||||
|
||||
m_DataSize = reader.ReadBytes(reader.ReadInt32());
|
||||
m_DataSize = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace AssetStudio
|
||||
if (m_Channel.dimension > 0)
|
||||
{
|
||||
chnMask |= 1u << chn;
|
||||
stride += m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format);
|
||||
stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,7 +253,7 @@ namespace AssetStudio
|
||||
m_Channel.dimension = 4;
|
||||
break;
|
||||
}
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format));
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,14 +396,14 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public enum GfxPrimitiveType : int
|
||||
public enum GfxPrimitiveType
|
||||
{
|
||||
kPrimitiveTriangles = 0,
|
||||
kPrimitiveTriangleStrip = 1,
|
||||
kPrimitiveQuads = 2,
|
||||
kPrimitiveLines = 3,
|
||||
kPrimitiveLineStrip = 4,
|
||||
kPrimitivePoints = 5,
|
||||
Triangles = 0,
|
||||
TriangleStrip = 1,
|
||||
Quads = 2,
|
||||
Lines = 3,
|
||||
LineStrip = 4,
|
||||
Points = 5
|
||||
};
|
||||
|
||||
public class SubMesh
|
||||
@@ -446,7 +446,7 @@ namespace AssetStudio
|
||||
|
||||
public sealed class Mesh : NamedObject
|
||||
{
|
||||
private bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices;
|
||||
private bool m_Use16BitIndices = true;
|
||||
public SubMesh[] m_SubMeshes;
|
||||
private uint[] m_IndexBuffer;
|
||||
public BlendShapeData m_Shapes;
|
||||
@@ -550,6 +550,7 @@ namespace AssetStudio
|
||||
((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression
|
||||
{
|
||||
var m_IndexFormat = reader.ReadInt32();
|
||||
m_Use16BitIndices = m_IndexFormat == 0;
|
||||
}
|
||||
|
||||
int m_IndexBuffer_size = reader.ReadInt32();
|
||||
@@ -650,11 +651,16 @@ namespace AssetStudio
|
||||
|
||||
int m_MeshUsageFlags = reader.ReadInt32();
|
||||
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
|
||||
{
|
||||
int m_CookingOptions = reader.ReadInt32();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_BakedConvexCollisionMesh = reader.ReadBytes(reader.ReadInt32());
|
||||
var m_BakedConvexCollisionMesh = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
var m_BakedTriangleCollisionMesh = reader.ReadBytes(reader.ReadInt32());
|
||||
var m_BakedTriangleCollisionMesh = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
@@ -680,7 +686,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (m_VertexData.m_VertexCount > 0)
|
||||
{
|
||||
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, (int)m_StreamData.size);
|
||||
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||
m_VertexData.m_DataSize = resourceReader.GetData();
|
||||
}
|
||||
}
|
||||
@@ -710,12 +716,13 @@ namespace AssetStudio
|
||||
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
|
||||
if (channelMask.Get(chn))
|
||||
{
|
||||
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2)
|
||||
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
|
||||
{
|
||||
m_Channel.dimension = 4;
|
||||
}
|
||||
|
||||
var componentByteSize = (int)MeshHelper.GetFormatSize(version, m_Channel.format);
|
||||
var vertexFormat = MeshHelper.ToVertexFormat(m_Channel.format, version);
|
||||
var componentByteSize = (int)MeshHelper.GetFormatSize(vertexFormat);
|
||||
var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
|
||||
for (int v = 0; v < m_VertexCount; v++)
|
||||
{
|
||||
@@ -727,7 +734,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.endian == EndianType.BigEndian && componentByteSize > 1) //swap bytes
|
||||
if (reader.Endian == EndianType.BigEndian && componentByteSize > 1) //swap bytes
|
||||
{
|
||||
for (var i = 0; i < componentBytes.Length / componentByteSize; i++)
|
||||
{
|
||||
@@ -740,10 +747,10 @@ namespace AssetStudio
|
||||
|
||||
int[] componentsIntArray = null;
|
||||
float[] componentsFloatArray = null;
|
||||
if (MeshHelper.IsIntFormat(version, m_Channel.format))
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, componentByteSize);
|
||||
if (MeshHelper.IsIntFormat(vertexFormat))
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
|
||||
else
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
|
||||
|
||||
if (version[0] >= 2018)
|
||||
{
|
||||
@@ -1058,7 +1065,7 @@ namespace AssetStudio
|
||||
}
|
||||
var indexCount = m_SubMesh.indexCount;
|
||||
var topology = m_SubMesh.topology;
|
||||
if (topology == GfxPrimitiveType.kPrimitiveTriangles)
|
||||
if (topology == GfxPrimitiveType.Triangles)
|
||||
{
|
||||
for (int i = 0; i < indexCount; i += 3)
|
||||
{
|
||||
@@ -1067,7 +1074,7 @@ namespace AssetStudio
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i + 2]);
|
||||
}
|
||||
}
|
||||
else if (version[0] < 4 || topology == GfxPrimitiveType.kPrimitiveTriangleStrip)
|
||||
else if (version[0] < 4 || topology == GfxPrimitiveType.TriangleStrip)
|
||||
{
|
||||
// de-stripify :
|
||||
uint triIndex = 0;
|
||||
@@ -1098,7 +1105,7 @@ namespace AssetStudio
|
||||
//fix indexCount
|
||||
m_SubMesh.indexCount = triIndex;
|
||||
}
|
||||
else if (topology == GfxPrimitiveType.kPrimitiveQuads)
|
||||
else if (topology == GfxPrimitiveType.Quads)
|
||||
{
|
||||
for (int q = 0; q < indexCount; q += 4)
|
||||
{
|
||||
@@ -1189,189 +1196,188 @@ namespace AssetStudio
|
||||
|
||||
public static class MeshHelper
|
||||
{
|
||||
private enum VertexChannelFormat
|
||||
public enum VertexChannelFormat
|
||||
{
|
||||
kChannelFormatFloat,
|
||||
kChannelFormatFloat16,
|
||||
kChannelFormatColor,
|
||||
kChannelFormatByte,
|
||||
kChannelFormatUInt32
|
||||
Float,
|
||||
Float16,
|
||||
Color,
|
||||
Byte,
|
||||
UInt32
|
||||
}
|
||||
|
||||
private enum VertexFormat
|
||||
public enum VertexFormat2017
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
kVertexFormatColor,
|
||||
kVertexFormatUNorm8,
|
||||
kVertexFormatSNorm8,
|
||||
kVertexFormatUNorm16,
|
||||
kVertexFormatSNorm16,
|
||||
kVertexFormatUInt8,
|
||||
kVertexFormatSInt8,
|
||||
kVertexFormatUInt16,
|
||||
kVertexFormatSInt16,
|
||||
kVertexFormatUInt32,
|
||||
kVertexFormatSInt32
|
||||
Float,
|
||||
Float16,
|
||||
Color,
|
||||
UNorm8,
|
||||
SNorm8,
|
||||
UNorm16,
|
||||
SNorm16,
|
||||
UInt8,
|
||||
SInt8,
|
||||
UInt16,
|
||||
SInt16,
|
||||
UInt32,
|
||||
SInt32
|
||||
}
|
||||
|
||||
private enum VertexFormatV2019
|
||||
public enum VertexFormat
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
kVertexFormatUNorm8,
|
||||
kVertexFormatSNorm8,
|
||||
kVertexFormatUNorm16,
|
||||
kVertexFormatSNorm16,
|
||||
kVertexFormatUInt8,
|
||||
kVertexFormatSInt8,
|
||||
kVertexFormatUInt16,
|
||||
kVertexFormatSInt16,
|
||||
kVertexFormatUInt32,
|
||||
kVertexFormatSInt32
|
||||
Float,
|
||||
Float16,
|
||||
UNorm8,
|
||||
SNorm8,
|
||||
UNorm16,
|
||||
SNorm16,
|
||||
UInt8,
|
||||
SInt8,
|
||||
UInt16,
|
||||
SInt16,
|
||||
UInt32,
|
||||
SInt32
|
||||
}
|
||||
|
||||
public static uint GetFormatSize(int[] version, int format)
|
||||
public static VertexFormat ToVertexFormat(int format, int[] version)
|
||||
{
|
||||
if (version[0] < 2017)
|
||||
{
|
||||
switch ((VertexChannelFormat)format)
|
||||
{
|
||||
case VertexChannelFormat.kChannelFormatFloat:
|
||||
return 4u;
|
||||
case VertexChannelFormat.kChannelFormatFloat16:
|
||||
return 2u;
|
||||
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
|
||||
return 1u;
|
||||
case VertexChannelFormat.kChannelFormatByte:
|
||||
return 1u;
|
||||
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
|
||||
return 4u;
|
||||
case VertexChannelFormat.Float:
|
||||
return VertexFormat.Float;
|
||||
case VertexChannelFormat.Float16:
|
||||
return VertexFormat.Float16;
|
||||
case VertexChannelFormat.Color: //in 4.x is size 4
|
||||
return VertexFormat.UNorm8;
|
||||
case VertexChannelFormat.Byte:
|
||||
return VertexFormat.UInt8;
|
||||
case VertexChannelFormat.UInt32: //in 5.x
|
||||
return VertexFormat.UInt32;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else if (version[0] < 2019)
|
||||
{
|
||||
switch ((VertexFormat)format)
|
||||
switch ((VertexFormat2017)format)
|
||||
{
|
||||
case VertexFormat.kVertexFormatFloat:
|
||||
return 4u;
|
||||
case VertexFormat.kVertexFormatFloat16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatColor:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatUNorm8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatSNorm8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatUNorm16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatSNorm16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatUInt8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatSInt8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatUInt16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatSInt16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatUInt32:
|
||||
return 4u;
|
||||
case VertexFormat.kVertexFormatSInt32:
|
||||
return 4u;
|
||||
case VertexFormat2017.Float:
|
||||
return VertexFormat.Float;
|
||||
case VertexFormat2017.Float16:
|
||||
return VertexFormat.Float16;
|
||||
case VertexFormat2017.Color:
|
||||
case VertexFormat2017.UNorm8:
|
||||
return VertexFormat.UNorm8;
|
||||
case VertexFormat2017.SNorm8:
|
||||
return VertexFormat.SNorm8;
|
||||
case VertexFormat2017.UNorm16:
|
||||
return VertexFormat.UNorm16;
|
||||
case VertexFormat2017.SNorm16:
|
||||
return VertexFormat.SNorm16;
|
||||
case VertexFormat2017.UInt8:
|
||||
return VertexFormat.UInt8;
|
||||
case VertexFormat2017.SInt8:
|
||||
return VertexFormat.SInt8;
|
||||
case VertexFormat2017.UInt16:
|
||||
return VertexFormat.UInt16;
|
||||
case VertexFormat2017.SInt16:
|
||||
return VertexFormat.SInt16;
|
||||
case VertexFormat2017.UInt32:
|
||||
return VertexFormat.UInt32;
|
||||
case VertexFormat2017.SInt32:
|
||||
return VertexFormat.SInt32;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((VertexFormatV2019)format)
|
||||
{
|
||||
case VertexFormatV2019.kVertexFormatFloat:
|
||||
return 4u;
|
||||
case VertexFormatV2019.kVertexFormatFloat16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUNorm8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatSNorm8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatUNorm16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatSNorm16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUInt8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatSInt8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatUInt16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatSInt16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUInt32:
|
||||
return 4u;
|
||||
case VertexFormatV2019.kVertexFormatSInt32:
|
||||
return 4u;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
return (VertexFormat)format;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsIntFormat(int[] version, int format)
|
||||
|
||||
public static uint GetFormatSize(VertexFormat format)
|
||||
{
|
||||
if (version[0] < 2017)
|
||||
switch (format)
|
||||
{
|
||||
return format == 4;
|
||||
}
|
||||
else if (version[0] < 2019)
|
||||
{
|
||||
return format >= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
return format >= 6;
|
||||
case VertexFormat.Float:
|
||||
case VertexFormat.UInt32:
|
||||
case VertexFormat.SInt32:
|
||||
return 4u;
|
||||
case VertexFormat.Float16:
|
||||
case VertexFormat.UNorm16:
|
||||
case VertexFormat.SNorm16:
|
||||
case VertexFormat.UInt16:
|
||||
case VertexFormat.SInt16:
|
||||
return 2u;
|
||||
case VertexFormat.UNorm8:
|
||||
case VertexFormat.SNorm8:
|
||||
case VertexFormat.UInt8:
|
||||
case VertexFormat.SInt8:
|
||||
return 1u;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] BytesToFloatArray(byte[] inputBytes, int size)
|
||||
public static bool IsIntFormat(VertexFormat format)
|
||||
{
|
||||
var result = new float[inputBytes.Length / size];
|
||||
for (int i = 0; i < inputBytes.Length / size; i++)
|
||||
return format >= VertexFormat.UInt8;
|
||||
}
|
||||
|
||||
public static float[] BytesToFloatArray(byte[] inputBytes, VertexFormat format)
|
||||
{
|
||||
var size = GetFormatSize(format);
|
||||
var len = inputBytes.Length / size;
|
||||
var result = new float[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var value = 0f;
|
||||
switch (size)
|
||||
switch (format)
|
||||
{
|
||||
case 1:
|
||||
value = inputBytes[i] / 255.0f;
|
||||
case VertexFormat.Float:
|
||||
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
break;
|
||||
case 2:
|
||||
value = Half.ToHalf(inputBytes, i * 2);
|
||||
case VertexFormat.Float16:
|
||||
result[i] = Half.ToHalf(inputBytes, i * 2);
|
||||
break;
|
||||
case 4:
|
||||
value = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
case VertexFormat.UNorm8:
|
||||
result[i] = inputBytes[i] / 255f;
|
||||
break;
|
||||
case VertexFormat.SNorm8:
|
||||
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
|
||||
break;
|
||||
case VertexFormat.UNorm16:
|
||||
result[i] = BitConverter.ToUInt16(inputBytes, i * 2) / 65535f;
|
||||
break;
|
||||
case VertexFormat.SNorm16:
|
||||
result[i] = Math.Max(BitConverter.ToInt16(inputBytes, i * 2) / 32767f, -1f);
|
||||
break;
|
||||
}
|
||||
result[i] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] BytesToIntArray(byte[] inputBytes, int size)
|
||||
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
|
||||
{
|
||||
var result = new int[inputBytes.Length / size];
|
||||
for (int i = 0; i < inputBytes.Length / size; i++)
|
||||
var size = GetFormatSize(format);
|
||||
var len = inputBytes.Length / size;
|
||||
var result = new int[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
switch (size)
|
||||
switch (format)
|
||||
{
|
||||
case 1:
|
||||
case VertexFormat.UInt8:
|
||||
case VertexFormat.SInt8:
|
||||
result[i] = inputBytes[i];
|
||||
break;
|
||||
case 2:
|
||||
case VertexFormat.UInt16:
|
||||
case VertexFormat.SInt16:
|
||||
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
|
||||
break;
|
||||
case 4:
|
||||
case VertexFormat.UInt32:
|
||||
case VertexFormat.SInt32:
|
||||
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace AssetStudio
|
||||
public sealed class MonoScript : NamedObject
|
||||
{
|
||||
public string m_ClassName;
|
||||
public string m_Namespace = string.Empty;
|
||||
public string m_Namespace;
|
||||
public string m_AssemblyName;
|
||||
|
||||
public MonoScript(ObjectReader reader) : base(reader)
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AssetStudio
|
||||
var m_Loop = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_AudioClip = new PPtr<AudioClip>(reader);
|
||||
m_MovieData = reader.ReadBytes(reader.ReadInt32());
|
||||
m_MovieData = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
@@ -36,19 +33,38 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasStructMember(string name)
|
||||
{
|
||||
return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name);
|
||||
}
|
||||
|
||||
public string Dump()
|
||||
{
|
||||
reader.Reset();
|
||||
if (serializedType?.m_Nodes != null)
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader);
|
||||
return sb.ToString();
|
||||
return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Dump(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadTypeString(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType()
|
||||
{
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace AssetStudio
|
||||
public PPtr(ObjectReader reader)
|
||||
{
|
||||
m_FileID = reader.ReadInt32();
|
||||
m_PathID = reader.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
m_PathID = reader.m_Version < SerializedFileFormatVersion.Unknown_14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
assetsFile = reader.assetsFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_DynamicOccludee = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_StaticShadowCaster = reader.ReadByte();
|
||||
}
|
||||
var m_MotionVectors = reader.ReadByte();
|
||||
var m_LightProbeUsage = reader.ReadByte();
|
||||
var m_ReflectionProbeUsage = reader.ReadByte();
|
||||
@@ -50,6 +54,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_RayTracingMode = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_RayTraceProcedural = reader.ReadByte();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
|
||||
19
AssetStudio/Classes/ResourceManager.cs
Normal file
19
AssetStudio/Classes/ResourceManager.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class ResourceManager : Object
|
||||
{
|
||||
public KeyValuePair<string, PPtr<Object>>[] m_Container;
|
||||
|
||||
public ResourceManager(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, PPtr<Object>>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, PPtr<Object>>(reader.ReadAlignedString(), new PPtr<Object>(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,16 @@ using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Hash128
|
||||
{
|
||||
public byte[] bytes;
|
||||
|
||||
public Hash128(BinaryReader reader)
|
||||
{
|
||||
bytes = reader.ReadBytes(16);
|
||||
}
|
||||
}
|
||||
|
||||
public class StructParameter
|
||||
{
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
@@ -46,15 +56,14 @@ namespace AssetStudio
|
||||
}
|
||||
public enum TextureDimension
|
||||
{
|
||||
kTexDimUnknown = -1,
|
||||
kTexDimNone = 0,
|
||||
kTexDimAny = 1,
|
||||
kTexDim2D = 2,
|
||||
kTexDim3D = 3,
|
||||
kTexDimCUBE = 4,
|
||||
kTexDim2DArray = 5,
|
||||
kTexDimCubeArray = 6,
|
||||
kTexDimForce32Bit = 2147483647
|
||||
Unknown = -1,
|
||||
None = 0,
|
||||
Any = 1,
|
||||
Tex2D = 2,
|
||||
Tex3D = 3,
|
||||
Cube = 4,
|
||||
Tex2DArray = 5,
|
||||
CubeArray = 6
|
||||
};
|
||||
|
||||
public class SerializedTextureProperty
|
||||
@@ -71,11 +80,12 @@ namespace AssetStudio
|
||||
|
||||
public enum SerializedPropertyType
|
||||
{
|
||||
kColor = 0,
|
||||
kVector = 1,
|
||||
kFloat = 2,
|
||||
kRange = 3,
|
||||
kTexture = 4
|
||||
Color = 0,
|
||||
Vector = 1,
|
||||
Float = 2,
|
||||
Range = 3,
|
||||
Texture = 4,
|
||||
Int = 5
|
||||
};
|
||||
|
||||
public class SerializedProperty
|
||||
@@ -185,11 +195,11 @@ namespace AssetStudio
|
||||
|
||||
public enum FogMode
|
||||
{
|
||||
kFogUnknown = -1,
|
||||
kFogDisabled = 0,
|
||||
kFogLinear = 1,
|
||||
kFogExp = 2,
|
||||
kFogExp2 = 3
|
||||
Unknown = -1,
|
||||
Disabled = 0,
|
||||
Linear = 1,
|
||||
Exp = 2,
|
||||
Exp2 = 3
|
||||
};
|
||||
|
||||
public class SerializedShaderState
|
||||
@@ -201,6 +211,7 @@ namespace AssetStudio
|
||||
public SerializedShaderFloatValue zTest;
|
||||
public SerializedShaderFloatValue zWrite;
|
||||
public SerializedShaderFloatValue culling;
|
||||
public SerializedShaderFloatValue conservative;
|
||||
public SerializedShaderFloatValue offsetFactor;
|
||||
public SerializedShaderFloatValue offsetUnits;
|
||||
public SerializedShaderFloatValue alphaToMask;
|
||||
@@ -239,6 +250,10 @@ namespace AssetStudio
|
||||
zTest = new SerializedShaderFloatValue(reader);
|
||||
zWrite = new SerializedShaderFloatValue(reader);
|
||||
culling = new SerializedShaderFloatValue(reader);
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
conservative = new SerializedShaderFloatValue(reader);
|
||||
}
|
||||
offsetFactor = new SerializedShaderFloatValue(reader);
|
||||
offsetUnits = new SerializedShaderFloatValue(reader);
|
||||
alphaToMask = new SerializedShaderFloatValue(reader);
|
||||
@@ -357,11 +372,18 @@ namespace AssetStudio
|
||||
{
|
||||
public int m_NameIndex;
|
||||
public int m_Index;
|
||||
public int m_ArraySize;
|
||||
|
||||
public BufferBinding(BinaryReader reader)
|
||||
public BufferBinding(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_NameIndex = reader.ReadInt32();
|
||||
m_Index = reader.ReadInt32();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
m_ArraySize = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +394,7 @@ namespace AssetStudio
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public StructParameter[] m_StructParams;
|
||||
public int m_Size;
|
||||
public bool m_IsPartialCB;
|
||||
|
||||
public ConstantBuffer(ObjectReader reader)
|
||||
{
|
||||
@@ -402,6 +425,16 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
m_Size = reader.ReadInt32();
|
||||
|
||||
if ((version[0] == 2020 && version[1] > 3) ||
|
||||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
|
||||
(version[0] > 2021) ||
|
||||
(version[0] == 2021 && version[1] > 1) ||
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 and up
|
||||
{
|
||||
m_IsPartialCB = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,42 +454,43 @@ namespace AssetStudio
|
||||
|
||||
public enum ShaderGpuProgramType
|
||||
{
|
||||
kShaderGpuProgramUnknown = 0,
|
||||
kShaderGpuProgramGLLegacy = 1,
|
||||
kShaderGpuProgramGLES31AEP = 2,
|
||||
kShaderGpuProgramGLES31 = 3,
|
||||
kShaderGpuProgramGLES3 = 4,
|
||||
kShaderGpuProgramGLES = 5,
|
||||
kShaderGpuProgramGLCore32 = 6,
|
||||
kShaderGpuProgramGLCore41 = 7,
|
||||
kShaderGpuProgramGLCore43 = 8,
|
||||
kShaderGpuProgramDX9VertexSM20 = 9,
|
||||
kShaderGpuProgramDX9VertexSM30 = 10,
|
||||
kShaderGpuProgramDX9PixelSM20 = 11,
|
||||
kShaderGpuProgramDX9PixelSM30 = 12,
|
||||
kShaderGpuProgramDX10Level9Vertex = 13,
|
||||
kShaderGpuProgramDX10Level9Pixel = 14,
|
||||
kShaderGpuProgramDX11VertexSM40 = 15,
|
||||
kShaderGpuProgramDX11VertexSM50 = 16,
|
||||
kShaderGpuProgramDX11PixelSM40 = 17,
|
||||
kShaderGpuProgramDX11PixelSM50 = 18,
|
||||
kShaderGpuProgramDX11GeometrySM40 = 19,
|
||||
kShaderGpuProgramDX11GeometrySM50 = 20,
|
||||
kShaderGpuProgramDX11HullSM50 = 21,
|
||||
kShaderGpuProgramDX11DomainSM50 = 22,
|
||||
kShaderGpuProgramMetalVS = 23,
|
||||
kShaderGpuProgramMetalFS = 24,
|
||||
kShaderGpuProgramSPIRV = 25,
|
||||
kShaderGpuProgramConsole = 26
|
||||
Unknown = 0,
|
||||
GLLegacy = 1,
|
||||
GLES31AEP = 2,
|
||||
GLES31 = 3,
|
||||
GLES3 = 4,
|
||||
GLES = 5,
|
||||
GLCore32 = 6,
|
||||
GLCore41 = 7,
|
||||
GLCore43 = 8,
|
||||
DX9VertexSM20 = 9,
|
||||
DX9VertexSM30 = 10,
|
||||
DX9PixelSM20 = 11,
|
||||
DX9PixelSM30 = 12,
|
||||
DX10Level9Vertex = 13,
|
||||
DX10Level9Pixel = 14,
|
||||
DX11VertexSM40 = 15,
|
||||
DX11VertexSM50 = 16,
|
||||
DX11PixelSM40 = 17,
|
||||
DX11PixelSM50 = 18,
|
||||
DX11GeometrySM40 = 19,
|
||||
DX11GeometrySM50 = 20,
|
||||
DX11HullSM50 = 21,
|
||||
DX11DomainSM50 = 22,
|
||||
MetalVS = 23,
|
||||
MetalFS = 24,
|
||||
SPIRV = 25,
|
||||
ConsoleVS = 26,
|
||||
ConsoleFS = 27,
|
||||
ConsoleHS = 28,
|
||||
ConsoleDS = 29,
|
||||
ConsoleGS = 30,
|
||||
RayTracing = 31,
|
||||
PS5NGGC = 32
|
||||
};
|
||||
|
||||
public class SerializedSubProgram
|
||||
public class SerializedProgramParameters
|
||||
{
|
||||
public uint m_BlobIndex;
|
||||
public ParserBindChannels m_Channels;
|
||||
public ushort[] m_KeywordIndices;
|
||||
public sbyte m_ShaderHardwareTier;
|
||||
public ShaderGpuProgramType m_GpuProgramType;
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
public TextureParameter[] m_TextureParams;
|
||||
@@ -466,33 +500,8 @@ namespace AssetStudio
|
||||
public UAVParameter[] m_UAVParams;
|
||||
public SamplerParameter[] m_Samplers;
|
||||
|
||||
public SerializedSubProgram(ObjectReader reader)
|
||||
public SerializedProgramParameters(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_BlobIndex = reader.ReadUInt32();
|
||||
m_Channels = new ParserBindChannels(reader);
|
||||
|
||||
if (version[0] >= 2019) //2019 and up
|
||||
{
|
||||
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_LocalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_KeywordIndices = reader.ReadUInt16Array();
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
m_ShaderHardwareTier = reader.ReadSByte();
|
||||
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
|
||||
reader.AlignStream();
|
||||
|
||||
int numVectorParams = reader.ReadInt32();
|
||||
m_VectorParams = new VectorParameter[numVectorParams];
|
||||
for (int i = 0; i < numVectorParams; i++)
|
||||
@@ -542,18 +551,139 @@ namespace AssetStudio
|
||||
m_UAVParams[i] = new UAVParameter(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
{
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedSubProgram
|
||||
{
|
||||
public uint m_BlobIndex;
|
||||
public ParserBindChannels m_Channels;
|
||||
public ushort[] m_KeywordIndices;
|
||||
public sbyte m_ShaderHardwareTier;
|
||||
public ShaderGpuProgramType m_GpuProgramType;
|
||||
public SerializedProgramParameters m_Parameters;
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
public TextureParameter[] m_TextureParams;
|
||||
public BufferBinding[] m_BufferParams;
|
||||
public ConstantBuffer[] m_ConstantBuffers;
|
||||
public BufferBinding[] m_ConstantBufferBindings;
|
||||
public UAVParameter[] m_UAVParams;
|
||||
public SamplerParameter[] m_Samplers;
|
||||
|
||||
public SerializedSubProgram(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_BlobIndex = reader.ReadUInt32();
|
||||
m_Channels = new ParserBindChannels(reader);
|
||||
|
||||
if ((version[0] >= 2019 && version[0] < 2021) || (version[0] == 2021 && version[1] < 2)) //2019 ~2021.1
|
||||
{
|
||||
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_LocalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_KeywordIndices = reader.ReadUInt16Array();
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
m_ShaderHardwareTier = reader.ReadSByte();
|
||||
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
|
||||
reader.AlignStream();
|
||||
|
||||
if ((version[0] == 2020 && version[1] > 3) ||
|
||||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
|
||||
(version[0] > 2021) ||
|
||||
(version[0] == 2021 && version[1] > 1) ||
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
|
||||
{
|
||||
m_Parameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
int numVectorParams = reader.ReadInt32();
|
||||
m_VectorParams = new VectorParameter[numVectorParams];
|
||||
for (int i = 0; i < numVectorParams; i++)
|
||||
{
|
||||
m_VectorParams[i] = new VectorParameter(reader);
|
||||
}
|
||||
|
||||
int numMatrixParams = reader.ReadInt32();
|
||||
m_MatrixParams = new MatrixParameter[numMatrixParams];
|
||||
for (int i = 0; i < numMatrixParams; i++)
|
||||
{
|
||||
m_MatrixParams[i] = new MatrixParameter(reader);
|
||||
}
|
||||
|
||||
int numTextureParams = reader.ReadInt32();
|
||||
m_TextureParams = new TextureParameter[numTextureParams];
|
||||
for (int i = 0; i < numTextureParams; i++)
|
||||
{
|
||||
m_TextureParams[i] = new TextureParameter(reader);
|
||||
}
|
||||
|
||||
int numBufferParams = reader.ReadInt32();
|
||||
m_BufferParams = new BufferBinding[numBufferParams];
|
||||
for (int i = 0; i < numBufferParams; i++)
|
||||
{
|
||||
m_BufferParams[i] = new BufferBinding(reader);
|
||||
}
|
||||
|
||||
int numConstantBuffers = reader.ReadInt32();
|
||||
m_ConstantBuffers = new ConstantBuffer[numConstantBuffers];
|
||||
for (int i = 0; i < numConstantBuffers; i++)
|
||||
{
|
||||
m_ConstantBuffers[i] = new ConstantBuffer(reader);
|
||||
}
|
||||
|
||||
int numConstantBufferBindings = reader.ReadInt32();
|
||||
m_ConstantBufferBindings = new BufferBinding[numConstantBufferBindings];
|
||||
for (int i = 0; i < numConstantBufferBindings; i++)
|
||||
{
|
||||
m_ConstantBufferBindings[i] = new BufferBinding(reader);
|
||||
}
|
||||
|
||||
int numUAVParams = reader.ReadInt32();
|
||||
m_UAVParams = new UAVParameter[numUAVParams];
|
||||
for (int i = 0; i < numUAVParams; i++)
|
||||
{
|
||||
m_UAVParams[i] = new UAVParameter(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
{
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt32();
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -561,27 +691,50 @@ namespace AssetStudio
|
||||
public class SerializedProgram
|
||||
{
|
||||
public SerializedSubProgram[] m_SubPrograms;
|
||||
public SerializedProgramParameters m_CommonParameters;
|
||||
public ushort[] m_SerializedKeywordStateMask;
|
||||
|
||||
public SerializedProgram(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numSubPrograms = reader.ReadInt32();
|
||||
m_SubPrograms = new SerializedSubProgram[numSubPrograms];
|
||||
for (int i = 0; i < numSubPrograms; i++)
|
||||
{
|
||||
m_SubPrograms[i] = new SerializedSubProgram(reader);
|
||||
}
|
||||
|
||||
if ((version[0] == 2020 && version[1] > 3) ||
|
||||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
|
||||
(version[0] > 2021) ||
|
||||
(version[0] == 2021 && version[1] > 1) ||
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
|
||||
{
|
||||
m_CommonParameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
|
||||
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
|
||||
{
|
||||
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum PassType
|
||||
{
|
||||
kPassTypeNormal = 0,
|
||||
kPassTypeUse = 1,
|
||||
kPassTypeGrab = 2
|
||||
Normal = 0,
|
||||
Use = 1,
|
||||
Grab = 2
|
||||
};
|
||||
|
||||
public class SerializedPass
|
||||
{
|
||||
public Hash128[] m_EditorDataHash;
|
||||
public byte[] m_Platforms;
|
||||
public ushort[] m_LocalKeywordMask;
|
||||
public ushort[] m_GlobalKeywordMask;
|
||||
public KeyValuePair<string, int>[] m_NameIndices;
|
||||
public PassType m_Type;
|
||||
public SerializedShaderState m_State;
|
||||
@@ -597,11 +750,32 @@ namespace AssetStudio
|
||||
public string m_Name;
|
||||
public string m_TextureName;
|
||||
public SerializedTagMap m_Tags;
|
||||
public ushort[] m_SerializedKeywordStateMask;
|
||||
|
||||
public SerializedPass(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
int numEditorDataHash = reader.ReadInt32();
|
||||
m_EditorDataHash = new Hash128[numEditorDataHash];
|
||||
for (int i = 0; i < numEditorDataHash; i++)
|
||||
{
|
||||
m_EditorDataHash[i] = new Hash128(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
m_Platforms = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
if (version[0] < 2021 || (version[0] == 2021 && version[1] < 2)) //2021.1 and down
|
||||
{
|
||||
m_LocalKeywordMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
m_GlobalKeywordMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
int numIndices = reader.ReadInt32();
|
||||
m_NameIndices = new KeyValuePair<string, int>[numIndices];
|
||||
for (int i = 0; i < numIndices; i++)
|
||||
@@ -631,6 +805,11 @@ namespace AssetStudio
|
||||
m_Name = reader.ReadAlignedString();
|
||||
m_TextureName = reader.ReadAlignedString();
|
||||
m_Tags = new SerializedTagMap(reader);
|
||||
if (version[0] == 2021 && version[1] >= 2) //2021.2 ~2021.x
|
||||
{
|
||||
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,18 +860,35 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedCustomEditorForRenderPipeline
|
||||
{
|
||||
public string customEditorName;
|
||||
public string renderPipelineType;
|
||||
|
||||
public SerializedCustomEditorForRenderPipeline(BinaryReader reader)
|
||||
{
|
||||
customEditorName = reader.ReadAlignedString();
|
||||
renderPipelineType = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedShader
|
||||
{
|
||||
public SerializedProperties m_PropInfo;
|
||||
public SerializedSubShader[] m_SubShaders;
|
||||
public string[] m_KeywordNames;
|
||||
public byte[] m_KeywordFlags;
|
||||
public string m_Name;
|
||||
public string m_CustomEditorName;
|
||||
public string m_FallbackName;
|
||||
public SerializedShaderDependency[] m_Dependencies;
|
||||
public SerializedCustomEditorForRenderPipeline[] m_CustomEditorForRenderPipelines;
|
||||
public bool m_DisableNoSubshadersMessage;
|
||||
|
||||
public SerializedShader(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_PropInfo = new SerializedProperties(reader);
|
||||
|
||||
int numSubShaders = reader.ReadInt32();
|
||||
@@ -702,6 +898,13 @@ namespace AssetStudio
|
||||
m_SubShaders[i] = new SerializedSubShader(reader);
|
||||
}
|
||||
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
m_KeywordNames = reader.ReadStringArray();
|
||||
m_KeywordFlags = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
m_Name = reader.ReadAlignedString();
|
||||
m_CustomEditorName = reader.ReadAlignedString();
|
||||
m_FallbackName = reader.ReadAlignedString();
|
||||
@@ -713,6 +916,16 @@ namespace AssetStudio
|
||||
m_Dependencies[i] = new SerializedShaderDependency(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_CustomEditorForRenderPipelinesSize = reader.ReadInt32();
|
||||
m_CustomEditorForRenderPipelines = new SerializedCustomEditorForRenderPipeline[m_CustomEditorForRenderPipelinesSize];
|
||||
for (int i = 0; i < m_CustomEditorForRenderPipelinesSize; i++)
|
||||
{
|
||||
m_CustomEditorForRenderPipelines[i] = new SerializedCustomEditorForRenderPipeline(reader);
|
||||
}
|
||||
}
|
||||
|
||||
m_DisableNoSubshadersMessage = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
@@ -720,28 +933,32 @@ namespace AssetStudio
|
||||
|
||||
public enum ShaderCompilerPlatform
|
||||
{
|
||||
kShaderCompPlatformNone = -1,
|
||||
kShaderCompPlatformGL = 0,
|
||||
kShaderCompPlatformD3D9 = 1,
|
||||
kShaderCompPlatformXbox360 = 2,
|
||||
kShaderCompPlatformPS3 = 3,
|
||||
kShaderCompPlatformD3D11 = 4,
|
||||
kShaderCompPlatformGLES20 = 5,
|
||||
kShaderCompPlatformNaCl = 6,
|
||||
kShaderCompPlatformFlash = 7,
|
||||
kShaderCompPlatformD3D11_9x = 8,
|
||||
kShaderCompPlatformGLES3Plus = 9,
|
||||
kShaderCompPlatformPSP2 = 10,
|
||||
kShaderCompPlatformPS4 = 11,
|
||||
kShaderCompPlatformXboxOne = 12,
|
||||
kShaderCompPlatformPSM = 13,
|
||||
kShaderCompPlatformMetal = 14,
|
||||
kShaderCompPlatformOpenGLCore = 15,
|
||||
kShaderCompPlatformN3DS = 16,
|
||||
kShaderCompPlatformWiiU = 17,
|
||||
kShaderCompPlatformVulkan = 18,
|
||||
kShaderCompPlatformSwitch = 19,
|
||||
kShaderCompPlatformXboxOneD3D12 = 20
|
||||
None = -1,
|
||||
GL = 0,
|
||||
D3D9 = 1,
|
||||
Xbox360 = 2,
|
||||
PS3 = 3,
|
||||
D3D11 = 4,
|
||||
GLES20 = 5,
|
||||
NaCl = 6,
|
||||
Flash = 7,
|
||||
D3D11_9x = 8,
|
||||
GLES3Plus = 9,
|
||||
PSP2 = 10,
|
||||
PS4 = 11,
|
||||
XboxOne = 12,
|
||||
PSM = 13,
|
||||
Metal = 14,
|
||||
OpenGLCore = 15,
|
||||
N3DS = 16,
|
||||
WiiU = 17,
|
||||
Vulkan = 18,
|
||||
Switch = 19,
|
||||
XboxOneD3D12 = 20,
|
||||
GameCoreXboxOne = 21,
|
||||
GameCoreScarlett = 22,
|
||||
PS5 = 23,
|
||||
PS5NGGC = 24
|
||||
};
|
||||
|
||||
public class Shader : NamedObject
|
||||
@@ -753,9 +970,9 @@ namespace AssetStudio
|
||||
//5.5 and up
|
||||
public SerializedShader m_ParsedForm;
|
||||
public ShaderCompilerPlatform[] platforms;
|
||||
public uint[] offsets;
|
||||
public uint[] compressedLengths;
|
||||
public uint[] decompressedLengths;
|
||||
public uint[][] offsets;
|
||||
public uint[][] compressedLengths;
|
||||
public uint[][] decompressedLengths;
|
||||
public byte[] compressedBlob;
|
||||
|
||||
public Shader(ObjectReader reader) : base(reader)
|
||||
@@ -766,27 +983,47 @@ namespace AssetStudio
|
||||
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
offsets = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
compressedLengths = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
decompressedLengths = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
offsets = reader.ReadUInt32ArrayArray();
|
||||
compressedLengths = reader.ReadUInt32ArrayArray();
|
||||
decompressedLengths = reader.ReadUInt32ArrayArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
offsets = reader.ReadUInt32Array();
|
||||
compressedLengths = reader.ReadUInt32Array();
|
||||
decompressedLengths = reader.ReadUInt32Array();
|
||||
offsets = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
compressedLengths = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
decompressedLengths = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
}
|
||||
compressedBlob = reader.ReadBytes(reader.ReadInt32());
|
||||
compressedBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
var m_DependenciesCount = reader.ReadInt32();
|
||||
for (int i = 0; i < m_DependenciesCount; i++)
|
||||
{
|
||||
new PPtr<Shader>(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2018)
|
||||
{
|
||||
var m_NonModifiableTexturesCount = reader.ReadInt32();
|
||||
for (int i = 0; i < m_NonModifiableTexturesCount; i++)
|
||||
{
|
||||
var first = reader.ReadAlignedString();
|
||||
new PPtr<Texture>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
var m_ShaderIsBaked = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Script = reader.ReadBytes(reader.ReadInt32());
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
var m_PathName = reader.ReadAlignedString();
|
||||
if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4
|
||||
{
|
||||
decompressedSize = reader.ReadUInt32();
|
||||
m_SubProgramBlob = reader.ReadBytes(reader.ReadInt32());
|
||||
m_SubProgramBlob = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
@@ -19,23 +18,23 @@ namespace AssetStudio
|
||||
|
||||
public enum SpritePackingRotation
|
||||
{
|
||||
kSPRNone = 0,
|
||||
kSPRFlipHorizontal = 1,
|
||||
kSPRFlipVertical = 2,
|
||||
kSPRRotate180 = 3,
|
||||
kSPRRotate90 = 4
|
||||
None = 0,
|
||||
FlipHorizontal = 1,
|
||||
FlipVertical = 2,
|
||||
Rotate180 = 3,
|
||||
Rotate90 = 4
|
||||
};
|
||||
|
||||
public enum SpritePackingMode
|
||||
{
|
||||
kSPMTight = 0,
|
||||
kSPMRectangle
|
||||
Tight = 0,
|
||||
Rectangle
|
||||
};
|
||||
|
||||
public enum SpriteMeshType
|
||||
{
|
||||
kSpriteMeshTypeFullRect,
|
||||
kSpriteMeshTypeTight
|
||||
FullRect,
|
||||
Tight
|
||||
};
|
||||
|
||||
public class SpriteSettings
|
||||
@@ -88,7 +87,7 @@ namespace AssetStudio
|
||||
public ushort[] indices;
|
||||
public Matrix4x4[] m_Bindpose;
|
||||
public BoneWeights4[] m_SourceSkin;
|
||||
public RectangleF textureRect;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public SpriteSettings settingsRaw;
|
||||
@@ -124,7 +123,7 @@ namespace AssetStudio
|
||||
m_SubMeshes[i] = new SubMesh(reader);
|
||||
}
|
||||
|
||||
m_IndexBuffer = reader.ReadBytes(reader.ReadInt32());
|
||||
m_IndexBuffer = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
m_VertexData = new VertexData(reader);
|
||||
@@ -156,7 +155,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
textureRect = reader.ReadRectangleF();
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
@@ -176,13 +175,29 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public class Rectf
|
||||
{
|
||||
public float x;
|
||||
public float y;
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
public Rectf(BinaryReader reader)
|
||||
{
|
||||
x = reader.ReadSingle();
|
||||
y = reader.ReadSingle();
|
||||
width = reader.ReadSingle();
|
||||
height = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Sprite : NamedObject
|
||||
{
|
||||
public RectangleF m_Rect;
|
||||
public Rectf m_Rect;
|
||||
public Vector2 m_Offset;
|
||||
public Vector4 m_Border;
|
||||
public float m_PixelsToUnits;
|
||||
public Vector2 m_Pivot;
|
||||
public Vector2 m_Pivot = new Vector2(0.5f, 0.5f);
|
||||
public uint m_Extrude;
|
||||
public bool m_IsPolygon;
|
||||
public KeyValuePair<Guid, long> m_RenderDataKey;
|
||||
@@ -193,7 +208,7 @@ namespace AssetStudio
|
||||
|
||||
public Sprite(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Rect = reader.ReadRectangleF();
|
||||
m_Rect = new Rectf(reader);
|
||||
m_Offset = reader.ReadVector2();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
|
||||
@@ -7,19 +7,20 @@ namespace AssetStudio
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public PPtr<Texture2D> alphaTexture;
|
||||
public System.Drawing.RectangleF textureRect;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public Vector4 uvTransform;
|
||||
public float downscaleMultiplier;
|
||||
public SpriteSettings settingsRaw;
|
||||
public SecondarySpriteTexture[] secondaryTextures;
|
||||
|
||||
public SpriteAtlasData(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
alphaTexture = new PPtr<Texture2D>(reader);
|
||||
textureRect = reader.ReadRectangleF();
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
@@ -28,6 +29,16 @@ namespace AssetStudio
|
||||
uvTransform = reader.ReadVector4();
|
||||
downscaleMultiplier = reader.ReadSingle();
|
||||
settingsRaw = new SpriteSettings(reader);
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var secondaryTexturesSize = reader.ReadInt32();
|
||||
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
|
||||
for (int i = 0; i < secondaryTexturesSize; i++)
|
||||
{
|
||||
secondaryTextures[i] = new SecondarySpriteTexture(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +46,7 @@ namespace AssetStudio
|
||||
{
|
||||
public PPtr<Sprite>[] m_PackedSprites;
|
||||
public Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> m_RenderDataMap;
|
||||
public bool m_IsVariant;
|
||||
|
||||
public SpriteAtlas(ObjectReader reader) : base(reader)
|
||||
{
|
||||
@@ -56,8 +68,9 @@ namespace AssetStudio
|
||||
var value = new SpriteAtlasData(reader);
|
||||
m_RenderDataMap.Add(new KeyValuePair<Guid, long>(first, second), value);
|
||||
}
|
||||
//string m_Tag
|
||||
//bool m_IsVariant
|
||||
var m_Tag = reader.ReadAlignedString();
|
||||
m_IsVariant = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace AssetStudio
|
||||
|
||||
public TextAsset(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = reader.ReadBytes(reader.ReadInt32());
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ForcedFallbackFormat = reader.ReadInt32();
|
||||
var m_DownscaleFallback = reader.ReadBoolean();
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_IsAlphaChannelOptional = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,22 @@ namespace AssetStudio
|
||||
{
|
||||
public class StreamingInfo
|
||||
{
|
||||
public uint offset;
|
||||
public long offset; //ulong
|
||||
public uint size;
|
||||
public string path;
|
||||
|
||||
public StreamingInfo(ObjectReader reader)
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
offset = reader.ReadInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
}
|
||||
size = reader.ReadUInt32();
|
||||
path = reader.ReadAlignedString();
|
||||
}
|
||||
@@ -59,6 +68,10 @@ namespace AssetStudio
|
||||
m_Width = reader.ReadInt32();
|
||||
m_Height = reader.ReadInt32();
|
||||
var m_CompleteImageSize = reader.ReadInt32();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_MipsStripped = reader.ReadInt32();
|
||||
}
|
||||
m_TextureFormat = (TextureFormat)reader.ReadInt32();
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
|
||||
{
|
||||
@@ -68,9 +81,29 @@ namespace AssetStudio
|
||||
{
|
||||
m_MipCount = reader.ReadInt32();
|
||||
}
|
||||
var m_IsReadable = reader.ReadBoolean(); //2.6.0 and up
|
||||
var m_ReadAllowed = reader.ReadBoolean(); //3.0.0 - 5.4
|
||||
//bool m_StreamingMipmaps 2018.2 and up
|
||||
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
|
||||
{
|
||||
var m_IsReadable = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_IsPreProcessed = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 3) //3.0.0 - 5.4
|
||||
{
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
|
||||
{
|
||||
var m_ReadAllowed = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
var m_StreamingMipmaps = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
@@ -87,6 +120,11 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ColorSpace = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_PlatformBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
var image_data_size = reader.ReadInt32();
|
||||
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
|
||||
{
|
||||
@@ -96,7 +134,7 @@ namespace AssetStudio
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_StreamData?.path))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, (int)m_StreamData.size);
|
||||
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -113,10 +151,13 @@ namespace AssetStudio
|
||||
RGB24,
|
||||
RGBA32,
|
||||
ARGB32,
|
||||
RGB565 = 7,
|
||||
R16 = 9,
|
||||
ARGBFloat,
|
||||
RGB565,
|
||||
BGR24,
|
||||
R16,
|
||||
DXT1,
|
||||
DXT5 = 12,
|
||||
DXT3,
|
||||
DXT5,
|
||||
RGBA4444,
|
||||
BGRA32,
|
||||
RHalf,
|
||||
@@ -127,11 +168,12 @@ namespace AssetStudio
|
||||
RGBAFloat,
|
||||
YUY2,
|
||||
RGB9e5Float,
|
||||
BC4 = 26,
|
||||
BC5,
|
||||
BC6H = 24,
|
||||
RGBFloat,
|
||||
BC6H,
|
||||
BC7,
|
||||
DXT1Crunched = 28,
|
||||
BC4,
|
||||
BC5,
|
||||
DXT1Crunched,
|
||||
DXT5Crunched,
|
||||
PVRTC_RGB2,
|
||||
PVRTC_RGBA2,
|
||||
@@ -171,5 +213,8 @@ namespace AssetStudio
|
||||
ASTC_HDR_8x8,
|
||||
ASTC_HDR_10x10,
|
||||
ASTC_HDR_12x12,
|
||||
RG32,
|
||||
RGB48,
|
||||
RGBA64
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamedResource
|
||||
{
|
||||
public string m_Source;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
|
||||
public StreamedResource(BinaryReader reader)
|
||||
{
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VideoClip : NamedObject
|
||||
{
|
||||
public ResourceReader m_VideoData;
|
||||
public string m_OriginalPath;
|
||||
public string m_Source;
|
||||
public ulong m_Size;
|
||||
public StreamedResource m_ExternalResources;
|
||||
public uint Width;
|
||||
public uint Height;
|
||||
public double m_FrameRate;
|
||||
public int m_Format;
|
||||
public bool m_HasSplitAlpha;
|
||||
|
||||
public VideoClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_OriginalPath = reader.ReadAlignedString();
|
||||
var m_ProxyWidth = reader.ReadUInt32();
|
||||
var m_ProxyHeight = reader.ReadUInt32();
|
||||
var Width = reader.ReadUInt32();
|
||||
var Height = reader.ReadUInt32();
|
||||
Width = reader.ReadUInt32();
|
||||
Height = reader.ReadUInt32();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_PixelAspecRatioNum = reader.ReadUInt32();
|
||||
var m_PixelAspecRatioDen = reader.ReadUInt32();
|
||||
}
|
||||
var m_FrameRate = reader.ReadDouble();
|
||||
m_FrameRate = reader.ReadDouble();
|
||||
var m_FrameCount = reader.ReadUInt64();
|
||||
var m_Format = reader.ReadInt32();
|
||||
m_Format = reader.ReadInt32();
|
||||
var m_AudioChannelCount = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_AudioSampleRate = reader.ReadUInt32Array();
|
||||
var m_AudioLanguage = reader.ReadStringArray();
|
||||
//StreamedResource m_ExternalResources
|
||||
m_Source = reader.ReadAlignedString();
|
||||
var m_Offset = reader.ReadUInt64();
|
||||
m_Size = reader.ReadUInt64();
|
||||
var m_HasSplitAlpha = reader.ReadBoolean();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_VideoShadersSize = reader.ReadInt32();
|
||||
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
|
||||
for (int i = 0; i < m_VideoShadersSize; i++)
|
||||
{
|
||||
m_VideoShaders[i] = new PPtr<Shader>(reader);
|
||||
}
|
||||
}
|
||||
m_ExternalResources = new StreamedResource(reader);
|
||||
m_HasSplitAlpha = reader.ReadBoolean();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_sRGB = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_Source))
|
||||
if (!string.IsNullOrEmpty(m_ExternalResources.m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, (long)m_Offset, (int)m_Size);
|
||||
resourceReader = new ResourceReader(m_ExternalResources.m_Source, assetsFile, m_ExternalResources.m_Offset, m_ExternalResources.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_ExternalResources.m_Size);
|
||||
}
|
||||
m_VideoData = resourceReader;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ namespace AssetStudio
|
||||
{1093, "m_CorrespondingSourceObject"},
|
||||
{1121, "m_PrefabInstance"},
|
||||
{1138, "m_PrefabAsset"},
|
||||
{1152, "FileSize"}
|
||||
{1152, "FileSize"},
|
||||
{1161, "Hash128"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum EndianType
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
}
|
||||
|
||||
public class EndianBinaryReader : BinaryReader
|
||||
{
|
||||
public EndianType endian;
|
||||
private readonly byte[] buffer;
|
||||
|
||||
public EndianType Endian;
|
||||
|
||||
public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream)
|
||||
{
|
||||
this.endian = endian;
|
||||
Endian = endian;
|
||||
buffer = new byte[8];
|
||||
}
|
||||
|
||||
public long Position
|
||||
@@ -28,88 +24,82 @@ namespace AssetStudio
|
||||
|
||||
public override short ReadInt16()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(2);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt16(buff, 0);
|
||||
Read(buffer, 0, 2);
|
||||
return BinaryPrimitives.ReadInt16BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt16();
|
||||
}
|
||||
|
||||
public override int ReadInt32()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt32(buff, 0);
|
||||
Read(buffer, 0, 4);
|
||||
return BinaryPrimitives.ReadInt32BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt32();
|
||||
}
|
||||
|
||||
public override long ReadInt64()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt64(buff, 0);
|
||||
Read(buffer, 0, 8);
|
||||
return BinaryPrimitives.ReadInt64BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt64();
|
||||
}
|
||||
|
||||
public override ushort ReadUInt16()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(2);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt16(buff, 0);
|
||||
Read(buffer, 0, 2);
|
||||
return BinaryPrimitives.ReadUInt16BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt16();
|
||||
}
|
||||
|
||||
public override uint ReadUInt32()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt32(buff, 0);
|
||||
Read(buffer, 0, 4);
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt32();
|
||||
}
|
||||
|
||||
public override ulong ReadUInt64()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt64(buff, 0);
|
||||
Read(buffer, 0, 8);
|
||||
return BinaryPrimitives.ReadUInt64BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt64();
|
||||
}
|
||||
|
||||
public override float ReadSingle()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToSingle(buff, 0);
|
||||
Read(buffer, 0, 4);
|
||||
Array.Reverse(buffer, 0, 4);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
return base.ReadSingle();
|
||||
}
|
||||
|
||||
public override double ReadDouble()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt64(buff, 0);
|
||||
Read(buffer, 0, 8);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
return base.ReadDouble();
|
||||
}
|
||||
|
||||
14
AssetStudio/EndianType.cs
Normal file
14
AssetStudio/EndianType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum EndianType
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
}
|
||||
}
|
||||
@@ -72,11 +72,6 @@ namespace AssetStudio
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static System.Drawing.RectangleF ReadRectangleF(this BinaryReader reader)
|
||||
{
|
||||
return new System.Drawing.RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Color ReadColor4(this BinaryReader reader)
|
||||
{
|
||||
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
@@ -102,6 +97,11 @@ namespace AssetStudio
|
||||
return ReadArray(reader.ReadBoolean, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static byte[] ReadUInt8Array(this BinaryReader reader)
|
||||
{
|
||||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static ushort[] ReadUInt16Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt16, reader.ReadInt32());
|
||||
|
||||
103
AssetStudio/FileReader.cs
Normal file
103
AssetStudio/FileReader.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileReader : EndianBinaryReader
|
||||
{
|
||||
public string FullPath;
|
||||
public string FileName;
|
||||
public FileType FileType;
|
||||
|
||||
private static readonly byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
private static readonly byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
private static readonly byte[] zipMagic = { 0x50, 0x4B, 0x03, 0x04 };
|
||||
private static readonly byte[] zipSpannedMagic = { 0x50, 0x4B, 0x07, 0x08 };
|
||||
|
||||
public FileReader(string path) : this(path, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { }
|
||||
|
||||
public FileReader(string path, Stream stream) : base(stream, EndianType.BigEndian)
|
||||
{
|
||||
FullPath = Path.GetFullPath(path);
|
||||
FileName = Path.GetFileName(path);
|
||||
FileType = CheckFileType();
|
||||
}
|
||||
|
||||
private FileType CheckFileType()
|
||||
{
|
||||
var signature = this.ReadStringToNull(20);
|
||||
Position = 0;
|
||||
switch (signature)
|
||||
{
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
case "UnityArchive":
|
||||
case "UnityFS":
|
||||
return FileType.BundleFile;
|
||||
case "UnityWebData1.0":
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
byte[] magic = ReadBytes(2);
|
||||
Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.GZipFile;
|
||||
}
|
||||
Position = 0x20;
|
||||
magic = ReadBytes(6);
|
||||
Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.BrotliFile;
|
||||
}
|
||||
if (IsSerializedFile())
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
magic = ReadBytes(4);
|
||||
Position = 0;
|
||||
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
||||
return FileType.ZipFile;
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSerializedFile()
|
||||
{
|
||||
var fileSize = BaseStream.Length;
|
||||
if (fileSize < 20)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var m_MetadataSize = ReadUInt32();
|
||||
long m_FileSize = ReadUInt32();
|
||||
var m_Version = ReadUInt32();
|
||||
long m_DataOffset = ReadUInt32();
|
||||
var m_Endianess = ReadByte();
|
||||
var m_Reserved = ReadBytes(3);
|
||||
if (m_Version >= 22)
|
||||
{
|
||||
if (fileSize < 48)
|
||||
{
|
||||
Position = 0;
|
||||
return false;
|
||||
}
|
||||
m_MetadataSize = ReadUInt32();
|
||||
m_FileSize = ReadInt64();
|
||||
m_DataOffset = ReadInt64();
|
||||
}
|
||||
Position = 0;
|
||||
if (m_FileSize != fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_DataOffset > fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
AssetStudio/FileType.cs
Normal file
19
AssetStudio/FileType.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
WebFile,
|
||||
ResourceFile,
|
||||
GZipFile,
|
||||
BrotliFile,
|
||||
ZipFile
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,28 @@ namespace AssetStudio
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImportedFrame FindRelativeFrameWithPath(string path)
|
||||
{
|
||||
var subs = path.Split(new[] { '/' }, 2);
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (child.Name == subs[0])
|
||||
{
|
||||
if (subs.Length == 1)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = child.FindRelativeFrameWithPath(subs[1]);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImportedFrame FindFrame(string name)
|
||||
{
|
||||
if (Name == name)
|
||||
@@ -132,6 +154,7 @@ namespace AssetStudio
|
||||
public class ImportedMesh
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedSubmesh> SubmeshList { get; set; }
|
||||
public List<ImportedBone> BoneList { get; set; }
|
||||
public bool hasNormal { get; set; }
|
||||
@@ -142,9 +165,9 @@ namespace AssetStudio
|
||||
|
||||
public class ImportedSubmesh
|
||||
{
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedFace> FaceList { get; set; }
|
||||
public string Material { get; set; }
|
||||
public int BaseVertex { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertex
|
||||
|
||||
@@ -16,11 +16,11 @@ namespace AssetStudio
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Log(LoggerEvent loggerEvent, string message);
|
||||
void Log(LoggerEvent loggerEvent, string message, bool ignoreLevel = false);
|
||||
}
|
||||
|
||||
public sealed class DummyLogger : ILogger
|
||||
{
|
||||
public void Log(LoggerEvent loggerEvent, string message) { }
|
||||
public void Log(LoggerEvent loggerEvent, string message, bool ignoreLevel) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IProgress
|
||||
{
|
||||
void Report(int value);
|
||||
}
|
||||
|
||||
public sealed class DummyProgress : IProgress
|
||||
{
|
||||
public void Report(int value) { }
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Org.Brotli.Dec;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
WebFile,
|
||||
ResourceFile
|
||||
}
|
||||
|
||||
public static class ImportHelper
|
||||
{
|
||||
public static void MergeSplitAssets(string path, bool allDirectories = false)
|
||||
@@ -20,8 +14,8 @@ namespace AssetStudio
|
||||
foreach (var splitFile in splitFiles)
|
||||
{
|
||||
var destFile = Path.GetFileNameWithoutExtension(splitFile);
|
||||
var destPath = Path.GetDirectoryName(splitFile) + "\\";
|
||||
var destFull = destPath + destFile;
|
||||
var destPath = Path.GetDirectoryName(splitFile);
|
||||
var destFull = Path.Combine(destPath, destFile);
|
||||
if (!File.Exists(destFull))
|
||||
{
|
||||
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
|
||||
@@ -43,7 +37,7 @@ namespace AssetStudio
|
||||
public static string[] ProcessingSplitFiles(List<string> selectFile)
|
||||
{
|
||||
var splitFiles = selectFile.Where(x => x.Contains(".split"))
|
||||
.Select(x => Path.GetDirectoryName(x) + "\\" + Path.GetFileNameWithoutExtension(x))
|
||||
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
selectFile.RemoveAll(x => x.Contains(".split"));
|
||||
@@ -57,55 +51,31 @@ namespace AssetStudio
|
||||
return selectFile.Distinct().ToArray();
|
||||
}
|
||||
|
||||
public static FileType CheckFileType(Stream stream, out EndianBinaryReader reader)
|
||||
public static FileReader DecompressGZip(FileReader reader)
|
||||
{
|
||||
reader = new EndianBinaryReader(stream);
|
||||
return CheckFileType(reader);
|
||||
}
|
||||
|
||||
public static FileType CheckFileType(string fileName, out EndianBinaryReader reader)
|
||||
{
|
||||
reader = new EndianBinaryReader(File.OpenRead(fileName));
|
||||
return CheckFileType(reader);
|
||||
}
|
||||
|
||||
private static FileType CheckFileType(EndianBinaryReader reader)
|
||||
{
|
||||
var signature = reader.ReadStringToNull(20);
|
||||
reader.Position = 0;
|
||||
switch (signature)
|
||||
using (reader)
|
||||
{
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
case "UnityArchive":
|
||||
case "UnityFS":
|
||||
return FileType.BundleFile;
|
||||
case "UnityWebData1.0":
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
var magic = reader.ReadBytes(2);
|
||||
reader.Position = 0;
|
||||
if (WebFile.gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.WebFile;
|
||||
}
|
||||
reader.Position = 0x20;
|
||||
magic = reader.ReadBytes(6);
|
||||
reader.Position = 0;
|
||||
if (WebFile.brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.WebFile;
|
||||
}
|
||||
if (SerializedFile.IsSerializedFile(reader))
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
}
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static FileReader DecompressBrotli(FileReader reader)
|
||||
{
|
||||
using (reader)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var brotliStream = new BrotliInputStream(reader.BaseStream))
|
||||
{
|
||||
brotliStream.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,5 +14,14 @@ namespace AssetStudio
|
||||
public static void Info(string message) => Default.Log(LoggerEvent.Info, message);
|
||||
public static void Warning(string message) => Default.Log(LoggerEvent.Warning, message);
|
||||
public static void Error(string message) => Default.Log(LoggerEvent.Error, message);
|
||||
|
||||
public static void Error(string message, Exception e)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(message);
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(e.ToString());
|
||||
Default.Log(LoggerEvent.Error, sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,540 +0,0 @@
|
||||
#define CHECK_ARGS
|
||||
#define CHECK_EOF
|
||||
//#define LOCAL_SHADOW
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Lz4
|
||||
{
|
||||
public class Lz4DecoderStream : Stream
|
||||
{
|
||||
public Lz4DecoderStream(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
Reset(input, inputLength);
|
||||
}
|
||||
|
||||
private void Reset(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
this.inputLength = inputLength;
|
||||
this.input = input;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
|
||||
decodeBufferPos = 0;
|
||||
|
||||
litLen = 0;
|
||||
matLen = 0;
|
||||
matDst = 0;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing && input != null)
|
||||
{
|
||||
input.Close();
|
||||
}
|
||||
input = null;
|
||||
decodeBuffer = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
private long inputLength;
|
||||
private Stream input;
|
||||
|
||||
//because we might not be able to match back across invocations,
|
||||
//we have to keep the last window's worth of bytes around for reuse
|
||||
//we use a circular buffer for this - every time we write into this
|
||||
//buffer, we also write the same into our output buffer
|
||||
|
||||
private const int DecBufLen = 0x10000;
|
||||
private const int DecBufMask = 0xFFFF;
|
||||
|
||||
private const int InBufLen = 128;
|
||||
|
||||
private byte[] decodeBuffer = new byte[DecBufLen + InBufLen];
|
||||
private int decodeBufferPos, inBufPos, inBufEnd;
|
||||
|
||||
//we keep track of which phase we're in so that we can jump right back
|
||||
//into the correct part of decoding
|
||||
|
||||
private DecodePhase phase;
|
||||
|
||||
private enum DecodePhase
|
||||
{
|
||||
ReadToken,
|
||||
ReadExLiteralLength,
|
||||
CopyLiteral,
|
||||
ReadOffset,
|
||||
ReadExMatchLength,
|
||||
CopyMatch,
|
||||
}
|
||||
|
||||
//state within interruptable phases and across phase boundaries is
|
||||
//kept here - again, so that we can punt out and restart freely
|
||||
|
||||
private int litLen, matLen, matDst;
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
#if CHECK_ARGS
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException("buffer");
|
||||
if (offset < 0 || count < 0 || buffer.Length - count < offset)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (input == null)
|
||||
throw new InvalidOperationException();
|
||||
#endif
|
||||
int nRead, nToRead = count;
|
||||
|
||||
var decBuf = decodeBuffer;
|
||||
|
||||
//the stringy gotos are obnoxious, but their purpose is to
|
||||
//make it *blindingly* obvious how the state machine transitions
|
||||
//back and forth as it reads - remember, we can yield out of
|
||||
//this routine in several places, and we must be able to re-enter
|
||||
//and pick up where we left off!
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
var phase = this.phase;
|
||||
var inBufPos = this.inBufPos;
|
||||
var inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
switch (phase)
|
||||
{
|
||||
case DecodePhase.ReadToken:
|
||||
goto readToken;
|
||||
|
||||
case DecodePhase.ReadExLiteralLength:
|
||||
goto readExLiteralLength;
|
||||
|
||||
case DecodePhase.CopyLiteral:
|
||||
goto copyLiteral;
|
||||
|
||||
case DecodePhase.ReadOffset:
|
||||
goto readOffset;
|
||||
|
||||
case DecodePhase.ReadExMatchLength:
|
||||
goto readExMatchLength;
|
||||
|
||||
case DecodePhase.CopyMatch:
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readToken:
|
||||
int tok;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
tok = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
|
||||
tok = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (tok == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen = tok >> 4;
|
||||
matLen = (tok & 0xF) + 4;
|
||||
|
||||
switch (litLen)
|
||||
{
|
||||
case 0:
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
case 0xF:
|
||||
phase = DecodePhase.ReadExLiteralLength;
|
||||
goto readExLiteralLength;
|
||||
|
||||
default:
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
readExLiteralLength:
|
||||
int exLitLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exLitLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exLitLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
|
||||
#if CHECK_EOF
|
||||
if (exLitLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen += exLitLen;
|
||||
if (exLitLen == 255)
|
||||
goto readExLiteralLength;
|
||||
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
|
||||
copyLiteral:
|
||||
int nReadLit = litLen < nToRead ? litLen : nToRead;
|
||||
if (nReadLit != 0)
|
||||
{
|
||||
if (inBufPos + nReadLit <= inBufEnd)
|
||||
{
|
||||
int ofs = offset;
|
||||
|
||||
for (int c = nReadLit; c-- != 0;)
|
||||
buffer[ofs++] = decBuf[inBufPos++];
|
||||
|
||||
nRead = nReadLit;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
nRead = ReadCore(buffer, offset, nReadLit);
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
offset += nRead;
|
||||
nToRead -= nRead;
|
||||
|
||||
litLen -= nRead;
|
||||
|
||||
if (litLen != 0)
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
readOffset:
|
||||
if (inBufPos + 1 < inBufEnd)
|
||||
{
|
||||
matDst = (decBuf[inBufPos + 1] << 8) | decBuf[inBufPos];
|
||||
inBufPos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
matDst = ReadOffsetCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (matDst == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (matLen == 15 + 4)
|
||||
{
|
||||
phase = DecodePhase.ReadExMatchLength;
|
||||
goto readExMatchLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readExMatchLength:
|
||||
int exMatLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exMatLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exMatLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (exMatLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
matLen += exMatLen;
|
||||
if (exMatLen == 255)
|
||||
goto readExMatchLength;
|
||||
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
|
||||
copyMatch:
|
||||
int nCpyMat = matLen < nToRead ? matLen : nToRead;
|
||||
if (nCpyMat != 0)
|
||||
{
|
||||
nRead = count - nToRead;
|
||||
|
||||
int bufDst = matDst - nRead;
|
||||
if (bufDst > 0)
|
||||
{
|
||||
//offset is fairly far back, we need to pull from the buffer
|
||||
|
||||
int bufSrc = decodeBufferPos - bufDst;
|
||||
if (bufSrc < 0)
|
||||
bufSrc += DecBufLen;
|
||||
int bufCnt = bufDst < nCpyMat ? bufDst : nCpyMat;
|
||||
|
||||
for (int c = bufCnt; c-- != 0;)
|
||||
buffer[offset++] = decBuf[bufSrc++ & DecBufMask];
|
||||
}
|
||||
else
|
||||
{
|
||||
bufDst = 0;
|
||||
}
|
||||
|
||||
int sOfs = offset - matDst;
|
||||
for (int i = bufDst; i < nCpyMat; i++)
|
||||
buffer[offset++] = buffer[sOfs++];
|
||||
|
||||
nToRead -= nCpyMat;
|
||||
matLen -= nCpyMat;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
goto readToken;
|
||||
|
||||
finish:
|
||||
nRead = count - nToRead;
|
||||
|
||||
int nToBuf = nRead < DecBufLen ? nRead : DecBufLen;
|
||||
int repPos = offset - nToBuf;
|
||||
|
||||
if (nToBuf == DecBufLen)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, repPos, decBuf, 0, DecBufLen);
|
||||
decodeBufferPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int decPos = decodeBufferPos;
|
||||
|
||||
while (nToBuf-- != 0)
|
||||
decBuf[decPos++ & DecBufMask] = buffer[repPos++];
|
||||
|
||||
decodeBufferPos = decPos & DecBufMask;
|
||||
}
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
this.phase = phase;
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
return nRead;
|
||||
}
|
||||
|
||||
private int ReadByteCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
return buf[inBufPos++];
|
||||
}
|
||||
|
||||
private int ReadOffsetCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
if (inBufEnd - inBufPos == 1)
|
||||
{
|
||||
buf[DecBufLen] = buf[inBufPos];
|
||||
|
||||
int nRead = input.Read(buf, DecBufLen + 1,
|
||||
InBufLen - 1 < inputLength ? InBufLen - 1 : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
{
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead + 1;
|
||||
}
|
||||
|
||||
int ret = (buf[inBufPos + 1] << 8) | buf[inBufPos];
|
||||
inBufPos += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private int ReadCore(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int nToRead = count;
|
||||
|
||||
var buf = decodeBuffer;
|
||||
int inBufLen = inBufEnd - inBufPos;
|
||||
|
||||
int fromBuf = nToRead < inBufLen ? nToRead : inBufLen;
|
||||
if (fromBuf != 0)
|
||||
{
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
if (nToRead != 0)
|
||||
{
|
||||
int nRead;
|
||||
|
||||
if (nToRead >= InBufLen)
|
||||
{
|
||||
nRead = input.Read(buffer, offset,
|
||||
nToRead < inputLength ? nToRead : (int)inputLength);
|
||||
nToRead -= nRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
|
||||
fromBuf = nToRead < nRead ? nToRead : nRead;
|
||||
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
inputLength -= nRead;
|
||||
}
|
||||
|
||||
return count - nToRead;
|
||||
}
|
||||
|
||||
#region Stream internals
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a half-precision floating point number.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for Half conversions and some low level operations.
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace AssetStudio
|
||||
public uint byteSize;
|
||||
public int typeID;
|
||||
public int classID;
|
||||
public ushort isDestroyed;
|
||||
public byte stripped;
|
||||
|
||||
public long m_PathID;
|
||||
public SerializedType serializedType;
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace AssetStudio
|
||||
public ClassIDType type;
|
||||
public SerializedType serializedType;
|
||||
public BuildTarget platform;
|
||||
public uint m_Version;
|
||||
public SerializedFileFormatVersion m_Version;
|
||||
|
||||
public int[] version => assetsFile.version;
|
||||
public BuildType buildType => assetsFile.buildType;
|
||||
|
||||
public ObjectReader(EndianBinaryReader reader, SerializedFile assetsFile, ObjectInfo objectInfo) : base(reader.BaseStream, reader.endian)
|
||||
public ObjectReader(EndianBinaryReader reader, SerializedFile assetsFile, ObjectInfo objectInfo) : base(reader.BaseStream, reader.Endian)
|
||||
{
|
||||
this.assetsFile = assetsFile;
|
||||
m_PathID = objectInfo.m_PathID;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace AssetStudio
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class Progress
|
||||
{
|
||||
public static IProgress Default = new DummyProgress();
|
||||
public static IProgress<int> Default = new Progress<int>();
|
||||
private static int preValue;
|
||||
|
||||
public static void Reset()
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("AssetStudio")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("AssetStudio")]
|
||||
[assembly: AssemblyCopyright("Copyright © Perfare 2018-2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("7662f8c2-7bfd-442e-a948-a43b4f7eb06e")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -8,11 +8,12 @@ namespace AssetStudio
|
||||
private string path;
|
||||
private SerializedFile assetsFile;
|
||||
private long offset;
|
||||
private int size;
|
||||
private long size;
|
||||
private BinaryReader reader;
|
||||
|
||||
public int Size { get => (int)size; }
|
||||
|
||||
public ResourceReader(string path, SerializedFile assetsFile, long offset, int size)
|
||||
public ResourceReader(string path, SerializedFile assetsFile, long offset, long size)
|
||||
{
|
||||
needSearch = true;
|
||||
this.path = path;
|
||||
@@ -21,28 +22,25 @@ namespace AssetStudio
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public ResourceReader(BinaryReader reader, long offset, int size)
|
||||
public ResourceReader(BinaryReader reader, long offset, long size)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public byte[] GetData()
|
||||
private BinaryReader GetReader()
|
||||
{
|
||||
if (needSearch)
|
||||
{
|
||||
var resourceFileName = Path.GetFileName(path);
|
||||
|
||||
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName, out reader))
|
||||
{
|
||||
needSearch = false;
|
||||
reader.BaseStream.Position = offset;
|
||||
return reader.ReadBytes(size);
|
||||
return reader;
|
||||
}
|
||||
|
||||
var assetsFileDirectory = Path.GetDirectoryName(assetsFile.fullName);
|
||||
var resourceFilePath = assetsFileDirectory + Path.DirectorySeparatorChar + resourceFileName;
|
||||
var resourceFilePath = Path.Combine(assetsFileDirectory, resourceFileName);
|
||||
if (!File.Exists(resourceFilePath))
|
||||
{
|
||||
var findFiles = Directory.GetFiles(assetsFileDirectory, resourceFileName, SearchOption.AllDirectories);
|
||||
@@ -53,18 +51,41 @@ namespace AssetStudio
|
||||
}
|
||||
if (File.Exists(resourceFilePath))
|
||||
{
|
||||
reader = new BinaryReader(File.OpenRead(resourceFilePath));
|
||||
needSearch = false;
|
||||
reader = new BinaryReader(File.OpenRead(resourceFilePath));
|
||||
assetsFile.assetsManager.resourceFileReaders.Add(resourceFileName, reader);
|
||||
reader.BaseStream.Position = offset;
|
||||
return reader.ReadBytes(size);
|
||||
return reader;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException($"Can't find the resource file {resourceFileName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = offset;
|
||||
return reader.ReadBytes(size);
|
||||
public byte[] GetData()
|
||||
{
|
||||
var binaryReader = GetReader();
|
||||
binaryReader.BaseStream.Position = offset;
|
||||
return binaryReader.ReadBytes((int)size);
|
||||
}
|
||||
|
||||
public void GetData(byte[] buff)
|
||||
{
|
||||
var binaryReader = GetReader();
|
||||
binaryReader.BaseStream.Position = offset;
|
||||
binaryReader.Read(buff, 0, (int)size);
|
||||
}
|
||||
|
||||
public void WriteData(string path)
|
||||
{
|
||||
var binaryReader = GetReader();
|
||||
binaryReader.BaseStream.Position = offset;
|
||||
using (var writer = File.OpenWrite(path))
|
||||
{
|
||||
binaryReader.BaseStream.CopyTo(writer, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace AssetStudio
|
||||
public class SerializedFile
|
||||
{
|
||||
public AssetsManager assetsManager;
|
||||
public EndianBinaryReader reader;
|
||||
public FileReader reader;
|
||||
public string fullName;
|
||||
public string originalPath;
|
||||
public string fileName;
|
||||
@@ -19,43 +19,45 @@ namespace AssetStudio
|
||||
public Dictionary<long, Object> ObjectsDic;
|
||||
|
||||
public SerializedFileHeader header;
|
||||
private EndianType m_FileEndianess;
|
||||
private byte m_FileEndianess;
|
||||
public string unityVersion = "2.5.0f5";
|
||||
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
|
||||
private bool m_EnableTypeTree = true;
|
||||
public List<SerializedType> m_Types;
|
||||
public List<SerializedType> m_RefTypes;
|
||||
public int bigIDEnabled = 0;
|
||||
public List<ObjectInfo> m_Objects;
|
||||
private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
|
||||
public List<FileIdentifier> m_Externals;
|
||||
public List<SerializedType> m_RefTypes;
|
||||
public string userInformation;
|
||||
|
||||
public SerializedFile(AssetsManager assetsManager, string fullName, EndianBinaryReader reader)
|
||||
public SerializedFile(FileReader reader, AssetsManager assetsManager)
|
||||
{
|
||||
this.assetsManager = assetsManager;
|
||||
this.reader = reader;
|
||||
this.fullName = fullName;
|
||||
fileName = Path.GetFileName(fullName);
|
||||
fullName = reader.FullPath;
|
||||
fileName = reader.FileName;
|
||||
|
||||
//ReadHeader
|
||||
// ReadHeader
|
||||
header = new SerializedFileHeader();
|
||||
header.m_MetadataSize = reader.ReadUInt32();
|
||||
header.m_FileSize = reader.ReadUInt32();
|
||||
header.m_Version = reader.ReadUInt32();
|
||||
header.m_Version = (SerializedFileFormatVersion)reader.ReadUInt32();
|
||||
header.m_DataOffset = reader.ReadUInt32();
|
||||
|
||||
if (header.m_Version >= 9)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_9)
|
||||
{
|
||||
header.m_Endianess = reader.ReadByte();
|
||||
header.m_Reserved = reader.ReadBytes(3);
|
||||
m_FileEndianess = (EndianType)header.m_Endianess;
|
||||
m_FileEndianess = header.m_Endianess;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Position = header.m_FileSize - header.m_MetadataSize;
|
||||
m_FileEndianess = (EndianType)reader.ReadByte();
|
||||
m_FileEndianess = reader.ReadByte();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 22)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.LargeFilesSupport)
|
||||
{
|
||||
header.m_MetadataSize = reader.ReadUInt32();
|
||||
header.m_FileSize = reader.ReadInt64();
|
||||
@@ -63,17 +65,17 @@ namespace AssetStudio
|
||||
reader.ReadInt64(); // unknown
|
||||
}
|
||||
|
||||
//ReadMetadata
|
||||
if (m_FileEndianess == EndianType.LittleEndian)
|
||||
// ReadMetadata
|
||||
if (m_FileEndianess == 0)
|
||||
{
|
||||
reader.endian = EndianType.LittleEndian;
|
||||
reader.Endian = EndianType.LittleEndian;
|
||||
}
|
||||
if (header.m_Version >= 7)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7)
|
||||
{
|
||||
unityVersion = reader.ReadStringToNull();
|
||||
SetVersion(unityVersion);
|
||||
}
|
||||
if (header.m_Version >= 8)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_8)
|
||||
{
|
||||
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
|
||||
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
|
||||
@@ -81,26 +83,25 @@ namespace AssetStudio
|
||||
m_TargetPlatform = BuildTarget.UnknownPlatform;
|
||||
}
|
||||
}
|
||||
if (header.m_Version >= 13)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.HasTypeTreeHashes)
|
||||
{
|
||||
m_EnableTypeTree = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
//ReadTypes
|
||||
// Read Types
|
||||
int typeCount = reader.ReadInt32();
|
||||
m_Types = new List<SerializedType>(typeCount);
|
||||
for (int i = 0; i < typeCount; i++)
|
||||
{
|
||||
m_Types.Add(ReadSerializedType());
|
||||
m_Types.Add(ReadSerializedType(false));
|
||||
}
|
||||
|
||||
var bigIDEnabled = 0;
|
||||
if (header.m_Version >= 7 && header.m_Version < 14)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7 && header.m_Version < SerializedFileFormatVersion.Unknown_14)
|
||||
{
|
||||
bigIDEnabled = reader.ReadInt32();
|
||||
}
|
||||
|
||||
//ReadObjects
|
||||
// Read Objects
|
||||
int objectCount = reader.ReadInt32();
|
||||
m_Objects = new List<ObjectInfo>(objectCount);
|
||||
Objects = new List<Object>(objectCount);
|
||||
@@ -112,7 +113,7 @@ namespace AssetStudio
|
||||
{
|
||||
objectInfo.m_PathID = reader.ReadInt64();
|
||||
}
|
||||
else if (header.m_Version < 14)
|
||||
else if (header.m_Version < SerializedFileFormatVersion.Unknown_14)
|
||||
{
|
||||
objectInfo.m_PathID = reader.ReadInt32();
|
||||
}
|
||||
@@ -122,7 +123,7 @@ namespace AssetStudio
|
||||
objectInfo.m_PathID = reader.ReadInt64();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 22)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.LargeFilesSupport)
|
||||
objectInfo.byteStart = reader.ReadInt64();
|
||||
else
|
||||
objectInfo.byteStart = reader.ReadUInt32();
|
||||
@@ -130,7 +131,7 @@ namespace AssetStudio
|
||||
objectInfo.byteStart += header.m_DataOffset;
|
||||
objectInfo.byteSize = reader.ReadUInt32();
|
||||
objectInfo.typeID = reader.ReadInt32();
|
||||
if (header.m_Version < 16)
|
||||
if (header.m_Version < SerializedFileFormatVersion.RefactoredClassId)
|
||||
{
|
||||
objectInfo.classID = reader.ReadUInt16();
|
||||
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
|
||||
@@ -141,24 +142,24 @@ namespace AssetStudio
|
||||
objectInfo.serializedType = type;
|
||||
objectInfo.classID = type.classID;
|
||||
}
|
||||
if (header.m_Version < 11)
|
||||
if (header.m_Version < SerializedFileFormatVersion.HasScriptTypeIndex)
|
||||
{
|
||||
var isDestroyed = reader.ReadUInt16();
|
||||
objectInfo.isDestroyed = reader.ReadUInt16();
|
||||
}
|
||||
if (header.m_Version >= 11 && header.m_Version < 17)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.HasScriptTypeIndex && header.m_Version < SerializedFileFormatVersion.RefactorTypeData)
|
||||
{
|
||||
var m_ScriptTypeIndex = reader.ReadInt16();
|
||||
if (objectInfo.serializedType != null)
|
||||
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
|
||||
}
|
||||
if (header.m_Version == 15 || header.m_Version == 16)
|
||||
if (header.m_Version == SerializedFileFormatVersion.SupportsStrippedObject || header.m_Version == SerializedFileFormatVersion.RefactoredClassId)
|
||||
{
|
||||
var stripped = reader.ReadByte();
|
||||
objectInfo.stripped = reader.ReadByte();
|
||||
}
|
||||
m_Objects.Add(objectInfo);
|
||||
}
|
||||
|
||||
if (header.m_Version >= 11)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.HasScriptTypeIndex)
|
||||
{
|
||||
int scriptCount = reader.ReadInt32();
|
||||
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
|
||||
@@ -166,7 +167,7 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ScriptType = new LocalSerializedObjectIdentifier();
|
||||
m_ScriptType.localSerializedFileIndex = reader.ReadInt32();
|
||||
if (header.m_Version < 14)
|
||||
if (header.m_Version < SerializedFileFormatVersion.Unknown_14)
|
||||
{
|
||||
m_ScriptType.localIdentifierInFile = reader.ReadInt32();
|
||||
}
|
||||
@@ -184,11 +185,11 @@ namespace AssetStudio
|
||||
for (int i = 0; i < externalsCount; i++)
|
||||
{
|
||||
var m_External = new FileIdentifier();
|
||||
if (header.m_Version >= 6)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_6)
|
||||
{
|
||||
var tempEmpty = reader.ReadStringToNull();
|
||||
}
|
||||
if (header.m_Version >= 5)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_5)
|
||||
{
|
||||
m_External.guid = new Guid(reader.ReadBytes(16));
|
||||
m_External.type = reader.ReadInt32();
|
||||
@@ -198,19 +199,19 @@ namespace AssetStudio
|
||||
m_Externals.Add(m_External);
|
||||
}
|
||||
|
||||
if (header.m_Version >= 20)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.SupportsRefObject)
|
||||
{
|
||||
int refTypesCount = reader.ReadInt32();
|
||||
m_RefTypes = new List<SerializedType>(refTypesCount);
|
||||
for (int i = 0; i < refTypesCount; i++)
|
||||
{
|
||||
m_RefTypes.Add(ReadSerializedType());
|
||||
m_RefTypes.Add(ReadSerializedType(true));
|
||||
}
|
||||
}
|
||||
|
||||
if (header.m_Version >= 5)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_5)
|
||||
{
|
||||
var userInformation = reader.ReadStringToNull();
|
||||
userInformation = reader.ReadStringToNull();
|
||||
}
|
||||
|
||||
//reader.AlignStream(16);
|
||||
@@ -218,80 +219,98 @@ namespace AssetStudio
|
||||
|
||||
public void SetVersion(string stringVersion)
|
||||
{
|
||||
unityVersion = stringVersion;
|
||||
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
buildType = new BuildType(buildSplit[0]);
|
||||
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
version = versionSplit.Select(int.Parse).ToArray();
|
||||
if (stringVersion != strippedVersion)
|
||||
{
|
||||
unityVersion = stringVersion;
|
||||
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (buildSplit.Length == 0)
|
||||
throw new NotSupportedException("Specified Unity version is not in a correct format.\n" +
|
||||
"Specify full Unity version, including letters at the end.\n" +
|
||||
"Example: 2017.4.39f1");
|
||||
buildType = new BuildType(buildSplit[0]);
|
||||
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
version = versionSplit.Select(int.Parse).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedType ReadSerializedType()
|
||||
private SerializedType ReadSerializedType(bool isRefType)
|
||||
{
|
||||
var type = new SerializedType();
|
||||
|
||||
type.classID = reader.ReadInt32();
|
||||
|
||||
if (header.m_Version >= 16)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.RefactoredClassId)
|
||||
{
|
||||
type.m_IsStrippedType = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 17)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.RefactorTypeData)
|
||||
{
|
||||
type.m_ScriptTypeIndex = reader.ReadInt16();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 13)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.HasTypeTreeHashes)
|
||||
{
|
||||
if ((header.m_Version < 16 && type.classID < 0) || (header.m_Version >= 16 && type.classID == 114))
|
||||
if (isRefType && type.m_ScriptTypeIndex >= 0)
|
||||
{
|
||||
type.m_ScriptID = reader.ReadBytes(16); //Hash128
|
||||
type.m_ScriptID = reader.ReadBytes(16);
|
||||
}
|
||||
type.m_OldTypeHash = reader.ReadBytes(16); //Hash128
|
||||
else if ((header.m_Version < SerializedFileFormatVersion.RefactoredClassId && type.classID < 0) || (header.m_Version >= SerializedFileFormatVersion.RefactoredClassId && type.classID == 114))
|
||||
{
|
||||
type.m_ScriptID = reader.ReadBytes(16);
|
||||
}
|
||||
type.m_OldTypeHash = reader.ReadBytes(16);
|
||||
}
|
||||
|
||||
if (m_EnableTypeTree)
|
||||
{
|
||||
var typeTree = new List<TypeTreeNode>();
|
||||
if (header.m_Version >= 12 || header.m_Version == 10)
|
||||
type.m_Type = new TypeTree();
|
||||
type.m_Type.m_Nodes = new List<TypeTreeNode>();
|
||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_12 || header.m_Version == SerializedFileFormatVersion.Unknown_10)
|
||||
{
|
||||
TypeTreeBlobRead(typeTree);
|
||||
TypeTreeBlobRead(type.m_Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadTypeTree(typeTree);
|
||||
ReadTypeTree(type.m_Type);
|
||||
}
|
||||
|
||||
if (header.m_Version >= 21)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.StoresTypeDependencies)
|
||||
{
|
||||
type.m_TypeDependencies = reader.ReadInt32Array();
|
||||
if (isRefType)
|
||||
{
|
||||
type.m_KlassName = reader.ReadStringToNull();
|
||||
type.m_NameSpace = reader.ReadStringToNull();
|
||||
type.m_AsmName = reader.ReadStringToNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
type.m_TypeDependencies = reader.ReadInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
type.m_Nodes = typeTree;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private void ReadTypeTree(List<TypeTreeNode> typeTree, int level = 0)
|
||||
private void ReadTypeTree(TypeTree m_Type, int level = 0)
|
||||
{
|
||||
var typeTreeNode = new TypeTreeNode();
|
||||
typeTree.Add(typeTreeNode);
|
||||
m_Type.m_Nodes.Add(typeTreeNode);
|
||||
typeTreeNode.m_Level = level;
|
||||
typeTreeNode.m_Type = reader.ReadStringToNull();
|
||||
typeTreeNode.m_Name = reader.ReadStringToNull();
|
||||
typeTreeNode.m_ByteSize = reader.ReadInt32();
|
||||
if (header.m_Version == 2)
|
||||
if (header.m_Version == SerializedFileFormatVersion.Unknown_2)
|
||||
{
|
||||
var variableCount = reader.ReadInt32();
|
||||
}
|
||||
if (header.m_Version != 3)
|
||||
if (header.m_Version != SerializedFileFormatVersion.Unknown_3)
|
||||
{
|
||||
typeTreeNode.m_Index = reader.ReadInt32();
|
||||
}
|
||||
typeTreeNode.m_IsArray = reader.ReadInt32();
|
||||
typeTreeNode.m_TypeFlags = reader.ReadInt32();
|
||||
typeTreeNode.m_Version = reader.ReadInt32();
|
||||
if (header.m_Version != 3)
|
||||
if (header.m_Version != SerializedFileFormatVersion.Unknown_3)
|
||||
{
|
||||
typeTreeNode.m_MetaFlag = reader.ReadInt32();
|
||||
}
|
||||
@@ -299,40 +318,40 @@ namespace AssetStudio
|
||||
int childrenCount = reader.ReadInt32();
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
ReadTypeTree(typeTree, level + 1);
|
||||
ReadTypeTree(m_Type, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void TypeTreeBlobRead(List<TypeTreeNode> typeTree)
|
||||
private void TypeTreeBlobRead(TypeTree m_Type)
|
||||
{
|
||||
int numberOfNodes = reader.ReadInt32();
|
||||
int stringBufferSize = reader.ReadInt32();
|
||||
for (int i = 0; i < numberOfNodes; i++)
|
||||
{
|
||||
var typeTreeNode = new TypeTreeNode();
|
||||
typeTree.Add(typeTreeNode);
|
||||
m_Type.m_Nodes.Add(typeTreeNode);
|
||||
typeTreeNode.m_Version = reader.ReadUInt16();
|
||||
typeTreeNode.m_Level = reader.ReadByte();
|
||||
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
|
||||
typeTreeNode.m_TypeFlags = reader.ReadByte();
|
||||
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_ByteSize = reader.ReadInt32();
|
||||
typeTreeNode.m_Index = reader.ReadInt32();
|
||||
typeTreeNode.m_MetaFlag = reader.ReadInt32();
|
||||
if (header.m_Version >= 19)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.TypeTreeNodeWithTypeFlags)
|
||||
{
|
||||
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
|
||||
}
|
||||
}
|
||||
var m_StringBuffer = reader.ReadBytes(stringBufferSize);
|
||||
m_Type.m_StringBuffer = reader.ReadBytes(stringBufferSize);
|
||||
|
||||
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_StringBuffer)))
|
||||
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_Type.m_StringBuffer)))
|
||||
{
|
||||
for (int i = 0; i < numberOfNodes; i++)
|
||||
{
|
||||
var typeTreeNode = typeTree[i];
|
||||
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
|
||||
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
|
||||
var m_Node = m_Type.m_Nodes[i];
|
||||
m_Node.m_Type = ReadString(stringBufferReader, m_Node.m_TypeStrOffset);
|
||||
m_Node.m_Name = ReadString(stringBufferReader, m_Node.m_NameStrOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,41 +378,8 @@ namespace AssetStudio
|
||||
ObjectsDic.Add(obj.m_PathID, obj);
|
||||
}
|
||||
|
||||
public static bool IsSerializedFile(EndianBinaryReader reader)
|
||||
{
|
||||
var fileSize = reader.BaseStream.Length;
|
||||
if (fileSize < 20)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var m_MetadataSize = reader.ReadUInt32();
|
||||
long m_FileSize = reader.ReadUInt32();
|
||||
var m_Version = reader.ReadUInt32();
|
||||
long m_DataOffset = reader.ReadUInt32();
|
||||
var m_Endianess = reader.ReadByte();
|
||||
var m_Reserved = reader.ReadBytes(3);
|
||||
if (m_Version >= 22)
|
||||
{
|
||||
if (fileSize < 48)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_MetadataSize = reader.ReadUInt32();
|
||||
m_FileSize = reader.ReadInt64();
|
||||
m_DataOffset = reader.ReadInt64();
|
||||
}
|
||||
if (m_FileSize != fileSize)
|
||||
{
|
||||
reader.Position = 0;
|
||||
return false;
|
||||
}
|
||||
if (m_DataOffset > fileSize)
|
||||
{
|
||||
reader.Position = 0;
|
||||
return false;
|
||||
}
|
||||
reader.Position = 0;
|
||||
return true;
|
||||
}
|
||||
public bool IsVersionStripped => unityVersion == strippedVersion;
|
||||
|
||||
private const string strippedVersion = "0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
87
AssetStudio/SerializedFileFormatVersion.cs
Normal file
87
AssetStudio/SerializedFileFormatVersion.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum SerializedFileFormatVersion
|
||||
{
|
||||
Unsupported = 1,
|
||||
Unknown_2 = 2,
|
||||
Unknown_3 = 3,
|
||||
/// <summary>
|
||||
/// 1.2.0 to 2.0.0
|
||||
/// </summary>
|
||||
Unknown_5 = 5,
|
||||
/// <summary>
|
||||
/// 2.1.0 to 2.6.1
|
||||
/// </summary>
|
||||
Unknown_6 = 6,
|
||||
/// <summary>
|
||||
/// 3.0.0b
|
||||
/// </summary>
|
||||
Unknown_7 = 7,
|
||||
/// <summary>
|
||||
/// 3.0.0 to 3.4.2
|
||||
/// </summary>
|
||||
Unknown_8 = 8,
|
||||
/// <summary>
|
||||
/// 3.5.0 to 4.7.2
|
||||
/// </summary>
|
||||
Unknown_9 = 9,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk1
|
||||
/// </summary>
|
||||
Unknown_10 = 10,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk2
|
||||
/// </summary>
|
||||
HasScriptTypeIndex = 11,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk3
|
||||
/// </summary>
|
||||
Unknown_12 = 12,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk4
|
||||
/// </summary>
|
||||
HasTypeTreeHashes = 13,
|
||||
/// <summary>
|
||||
/// 5.0.0unk
|
||||
/// </summary>
|
||||
Unknown_14 = 14,
|
||||
/// <summary>
|
||||
/// 5.0.1 to 5.4.0
|
||||
/// </summary>
|
||||
SupportsStrippedObject = 15,
|
||||
/// <summary>
|
||||
/// 5.5.0a
|
||||
/// </summary>
|
||||
RefactoredClassId = 16,
|
||||
/// <summary>
|
||||
/// 5.5.0unk to 2018.4
|
||||
/// </summary>
|
||||
RefactorTypeData = 17,
|
||||
/// <summary>
|
||||
/// 2019.1a
|
||||
/// </summary>
|
||||
RefactorShareableTypeTreeData = 18,
|
||||
/// <summary>
|
||||
/// 2019.1unk
|
||||
/// </summary>
|
||||
TypeTreeNodeWithTypeFlags = 19,
|
||||
/// <summary>
|
||||
/// 2019.2
|
||||
/// </summary>
|
||||
SupportsRefObject = 20,
|
||||
/// <summary>
|
||||
/// 2019.3 to 2019.4
|
||||
/// </summary>
|
||||
StoresTypeDependencies = 21,
|
||||
/// <summary>
|
||||
/// 2020.1 to x
|
||||
/// </summary>
|
||||
LargeFilesSupport = 22
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace AssetStudio
|
||||
{
|
||||
public uint m_MetadataSize;
|
||||
public long m_FileSize;
|
||||
public uint m_Version;
|
||||
public SerializedFileFormatVersion m_Version;
|
||||
public long m_DataOffset;
|
||||
public byte m_Endianess;
|
||||
public byte[] m_Reserved;
|
||||
|
||||
@@ -10,9 +10,12 @@ namespace AssetStudio
|
||||
public int classID;
|
||||
public bool m_IsStrippedType;
|
||||
public short m_ScriptTypeIndex = -1;
|
||||
public List<TypeTreeNode> m_Nodes;
|
||||
public TypeTree m_Type;
|
||||
public byte[] m_ScriptID; //Hash128
|
||||
public byte[] m_OldTypeHash; //Hash128
|
||||
public int[] m_TypeDependencies;
|
||||
public string m_KlassName;
|
||||
public string m_NameSpace;
|
||||
public string m_AsmName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,16 @@ namespace AssetStudio
|
||||
return newOutStream;
|
||||
}
|
||||
|
||||
public static void StreamDecompress(Stream inStream, Stream outStream, long inSize, long outSize)
|
||||
public static void StreamDecompress(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize)
|
||||
{
|
||||
var basePosition = compressedStream.Position;
|
||||
var decoder = new Decoder();
|
||||
var properties = new byte[5];
|
||||
if (inStream.Read(properties, 0, 5) != 5)
|
||||
if (compressedStream.Read(properties, 0, 5) != 5)
|
||||
throw new Exception("input .lzma is too short");
|
||||
decoder.SetDecoderProperties(properties);
|
||||
inSize -= 5L;
|
||||
decoder.Code(inStream, outStream, inSize, outSize, null);
|
||||
decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
|
||||
compressedStream.Position = basePosition + compressedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace AssetStudio
|
||||
{
|
||||
public class StreamFile
|
||||
{
|
||||
public string path;
|
||||
public string fileName;
|
||||
public Stream stream;
|
||||
}
|
||||
|
||||
14
AssetStudio/TypeTree.cs
Normal file
14
AssetStudio/TypeTree.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class TypeTree
|
||||
{
|
||||
public List<TypeTreeNode> m_Nodes;
|
||||
public byte[] m_StringBuffer;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class TypeTreeHelper
|
||||
{
|
||||
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader)
|
||||
public static string ReadTypeString(TypeTree m_Type, ObjectReader reader)
|
||||
{
|
||||
for (int i = 0; i < members.Count; i++)
|
||||
reader.Reset();
|
||||
var sb = new StringBuilder();
|
||||
var m_Nodes = m_Type.m_Nodes;
|
||||
for (int i = 0; i < m_Nodes.Count; i++)
|
||||
{
|
||||
ReadStringValue(sb, members, reader, ref i);
|
||||
ReadStringValue(sb, m_Nodes, reader, ref i);
|
||||
}
|
||||
var readed = reader.Position - reader.byteStart;
|
||||
if (readed != reader.byteSize)
|
||||
{
|
||||
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i)
|
||||
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
|
||||
{
|
||||
var member = members[i];
|
||||
var level = member.m_Level;
|
||||
var varTypeStr = member.m_Type;
|
||||
var varNameStr = member.m_Name;
|
||||
var m_Node = m_Nodes[i];
|
||||
var level = m_Node.m_Level;
|
||||
var varTypeStr = m_Node.m_Type;
|
||||
var varNameStr = m_Node.m_Name;
|
||||
object value = null;
|
||||
var append = true;
|
||||
var align = (member.m_MetaFlag & 0x4000) != 0;
|
||||
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
||||
switch (varTypeStr)
|
||||
{
|
||||
case "SInt8":
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "UInt8":
|
||||
case "char":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "char":
|
||||
value = BitConverter.ToChar(reader.ReadBytes(2), 0);
|
||||
break;
|
||||
case "short":
|
||||
case "SInt16":
|
||||
value = reader.ReadInt16();
|
||||
@@ -73,22 +84,23 @@ namespace AssetStudio
|
||||
append = false;
|
||||
var str = reader.ReadAlignedString();
|
||||
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str);
|
||||
i += 3;
|
||||
var toSkip = GetNodes(m_Nodes, i);
|
||||
i += toSkip.Count - 1;
|
||||
break;
|
||||
case "map":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
|
||||
var map = GetMembers(members, i);
|
||||
var map = GetNodes(m_Nodes, i);
|
||||
i += map.Count - 1;
|
||||
var first = GetMembers(map, 4);
|
||||
var first = GetNodes(map, 4);
|
||||
var next = 4 + first.Count;
|
||||
var second = GetMembers(map, next);
|
||||
var second = GetNodes(map, next);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
|
||||
@@ -112,16 +124,16 @@ namespace AssetStudio
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
|
||||
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
|
||||
var vector = GetMembers(members, i);
|
||||
var vector = GetNodes(m_Nodes, i);
|
||||
i += vector.Count - 1;
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
@@ -135,7 +147,7 @@ namespace AssetStudio
|
||||
{
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
var @class = GetMembers(members, i);
|
||||
var @class = GetNodes(m_Nodes, i);
|
||||
i += @class.Count - 1;
|
||||
for (int j = 1; j < @class.Count; j++)
|
||||
{
|
||||
@@ -151,33 +163,42 @@ namespace AssetStudio
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
public static UType ReadUType(List<TypeTreeNode> members, BinaryReader reader)
|
||||
public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader)
|
||||
{
|
||||
var obj = new UType();
|
||||
for (int i = 1; i < members.Count; i++)
|
||||
reader.Reset();
|
||||
var obj = new OrderedDictionary();
|
||||
var m_Nodes = m_Types.m_Nodes;
|
||||
for (int i = 1; i < m_Nodes.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var varNameStr = member.m_Name;
|
||||
obj[varNameStr] = ReadValue(members, reader, ref i);
|
||||
var m_Node = m_Nodes[i];
|
||||
var varNameStr = m_Node.m_Name;
|
||||
obj[varNameStr] = ReadValue(m_Nodes, reader, ref i);
|
||||
}
|
||||
var readed = reader.Position - reader.byteStart;
|
||||
if (readed != reader.byteSize)
|
||||
{
|
||||
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
|
||||
private static object ReadValue(List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
|
||||
{
|
||||
var member = members[i];
|
||||
var varTypeStr = member.m_Type;
|
||||
var m_Node = m_Nodes[i];
|
||||
var varTypeStr = m_Node.m_Type;
|
||||
object value;
|
||||
var align = (member.m_MetaFlag & 0x4000) != 0;
|
||||
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
||||
switch (varTypeStr)
|
||||
{
|
||||
case "SInt8":
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "UInt8":
|
||||
case "char":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "char":
|
||||
value = BitConverter.ToChar(reader.ReadBytes(2), 0);
|
||||
break;
|
||||
case "short":
|
||||
case "SInt16":
|
||||
value = reader.ReadInt16();
|
||||
@@ -215,17 +236,18 @@ namespace AssetStudio
|
||||
break;
|
||||
case "string":
|
||||
value = reader.ReadAlignedString();
|
||||
i += 3;
|
||||
var toSkip = GetNodes(m_Nodes, i);
|
||||
i += toSkip.Count - 1;
|
||||
break;
|
||||
case "map":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var map = GetMembers(members, i);
|
||||
var map = GetNodes(m_Nodes, i);
|
||||
i += map.Count - 1;
|
||||
var first = GetMembers(map, 4);
|
||||
var first = GetNodes(map, 4);
|
||||
var next = 4 + first.Count;
|
||||
var second = GetMembers(map, next);
|
||||
var second = GetNodes(map, next);
|
||||
var size = reader.ReadInt32();
|
||||
var dic = new List<KeyValuePair<object, object>>(size);
|
||||
for (int j = 0; j < size; j++)
|
||||
@@ -246,11 +268,11 @@ namespace AssetStudio
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
|
||||
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var vector = GetMembers(members, i);
|
||||
var vector = GetNodes(m_Nodes, i);
|
||||
i += vector.Count - 1;
|
||||
var size = reader.ReadInt32();
|
||||
var list = new List<object>(size);
|
||||
@@ -264,9 +286,9 @@ namespace AssetStudio
|
||||
}
|
||||
else //Class
|
||||
{
|
||||
var @class = GetMembers(members, i);
|
||||
var @class = GetNodes(m_Nodes, i);
|
||||
i += @class.Count - 1;
|
||||
var obj = new UType();
|
||||
var obj = new OrderedDictionary();
|
||||
for (int j = 1; j < @class.Count; j++)
|
||||
{
|
||||
var classmember = @class[j];
|
||||
@@ -283,22 +305,22 @@ namespace AssetStudio
|
||||
return value;
|
||||
}
|
||||
|
||||
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index)
|
||||
private static List<TypeTreeNode> GetNodes(List<TypeTreeNode> m_Nodes, int index)
|
||||
{
|
||||
var member2 = new List<TypeTreeNode>();
|
||||
member2.Add(members[index]);
|
||||
var level = members[index].m_Level;
|
||||
for (int i = index + 1; i < members.Count; i++)
|
||||
var nodes = new List<TypeTreeNode>();
|
||||
nodes.Add(m_Nodes[index]);
|
||||
var level = m_Nodes[index].m_Level;
|
||||
for (int i = index + 1; i < m_Nodes.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var member = m_Nodes[i];
|
||||
var level2 = member.m_Level;
|
||||
if (level2 <= level)
|
||||
{
|
||||
return member2;
|
||||
return nodes;
|
||||
}
|
||||
member2.Add(member);
|
||||
nodes.Add(member);
|
||||
}
|
||||
return member2;
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,22 @@ namespace AssetStudio
|
||||
public string m_Name;
|
||||
public int m_ByteSize;
|
||||
public int m_Index;
|
||||
public int m_IsArray; //m_TypeFlags
|
||||
public int m_TypeFlags; //m_IsArray
|
||||
public int m_Version;
|
||||
public int m_MetaFlag;
|
||||
public int m_Level;
|
||||
public uint m_TypeStrOffset;
|
||||
public uint m_NameStrOffset;
|
||||
public ulong m_RefTypeHash;
|
||||
|
||||
public TypeTreeNode() { }
|
||||
|
||||
public TypeTreeNode(string type, string name, int level, bool align)
|
||||
{
|
||||
m_Type = type;
|
||||
m_Name = name;
|
||||
m_Level = level;
|
||||
m_MetaFlag = align ? 0x4000 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class UType : IDictionary<string, object>
|
||||
{
|
||||
private List<string> keys;
|
||||
private IDictionary<string, object> values;
|
||||
|
||||
public UType()
|
||||
{
|
||||
keys = new List<string>();
|
||||
values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!values.ContainsKey(key))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return values[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!values.ContainsKey(key))
|
||||
{
|
||||
keys.Add(key);
|
||||
}
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Keys => keys;
|
||||
|
||||
public ICollection<object> Values => values.Values;
|
||||
|
||||
public int Count => keys.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public void Add(string key, object value)
|
||||
{
|
||||
keys.Add(key);
|
||||
values.Add(key, value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, object> item)
|
||||
{
|
||||
keys.Add(item.Key);
|
||||
values.Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
keys.Clear();
|
||||
values.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, object> item)
|
||||
{
|
||||
return values.Contains(item);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return values.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
||||
{
|
||||
values.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
return values.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
keys.Remove(key);
|
||||
return values.Remove(key);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, object> item)
|
||||
{
|
||||
keys.Remove(item.Key);
|
||||
return values.Remove(item);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out object value)
|
||||
{
|
||||
return values.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return values.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Org.Brotli.Dec;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class WebFile
|
||||
{
|
||||
public static byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
public static byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
public StreamFile[] fileList;
|
||||
|
||||
private class WebData
|
||||
@@ -23,50 +17,8 @@ namespace AssetStudio
|
||||
|
||||
public WebFile(EndianBinaryReader reader)
|
||||
{
|
||||
var magic = reader.ReadBytes(2);
|
||||
reader.Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream))
|
||||
{
|
||||
ReadWebData(binaryReader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Position = 0x20;
|
||||
magic = reader.ReadBytes(6);
|
||||
reader.Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
var brotliStream = new BrotliInputStream(reader.BaseStream);
|
||||
var stream = new MemoryStream();
|
||||
brotliStream.CopyTo(stream);
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream))
|
||||
{
|
||||
ReadWebData(binaryReader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.endian = EndianType.LittleEndian;
|
||||
ReadWebData(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadWebData(BinaryReader reader)
|
||||
{
|
||||
reader.Endian = EndianType.LittleEndian;
|
||||
var signature = reader.ReadStringToNull();
|
||||
if (signature != "UnityWebData1.0")
|
||||
return;
|
||||
var headLength = reader.ReadInt32();
|
||||
var dataList = new List<WebData>();
|
||||
while (reader.BaseStream.Position < headLength)
|
||||
@@ -83,6 +35,7 @@ namespace AssetStudio
|
||||
{
|
||||
var data = dataList[i];
|
||||
var file = new StreamFile();
|
||||
file.path = data.path;
|
||||
file.fileName = Path.GetFileName(data.path);
|
||||
reader.BaseStream.Position = data.dataOffset;
|
||||
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));
|
||||
|
||||
97
AssetStudioCLI/AssetStudioCLI.csproj
Normal file
97
AssetStudioCLI/AssetStudioCLI.csproj
Normal file
@@ -0,0 +1,97 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
|
||||
<AssemblyTitle>AssetStudioMod by aelurum</AssemblyTitle>
|
||||
<AssemblyName>AssetStudioModCLI</AssemblyName>
|
||||
<Version>0.17.2.0</Version>
|
||||
<Copyright>Copyright © Perfare; Copyright © aelurum 2023</Copyright>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</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 windows 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 other platforms extra files for $(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>
|
||||
|
||||
<!-- 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 windows 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 other platforms extra files for Portable 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="CopyExtraFilesMac" AfterTargets="AfterBuild" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
|
||||
<Message Text="Copying extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(ProjectDir)Libraries\$(RuntimeIdentifier)\libfmod.dylib" DestinationFolder="$(TargetDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishExtraFilesMac" AfterTargets="Publish" Condition=" $(RuntimeIdentifier.Contains('osx-')) ">
|
||||
<Message Text="Publishing extra files for $(RuntimeIdentifier)($(TargetFramework))... " Importance="high" />
|
||||
<Copy SourceFiles="$(TargetDir)\libfmod.dylib" DestinationFolder="$(PublishDir)" ContinueOnError="false" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
118
AssetStudioCLI/CLILogger.cs
Normal file
118
AssetStudioCLI/CLILogger.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
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()
|
||||
{
|
||||
logOutput = CLIOptions.o_logOutput.Value;
|
||||
logMinLevel = CLIOptions.o_logLevel.Value;
|
||||
var appAssembly = typeof(Program).Assembly.GetName();
|
||||
LogName = $"{appAssembly.Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log";
|
||||
LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogName);
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
|
||||
LogToFile(LoggerEvent.Verbose, $"---{appAssembly.Name} v{appAssembly.Version} [{arch}] | Logger launched---\n" +
|
||||
$"CMD Args: {string.Join(" ", CLIOptions.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, bool ignoreLevel)
|
||||
{
|
||||
if ((logMsgLevel < logMinLevel && !ignoreLevel) || 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
437
AssetStudioCLI/Exporter.cs
Normal file
437
AssetStudioCLI/Exporter.cs
Normal file
@@ -0,0 +1,437 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal static class Exporter
|
||||
{
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_Texture2D = (Texture2D)item.Asset;
|
||||
if (CLIOptions.convertTexture)
|
||||
{
|
||||
var type = CLIOptions.o_imageFormat.Value;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
|
||||
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Converting \"{m_Texture2D.m_Name}\" to {type}..");
|
||||
sb.AppendLine($"Width: {m_Texture2D.m_Width}");
|
||||
sb.AppendLine($"Height: {m_Texture2D.m_Height}");
|
||||
sb.AppendLine($"Format: {m_Texture2D.m_TextureFormat}");
|
||||
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
|
||||
{
|
||||
case 0: sb.AppendLine("Filter Mode: Point "); break;
|
||||
case 1: sb.AppendLine("Filter Mode: Bilinear "); break;
|
||||
case 2: sb.AppendLine("Filter Mode: Trilinear "); break;
|
||||
}
|
||||
sb.AppendLine($"Anisotropic level: {m_Texture2D.m_TextureSettings.m_Aniso}");
|
||||
sb.AppendLine($"Mip map bias: {m_Texture2D.m_TextureSettings.m_MipBias}");
|
||||
switch (m_Texture2D.m_TextureSettings.m_WrapMode)
|
||||
{
|
||||
case 0: sb.AppendLine($"Wrap mode: Repeat"); break;
|
||||
case 1: sb.AppendLine($"Wrap mode: Clamp"); break;
|
||||
}
|
||||
Logger.Debug(sb.ToString());
|
||||
}
|
||||
|
||||
var image = m_Texture2D.ConvertToImage(flip: true);
|
||||
if (image == null)
|
||||
{
|
||||
Logger.Error($"Export error. Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
|
||||
return false;
|
||||
}
|
||||
using (image)
|
||||
{
|
||||
using (var file = File.OpenWrite(exportFullPath))
|
||||
{
|
||||
image.WriteToStream(file, type);
|
||||
}
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ExportAudioClip(AssetItem item, string exportPath)
|
||||
{
|
||||
string exportFullPath;
|
||||
var m_AudioClip = (AudioClip)item.Asset;
|
||||
var m_AudioData = m_AudioClip.m_AudioData.GetData();
|
||||
if (m_AudioData == null || m_AudioData.Length == 0)
|
||||
{
|
||||
Logger.Error($"Export error. \"{item.Text}\": AudioData was not found");
|
||||
return false;
|
||||
}
|
||||
var converter = new AudioClipConverter(m_AudioClip);
|
||||
if (CLIOptions.o_audioFormat.Value != AudioFormat.None && converter.IsSupport)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
|
||||
return false;
|
||||
|
||||
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Converting \"{m_AudioClip.m_Name}\" to wav..");
|
||||
sb.AppendLine(m_AudioClip.version[0] < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
|
||||
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
|
||||
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
|
||||
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
|
||||
Logger.Debug(sb.ToString());
|
||||
}
|
||||
|
||||
var buffer = converter.ConvertToWav(m_AudioData);
|
||||
if (buffer == null)
|
||||
{
|
||||
Logger.Error($"Export error. \"{item.Text}\": Failed to convert to Wav");
|
||||
return false;
|
||||
}
|
||||
File.WriteAllBytes(exportFullPath, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, m_AudioData);
|
||||
}
|
||||
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportVideoClip(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_VideoClip = (VideoClip)item.Asset;
|
||||
if (m_VideoClip.m_ExternalResources.m_Size > 0)
|
||||
{
|
||||
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
|
||||
return false;
|
||||
|
||||
if (CLIOptions.o_logLevel.Value <= LoggerEvent.Debug)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"VideoClip format: {m_VideoClip.m_Format}");
|
||||
sb.AppendLine($"VideoClip width: {m_VideoClip.Width}");
|
||||
sb.AppendLine($"VideoClip height: {m_VideoClip.Height}");
|
||||
sb.AppendLine($"VideoClip frame rate: {m_VideoClip.m_FrameRate:.0##}");
|
||||
sb.AppendLine($"VideoClip split alpha: {m_VideoClip.m_HasSplitAlpha}");
|
||||
Logger.Debug(sb.ToString());
|
||||
}
|
||||
|
||||
m_VideoClip.m_VideoData.WriteData(exportFullPath);
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportMovieTexture(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_MovieTexture = (MovieTexture)item.Asset;
|
||||
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
|
||||
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var m_TextAsset = (TextAsset)item.Asset;
|
||||
var extension = ".txt";
|
||||
var assetExtension = Path.GetExtension(m_TextAsset.m_Name);
|
||||
if (!CLIOptions.f_notRestoreExtensionName.Value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(assetExtension))
|
||||
{
|
||||
extension = "";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(item.Container))
|
||||
{
|
||||
var ext = Path.GetExtension(item.Container);
|
||||
if (!string.IsNullOrEmpty(item.Container))
|
||||
{
|
||||
extension = ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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 = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader);
|
||||
type = m_MonoBehaviour.ToType(m_Type);
|
||||
}
|
||||
if (type != null)
|
||||
{
|
||||
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var type = CLIOptions.o_imageFormat.Value;
|
||||
var alphaMask = SpriteMaskMode.On;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
var image = ((Sprite)item.Asset).GetImage(alphaMask);
|
||||
if (image != null)
|
||||
{
|
||||
using (image)
|
||||
{
|
||||
using (var file = File.OpenWrite(exportFullPath))
|
||||
{
|
||||
image.WriteToStream(file, type);
|
||||
}
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = m_MonoBehaviour.ConvertToTypeTree(Studio.assemblyLoader);
|
||||
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;
|
||||
}
|
||||
|
||||
private static bool ExportMesh(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_Mesh = (Mesh)item.Asset;
|
||||
if (m_Mesh.m_VertexCount <= 0)
|
||||
return false;
|
||||
if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath))
|
||||
return false;
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("g " + m_Mesh.m_Name);
|
||||
|
||||
#region Vertices
|
||||
|
||||
if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int c = 3;
|
||||
if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4)
|
||||
{
|
||||
c = 4;
|
||||
}
|
||||
|
||||
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
|
||||
{
|
||||
sb.Append($"v {-m_Mesh.m_Vertices[v * c]} {m_Mesh.m_Vertices[v * c + 1]} {m_Mesh.m_Vertices[v * c + 2]}\r\n");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UV
|
||||
|
||||
if (m_Mesh.m_UV0?.Length > 0)
|
||||
{
|
||||
c = 4;
|
||||
if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
|
||||
{
|
||||
c = 2;
|
||||
}
|
||||
else if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 3)
|
||||
{
|
||||
c = 3;
|
||||
}
|
||||
|
||||
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
|
||||
{
|
||||
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * c], m_Mesh.m_UV0[v * c + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Normals
|
||||
|
||||
if (m_Mesh.m_Normals?.Length > 0)
|
||||
{
|
||||
if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3)
|
||||
{
|
||||
c = 3;
|
||||
}
|
||||
else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4)
|
||||
{
|
||||
c = 4;
|
||||
}
|
||||
|
||||
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
|
||||
{
|
||||
sb.AppendFormat("vn {0} {1} {2}\r\n", -m_Mesh.m_Normals[v * c], m_Mesh.m_Normals[v * c + 1], m_Mesh.m_Normals[v * c + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Face
|
||||
|
||||
int sum = 0;
|
||||
for (var i = 0; i < m_Mesh.m_SubMeshes.Length; i++)
|
||||
{
|
||||
sb.AppendLine($"g {m_Mesh.m_Name}_{i}");
|
||||
int indexCount = (int)m_Mesh.m_SubMeshes[i].indexCount;
|
||||
var end = sum + indexCount / 3;
|
||||
for (int f = sum; f < end; f++)
|
||||
{
|
||||
sb.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\r\n", m_Mesh.m_Indices[f * 3 + 2] + 1, m_Mesh.m_Indices[f * 3 + 1] + 1, m_Mesh.m_Indices[f * 3] + 1);
|
||||
}
|
||||
|
||||
sum = end;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
sb.Replace("NaN", "0");
|
||||
File.WriteAllText(exportFullPath, sb.ToString());
|
||||
Logger.Debug($"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportConvertFile(AssetItem item, string exportPath)
|
||||
{
|
||||
switch (item.Type)
|
||||
{
|
||||
case ClassIDType.Texture2D:
|
||||
return ExportTexture2D(item, exportPath);
|
||||
case ClassIDType.AudioClip:
|
||||
return ExportAudioClip(item, exportPath);
|
||||
case ClassIDType.VideoClip:
|
||||
return ExportVideoClip(item, exportPath);
|
||||
case ClassIDType.MovieTexture:
|
||||
return ExportMovieTexture(item, exportPath);
|
||||
case ClassIDType.Shader:
|
||||
return ExportShader(item, exportPath);
|
||||
case ClassIDType.TextAsset:
|
||||
return ExportTextAsset(item, exportPath);
|
||||
case ClassIDType.MonoBehaviour:
|
||||
return ExportMonoBehaviour(item, exportPath);
|
||||
case ClassIDType.Font:
|
||||
return ExportFont(item, exportPath);
|
||||
case ClassIDType.Sprite:
|
||||
return ExportSprite(item, exportPath);
|
||||
case ClassIDType.Mesh:
|
||||
return ExportMesh(item, exportPath);
|
||||
default:
|
||||
return ExportRawFile(item, exportPath);
|
||||
}
|
||||
}
|
||||
|
||||
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.
832
AssetStudioCLI/Options/CLIOptions.cs
Normal file
832
AssetStudioCLI/Options/CLIOptions.cs
Normal file
@@ -0,0 +1,832 @@
|
||||
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,
|
||||
ExportLive2D,
|
||||
}
|
||||
|
||||
internal enum AssetGroupOption
|
||||
{
|
||||
None,
|
||||
TypeName,
|
||||
ContainerPath,
|
||||
ContainerPathFull,
|
||||
SourceFileName,
|
||||
}
|
||||
|
||||
internal enum ExportListType
|
||||
{
|
||||
None,
|
||||
XML,
|
||||
}
|
||||
|
||||
internal enum AudioFormat
|
||||
{
|
||||
None,
|
||||
Wav,
|
||||
}
|
||||
|
||||
internal enum FilterBy
|
||||
{
|
||||
None,
|
||||
Name,
|
||||
Container,
|
||||
PathID,
|
||||
NameOrContainer,
|
||||
NameAndContainer,
|
||||
}
|
||||
|
||||
internal static class CLIOptions
|
||||
{
|
||||
public static bool isParsed;
|
||||
public static bool showHelp;
|
||||
public static string[] cliArgs;
|
||||
public static string inputPath;
|
||||
public static FilterBy filterBy;
|
||||
private static Dictionary<string, string> optionsDict;
|
||||
private static Dictionary<string, string> flagsDict;
|
||||
private static Dictionary<HelpGroups, Dictionary<string, string>> optionGroups;
|
||||
private static List<ClassIDType> supportedAssetTypes;
|
||||
//general
|
||||
public static Option<WorkMode> o_workMode;
|
||||
public static Option<List<ClassIDType>> o_exportAssetTypes;
|
||||
public static Option<AssetGroupOption> o_groupAssetsBy;
|
||||
public static Option<string> o_outputFolder;
|
||||
public static Option<bool> o_displayHelp;
|
||||
//logger
|
||||
public static Option<LoggerEvent> o_logLevel;
|
||||
public static Option<LogOutputMode> o_logOutput;
|
||||
//convert
|
||||
public static bool convertTexture;
|
||||
public static Option<ImageFormat> o_imageFormat;
|
||||
public static Option<AudioFormat> o_audioFormat;
|
||||
//advanced
|
||||
public static Option<ExportListType> o_exportAssetList;
|
||||
public static Option<List<string>> o_filterByName;
|
||||
public static Option<List<string>> o_filterByContainer;
|
||||
public static Option<List<string>> o_filterByPathID;
|
||||
public static Option<List<string>> o_filterByText;
|
||||
public static Option<string> o_assemblyPath;
|
||||
public static Option<string> o_unityVersion;
|
||||
public static Option<bool> f_notRestoreExtensionName;
|
||||
|
||||
static CLIOptions()
|
||||
{
|
||||
OptionExtensions.OptionGrouping = OptionGrouping;
|
||||
InitOptions();
|
||||
}
|
||||
|
||||
private static void OptionGrouping(string name, string desc, HelpGroups group, bool isFlag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var optionDict = new Dictionary<string, string>() { { name, desc } };
|
||||
if (!optionGroups.ContainsKey(group))
|
||||
{
|
||||
optionGroups.Add(group, optionDict);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionGroups[group].Add(name, desc);
|
||||
}
|
||||
|
||||
if (isFlag)
|
||||
{
|
||||
flagsDict.Add(name, desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionsDict.Add(name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitOptions()
|
||||
{
|
||||
isParsed = false;
|
||||
showHelp = false;
|
||||
cliArgs = null;
|
||||
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,
|
||||
ClassIDType.MovieTexture,
|
||||
ClassIDType.Mesh,
|
||||
};
|
||||
|
||||
#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 | live2d>\n" +
|
||||
"Export - Exports converted assets\n" +
|
||||
"ExportRaw - Exports raw data\n" +
|
||||
"Dump - Makes asset dumps\n" +
|
||||
"Info - Loads file(s), shows the number of available for export assets and exits\n" +
|
||||
"Live2D - Exports Live2D Cubism 3 models\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, movieTexture,\n" +
|
||||
"audio, video, mesh | 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 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) | containerFull | 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" +
|
||||
"ContainerFull - Group exported assets by full container path (e.g. with prefab name)\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 use/restore original TextAsset\nextension name, and will just export all TextAssets with the \".txt\" extension",
|
||||
optionHelpGroup: HelpGroups.Advanced,
|
||||
isFlag: true
|
||||
);
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static void ParseArgs(string[] args)
|
||||
{
|
||||
cliArgs = 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;
|
||||
case "live2d":
|
||||
o_workMode.Value = WorkMode.ExportLive2D;
|
||||
o_exportAssetTypes.Value = new List<ClassIDType>()
|
||||
{
|
||||
ClassIDType.AnimationClip,
|
||||
ClassIDType.GameObject,
|
||||
ClassIDType.MonoBehaviour,
|
||||
ClassIDType.Texture2D,
|
||||
ClassIDType.Transform,
|
||||
};
|
||||
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":
|
||||
if (o_workMode.Value == WorkMode.ExportLive2D)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
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 "movietexture":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.MovieTexture);
|
||||
break;
|
||||
case "mesh":
|
||||
o_exportAssetTypes.Value.Add(ClassIDType.Mesh);
|
||||
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 "containerfull":
|
||||
o_groupAssetsBy.Value = AssetGroupOption.ContainerPathFull;
|
||||
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;
|
||||
Studio.assemblyLoader.Load(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;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (!Studio.assemblyLoader.Loaded)
|
||||
{
|
||||
Studio.assemblyLoader.Loaded = true;
|
||||
}
|
||||
isParsed = true;
|
||||
}
|
||||
|
||||
private static string[] ValueSplitter(string value)
|
||||
{
|
||||
var separator = value.Contains(';') ? ';' : ',';
|
||||
return value.Split(separator);
|
||||
}
|
||||
|
||||
private static 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 static 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
|
||||
{
|
||||
var arch = Environment.Is64BitProcess ? "x64" : "x32";
|
||||
Console.WriteLine($"# {appAssembly.Name} [{arch}]\n# Based on AssetStudioMod v{appAssembly.Version}\n");
|
||||
Console.WriteLine($"{usage}\n\n{helpMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
private static 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 static void ShowCurrentOptions()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("[Current Options]");
|
||||
sb.AppendLine($"# Working Mode: {o_workMode}");
|
||||
sb.AppendLine($"# Input Path: \"{inputPath}\"");
|
||||
switch (o_workMode.Value)
|
||||
{
|
||||
case WorkMode.Info:
|
||||
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}\"");
|
||||
break;
|
||||
case WorkMode.ExportLive2D:
|
||||
sb.AppendLine($"# Output Path: \"{o_outputFolder}\"");
|
||||
sb.AppendLine($"# Log Level: {o_logLevel}");
|
||||
sb.AppendLine($"# Log Output: {o_logOutput}");
|
||||
sb.AppendLine($"# Export Asset List: {o_exportAssetList}");
|
||||
sb.AppendLine($"# Assebmly Path: \"{o_assemblyPath}\"");
|
||||
sb.AppendLine($"# Unity Version: \"{o_unityVersion}\"");
|
||||
break;
|
||||
default:
|
||||
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}");
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
AssetStudioCLI/Options/OptionExtensions.cs
Normal file
17
AssetStudioCLI/Options/OptionExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudioCLI.Options
|
||||
{
|
||||
internal static class OptionExtensions
|
||||
{
|
||||
public static Action<string, string, HelpGroups, bool> OptionGrouping = (name, desc, group, isFlag) => { };
|
||||
}
|
||||
|
||||
internal class GroupedOption<T> : Option<T>
|
||||
{
|
||||
public GroupedOption(T optionDefaultValue, string optionName, string optionDescription, HelpGroups optionHelpGroup, bool isFlag = false) : base(optionDefaultValue, optionName, optionDescription, optionHelpGroup, isFlag)
|
||||
{
|
||||
OptionExtensions.OptionGrouping(optionName, optionDescription, optionHelpGroup, isFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
AssetStudioCLI/Program.cs
Normal file
70
AssetStudioCLI/Program.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using AssetStudio;
|
||||
using AssetStudioCLI.Options;
|
||||
using System;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CLIOptions.ParseArgs(args);
|
||||
if (CLIOptions.isParsed)
|
||||
{
|
||||
CLIRun();
|
||||
}
|
||||
else if (CLIOptions.showHelp)
|
||||
{
|
||||
CLIOptions.ShowHelp();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine();
|
||||
CLIOptions.ShowHelp(showUsageOnly: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CLIRun()
|
||||
{
|
||||
var cliLogger = new CLILogger();
|
||||
Logger.Default = cliLogger;
|
||||
CLIOptions.ShowCurrentOptions();
|
||||
|
||||
try
|
||||
{
|
||||
if (Studio.LoadAssets())
|
||||
{
|
||||
Studio.ParseAssets();
|
||||
if (CLIOptions.filterBy != FilterBy.None && CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
|
||||
{
|
||||
Studio.FilterAssets();
|
||||
}
|
||||
if (CLIOptions.o_exportAssetList.Value != ExportListType.None)
|
||||
{
|
||||
Studio.ExportAssetList();
|
||||
}
|
||||
switch (CLIOptions.o_workMode.Value)
|
||||
{
|
||||
case WorkMode.Info:
|
||||
Studio.ShowExportableAssetsInfo();
|
||||
break;
|
||||
case WorkMode.ExportLive2D:
|
||||
Studio.ExportLive2D();
|
||||
break;
|
||||
default:
|
||||
Studio.ExportAssets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
cliLogger.LogToFile(LoggerEvent.Verbose, "---Program ended---");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
AssetStudioCLI/ReadMe.md
Normal file
97
AssetStudioCLI/ReadMe.md
Normal file
@@ -0,0 +1,97 @@
|
||||
## AssetStudioModCLI
|
||||
CLI version of AssetStudioMod.
|
||||
- Supported asset types: `Texture2D`, `Sprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip`, `Mesh`.
|
||||
- *There are no plans to add support for `AnimationClip`, `Animator` for now.*
|
||||
|
||||
### Usage
|
||||
```
|
||||
AssetStudioModCLI <input path to asset file/folder> [-m, --mode <value>]
|
||||
[-t, --asset-type <value(s)>] [-g, --group-option <value>]
|
||||
[-o, --output <path>] [-h, --help]
|
||||
[--log-level <value>] [--log-output <value>]
|
||||
[--image-format <value>] [--audio-format <value>]
|
||||
[--export-asset-list <value>] [--filter-by-name <text>]
|
||||
[--filter-by-container <text>] [--filter-by-pathid <text>]
|
||||
[--filter-by-text <text>] [--assembly-folder <path>]
|
||||
[--unity-version <text>] [--not-restore-extension]
|
||||
|
||||
|
||||
General Options:
|
||||
-m, --mode <value> Specify working mode
|
||||
<Value: export(default) | exportRaw | dump | info | live2d>
|
||||
Export - Exports converted assets
|
||||
ExportRaw - Exports raw data
|
||||
Dump - Makes asset dumps
|
||||
Info - Loads file(s), shows the number of available for export assets and exits
|
||||
Live2D - Exports Live2D Cubism 3 models
|
||||
Example: "-m info"
|
||||
|
||||
-t, --asset-type <value(s)> Specify asset type(s) to export
|
||||
<Value(s): tex2d, sprite, textAsset, monoBehaviour, font, shader, movieTexture,
|
||||
audio, video, mesh | all(default)>
|
||||
All - export all asset types, which are listed in the values
|
||||
*To specify multiple asset types, write them separated by ',' or ';' without spaces
|
||||
Examples: "-t sprite" or "-t tex2d,sprite,audio" or "-t tex2d;sprite;font"
|
||||
|
||||
-g, --group-option <value> Specify the way in which exported assets should be grouped
|
||||
<Value: none | type | container(default) | containerFull | filename>
|
||||
None - Do not group exported assets
|
||||
Type - Group exported assets by type name
|
||||
Container - Group exported assets by container path
|
||||
ContainerFull - Group exported assets by full container path (e.g. with prefab name)
|
||||
Filename - Group exported assets by source file name
|
||||
Example: "-g container"
|
||||
|
||||
-o, --output <path> Specify path to the output folder
|
||||
If path isn't specifyed, 'ASExport' folder will be created in the program's work folder
|
||||
|
||||
-h, --help Display help and exit
|
||||
|
||||
Logger Options:
|
||||
--log-level <value> Specify the log level
|
||||
<Value: verbose | debug | info(default) | warning | error>
|
||||
Example: "--log-level warning"
|
||||
|
||||
--log-output <value> Specify the log output
|
||||
<Value: console(default) | file | both>
|
||||
Example: "--log-output both"
|
||||
|
||||
Convert Options:
|
||||
--image-format <value> Specify the format for converting image assets
|
||||
<Value: none | jpg | png(default) | bmp | tga | webp>
|
||||
None - Do not convert images and export them as texture data (.tex)
|
||||
Example: "--image-format jpg"
|
||||
|
||||
--audio-format <value> Specify the format for converting audio assets
|
||||
<Value: none | wav(default)>
|
||||
None - Do not convert audios and export them in their own format
|
||||
Example: "--audio-format wav"
|
||||
|
||||
Advanced Options:
|
||||
--export-asset-list <value> Specify the format in which you want to export asset list
|
||||
<Value: none(default) | xml>
|
||||
None - Do not export asset list
|
||||
Example: "--export-asset-list xml"
|
||||
|
||||
--filter-by-name <text> Specify the name by which assets should be filtered
|
||||
*To specify multiple names write them separated by ',' or ';' without spaces
|
||||
Example: "--filter-by-name char" or "--filter-by-name char,bg"
|
||||
|
||||
--filter-by-container <text> Specify the container by which assets should be filtered
|
||||
*To specify multiple containers write them separated by ',' or ';' without spaces
|
||||
Example: "--filter-by-container arts" or "--filter-by-container arts,icons"
|
||||
|
||||
--filter-by-pathid <text> Specify the PathID by which assets should be filtered
|
||||
*To specify multiple PathIDs write them separated by ',' or ';' without spaces
|
||||
Example: "--filter-by-pathid 7238605633795851352,-2430306240205277265"
|
||||
|
||||
--filter-by-text <text> Specify the text by which assets should be filtered
|
||||
Looks for assets that contain the specified text in their names or containers
|
||||
*To specify multiple values write them separated by ',' or ';' without spaces
|
||||
Example: "--filter-by-text portrait" or "--filter-by-text portrait,art"
|
||||
|
||||
--assembly-folder <path> Specify the path to the assembly folder
|
||||
--unity-version <text> Specify Unity version. Example: "--unity-version 2017.4.39f1"
|
||||
--not-restore-extension (Flag) If specified, AssetStudio will not try to use/restore original TextAsset
|
||||
extension name, and will just export all TextAssets with the ".txt" extension
|
||||
```
|
||||
479
AssetStudioCLI/Studio.cs
Normal file
479
AssetStudioCLI/Studio.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
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 static CubismLive2DExtractor.Live2DExtractor;
|
||||
using Ansi = AssetStudioCLI.CLIAnsiColors;
|
||||
|
||||
namespace AssetStudioCLI
|
||||
{
|
||||
internal static class Studio
|
||||
{
|
||||
public static AssetsManager assetsManager = new AssetsManager();
|
||||
public static List<AssetItem> parsedAssetsList = new List<AssetItem>();
|
||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||
private static Dictionary<AssetStudio.Object, string> containers = new Dictionary<AssetStudio.Object, string>();
|
||||
|
||||
static Studio()
|
||||
{
|
||||
Progress.Default = new Progress<int>(ShowCurProgressValue);
|
||||
}
|
||||
|
||||
private static void ShowCurProgressValue(int value)
|
||||
{
|
||||
Console.Write($"[{value:000}%]\r");
|
||||
}
|
||||
|
||||
public static bool LoadAssets()
|
||||
{
|
||||
var isLoaded = false;
|
||||
assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.Value;
|
||||
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
|
||||
|
||||
assetsManager.LoadFilesAndFolders(CLIOptions.inputPath);
|
||||
if (assetsManager.assetsFileList.Count == 0)
|
||||
{
|
||||
Logger.Warning("No Unity file can be loaded.");
|
||||
}
|
||||
else
|
||||
{
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public static void ParseAssets()
|
||||
{
|
||||
Logger.Info("Parse assets...");
|
||||
|
||||
var fileAssetsList = new List<AssetItem>();
|
||||
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 Mesh _:
|
||||
case MovieTexture _:
|
||||
case TextAsset _:
|
||||
case Font _:
|
||||
case Sprite _:
|
||||
assetItem.Text = ((NamedObject)asset).m_Name;
|
||||
break;
|
||||
case Shader m_Shader:
|
||||
assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name;
|
||||
break;
|
||||
case MonoBehaviour m_MonoBehaviour:
|
||||
if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
assetItem.Text = m_Script.m_ClassName;
|
||||
}
|
||||
else
|
||||
{
|
||||
assetItem.Text = m_MonoBehaviour.m_Name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (assetItem.Text == "")
|
||||
{
|
||||
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
|
||||
}
|
||||
|
||||
isExportable = CLIOptions.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);
|
||||
fileAssetsList.Clear();
|
||||
if (CLIOptions.o_workMode.Value != WorkMode.ExportLive2D)
|
||||
{
|
||||
containers.Clear();
|
||||
}
|
||||
}
|
||||
var log = $"Finished loading {assetsManager.assetsFileList.Count} files with {parsedAssetsList.Count} exportable assets";
|
||||
var unityVer = assetsManager.assetsFileList[0].version;
|
||||
long m_ObjectsCount;
|
||||
if (unityVer[0] > 2020)
|
||||
{
|
||||
m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y =>
|
||||
y.classID != (int)ClassIDType.Shader
|
||||
&& CLIOptions.o_exportAssetTypes.Value.Any(k => (int)k == y.classID))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ObjectsCount = assetsManager.assetsFileList.Sum(x => x.m_Objects.LongCount(y => CLIOptions.o_exportAssetTypes.Value.Any(k => (int)k == y.classID)));
|
||||
}
|
||||
var objectsCount = assetsManager.assetsFileList.Sum(x => x.Objects.LongCount(y => CLIOptions.o_exportAssetTypes.Value.Any(k => k == y.type)));
|
||||
if (m_ObjectsCount != objectsCount)
|
||||
{
|
||||
log += $" and {m_ObjectsCount - objectsCount} assets failed to read";
|
||||
}
|
||||
Logger.Info(log);
|
||||
}
|
||||
|
||||
public static void ShowExportableAssetsInfo()
|
||||
{
|
||||
var exportableAssetsCountDict = new Dictionary<ClassIDType, int>();
|
||||
string info = "";
|
||||
if (parsedAssetsList.Count > 0)
|
||||
{
|
||||
foreach (var asset in parsedAssetsList)
|
||||
{
|
||||
if (exportableAssetsCountDict.ContainsKey(asset.Type))
|
||||
{
|
||||
exportableAssetsCountDict[asset.Type] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
exportableAssetsCountDict.Add(asset.Type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info += "No exportable assets found.";
|
||||
}
|
||||
|
||||
if (CLIOptions.o_logLevel.Value > LoggerEvent.Info)
|
||||
{
|
||||
Console.WriteLine(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info(info);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FilterAssets()
|
||||
{
|
||||
var assetsCount = parsedAssetsList.Count;
|
||||
var filteredAssets = new List<AssetItem>();
|
||||
|
||||
switch(CLIOptions.filterBy)
|
||||
{
|
||||
case FilterBy.Name:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.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("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
|
||||
);
|
||||
break;
|
||||
case FilterBy.Container:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers."
|
||||
);
|
||||
break;
|
||||
case FilterBy.PathID:
|
||||
filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByPathID.Value.Any(y => x.m_PathID.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0));
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs."
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameOrContainer:
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
CLIOptions.o_filterByText.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) ||
|
||||
CLIOptions.o_filterByText.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
);
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Contaniers."
|
||||
);
|
||||
break;
|
||||
case FilterBy.NameAndContainer:
|
||||
filteredAssets = parsedAssetsList.FindAll(x =>
|
||||
CLIOptions.o_filterByName.Value.Any(y => x.Text.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) &&
|
||||
CLIOptions.o_filterByContainer.Value.Any(y => x.Container.ToString().IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
);
|
||||
Logger.Info(
|
||||
$"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " +
|
||||
$"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByContainer.Value)}\"".Color(Ansi.BrightYellow)} in their Containers " +
|
||||
$"and {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names."
|
||||
);
|
||||
break;
|
||||
}
|
||||
parsedAssetsList.Clear();
|
||||
parsedAssetsList = filteredAssets;
|
||||
}
|
||||
|
||||
public static void ExportAssets()
|
||||
{
|
||||
var savePath = CLIOptions.o_outputFolder.Value;
|
||||
var toExportCount = parsedAssetsList.Count;
|
||||
var exportedCount = 0;
|
||||
|
||||
var groupOption = CLIOptions.o_groupAssetsBy.Value;
|
||||
foreach (var asset in parsedAssetsList)
|
||||
{
|
||||
string exportPath;
|
||||
switch (groupOption)
|
||||
{
|
||||
case AssetGroupOption.TypeName:
|
||||
exportPath = Path.Combine(savePath, asset.TypeString);
|
||||
break;
|
||||
case AssetGroupOption.ContainerPath:
|
||||
case AssetGroupOption.ContainerPathFull:
|
||||
if (!string.IsNullOrEmpty(asset.Container))
|
||||
{
|
||||
exportPath = Path.Combine(savePath, Path.GetDirectoryName(asset.Container));
|
||||
if (groupOption == AssetGroupOption.ContainerPathFull)
|
||||
{
|
||||
exportPath = Path.Combine(exportPath, Path.GetFileNameWithoutExtension(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 (CLIOptions.o_workMode.Value)
|
||||
{
|
||||
case WorkMode.ExportRaw:
|
||||
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportRawFile(asset, exportPath))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
case WorkMode.Dump:
|
||||
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportDumpFile(asset, exportPath))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
case WorkMode.Export:
|
||||
Logger.Debug($"{CLIOptions.o_workMode}: {asset.Type} : {asset.Container} : {asset.Text}");
|
||||
if (ExportConvertFile(asset, exportPath))
|
||||
{
|
||||
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.Default.Log(LoggerEvent.Info, "Nothing exported.", ignoreLevel: true);
|
||||
}
|
||||
else if (toExportCount > exportedCount)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightYellow)}\".", ignoreLevel: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, $"Finished exporting {exportedCount} asset(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightGreen)}\".", ignoreLevel: true);
|
||||
}
|
||||
|
||||
if (toExportCount > exportedCount)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, $"{toExportCount - exportedCount} asset(s) skipped (not extractable or file(s) already exist).", ignoreLevel: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExportAssetList()
|
||||
{
|
||||
var savePath = CLIOptions.o_outputFolder.Value;
|
||||
|
||||
switch (CLIOptions.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.");
|
||||
}
|
||||
|
||||
public static void ExportLive2D()
|
||||
{
|
||||
var baseDestPath = Path.Combine(CLIOptions.o_outputFolder.Value, "Live2DOutput");
|
||||
var useFullContainerPath = false;
|
||||
|
||||
Progress.Reset();
|
||||
Logger.Info($"Searching for Live2D files...");
|
||||
|
||||
var cubismMocs = parsedAssetsList.Where(x =>
|
||||
{
|
||||
if (x.Type == ClassIDType.MonoBehaviour)
|
||||
{
|
||||
((MonoBehaviour)x.Asset).m_Script.TryGet(out var m_Script);
|
||||
return m_Script?.m_ClassName == "CubismMoc";
|
||||
}
|
||||
return false;
|
||||
}).Select(x => x.Asset).ToArray();
|
||||
if (cubismMocs.Length == 0)
|
||||
{
|
||||
Logger.Default.Log(LoggerEvent.Info, "Live2D Cubism models were not found.", ignoreLevel: true);
|
||||
return;
|
||||
}
|
||||
if (cubismMocs.Length > 1)
|
||||
{
|
||||
var basePathSet = cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToHashSet();
|
||||
|
||||
if (basePathSet.Count != cubismMocs.Length)
|
||||
{
|
||||
useFullContainerPath = true;
|
||||
Logger.Debug($"useFullContainerPath: {useFullContainerPath}");
|
||||
}
|
||||
}
|
||||
var basePathList = useFullContainerPath ?
|
||||
cubismMocs.Select(x => containers[x]).ToList() :
|
||||
cubismMocs.Select(x => containers[x].Substring(0, containers[x].LastIndexOf("/"))).ToList();
|
||||
var lookup = containers.ToLookup(
|
||||
x => basePathList.Find(b => x.Value.Contains(b) && x.Value.Split('/').Any(y => y == b.Substring(b.LastIndexOf("/") + 1))),
|
||||
x => x.Key
|
||||
);
|
||||
|
||||
var totalModelCount = lookup.LongCount(x => x.Key != null);
|
||||
Logger.Info($"Found {totalModelCount} model(s).");
|
||||
var name = "";
|
||||
var modelCounter = 0;
|
||||
foreach (var assets in lookup)
|
||||
{
|
||||
var container = assets.Key;
|
||||
if (container == null)
|
||||
continue;
|
||||
name = container;
|
||||
|
||||
Logger.Info($"[{modelCounter + 1}/{totalModelCount}] Exporting Live2D: \"{container.Color(Ansi.BrightCyan)}\"");
|
||||
try
|
||||
{
|
||||
var modelName = useFullContainerPath ? Path.GetFileNameWithoutExtension(container) : container.Substring(container.LastIndexOf('/') + 1);
|
||||
container = Path.HasExtension(container) ? container.Replace(Path.GetExtension(container), "") : container;
|
||||
var destPath = Path.Combine(baseDestPath, container) + Path.DirectorySeparatorChar;
|
||||
|
||||
ExtractLive2D(assets, destPath, modelName, assemblyLoader);
|
||||
modelCounter++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Live2D model export error: \"{name}\"", ex);
|
||||
}
|
||||
Progress.Report(modelCounter, (int)totalModelCount);
|
||||
}
|
||||
var status = modelCounter > 0 ?
|
||||
$"Finished exporting [{modelCounter}/{totalModelCount}] Live2D model(s) to \"{CLIOptions.o_outputFolder.Value.Color(Ansi.BrightCyan)}\"" :
|
||||
"Nothing exported.";
|
||||
Logger.Default.Log(LoggerEvent.Info, status, ignoreLevel: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
[assembly:AssemblyTitleAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyDescriptionAttribute(L"")];
|
||||
[assembly:AssemblyConfigurationAttribute(L"")];
|
||||
[assembly:AssemblyCompanyAttribute(L"")];
|
||||
[assembly:AssemblyProductAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyCopyrightAttribute(L"Copyright © Perfare 2018-2020")];
|
||||
[assembly:AssemblyTrademarkAttribute(L"")];
|
||||
[assembly:AssemblyCultureAttribute(L"")];
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.0.*")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
char* Fbx::StringToUTF8(String^ s)
|
||||
{
|
||||
auto bytes = Text::Encoding::UTF8->GetBytes(s);
|
||||
auto chars = new char[bytes->Length + 1];
|
||||
pin_ptr<unsigned char> ptr = &bytes[0];
|
||||
memcpy(chars, ptr, bytes->Length);
|
||||
chars[bytes->Length] = '\0';
|
||||
return chars;
|
||||
}
|
||||
|
||||
void Fbx::Init(FbxManager** pSdkManager, FbxScene** pScene)
|
||||
{
|
||||
*pSdkManager = FbxManager::Create();
|
||||
if (!pSdkManager)
|
||||
{
|
||||
throw gcnew Exception(gcnew String("Unable to create the FBX SDK manager"));
|
||||
}
|
||||
|
||||
FbxIOSettings* ios = FbxIOSettings::Create(*pSdkManager, IOSROOT);
|
||||
(*pSdkManager)->SetIOSettings(ios);
|
||||
*pScene = FbxScene::Create(*pSdkManager, "");
|
||||
}
|
||||
|
||||
Vector3 Fbx::QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetQ(FbxQuaternion(q.X, q.Y, q.Z, q.W));
|
||||
FbxVector4 lEuler = lMatrixRot.GetR();
|
||||
return Vector3((float)lEuler[0], (float)lEuler[1], (float)lEuler[2]);
|
||||
}
|
||||
|
||||
Quaternion Fbx::EulerToQuaternion(Vector3 v)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetR(FbxVector4(v.X, v.Y, v.Z));
|
||||
FbxQuaternion lQuaternion = lMatrixRot.GetQ();
|
||||
return Quaternion((float)lQuaternion[0], (float)lQuaternion[1], (float)lQuaternion[2], (float)lQuaternion[3]);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#ifdef IOS_REF
|
||||
#undef IOS_REF
|
||||
#define IOS_REF (*(pSdkManager->GetIOSettings()))
|
||||
#endif
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::IO;
|
||||
|
||||
#define WITH_MARSHALLED_STRING(name,str,block)\
|
||||
{ \
|
||||
char* name; \
|
||||
try \
|
||||
{ \
|
||||
name = StringToUTF8(str); \
|
||||
block \
|
||||
} \
|
||||
finally \
|
||||
{ \
|
||||
delete name; \
|
||||
} \
|
||||
}
|
||||
|
||||
static char* FBXVersion[] =
|
||||
{
|
||||
FBX_2010_00_COMPATIBLE,
|
||||
FBX_2011_00_COMPATIBLE,
|
||||
FBX_2012_00_COMPATIBLE,
|
||||
FBX_2013_00_COMPATIBLE,
|
||||
FBX_2014_00_COMPATIBLE,
|
||||
FBX_2016_00_COMPATIBLE
|
||||
};
|
||||
|
||||
namespace AssetStudio {
|
||||
|
||||
public ref class Fbx
|
||||
{
|
||||
public:
|
||||
static Vector3 QuaternionToEuler(Quaternion q);
|
||||
static Quaternion EulerToQuaternion(Vector3 v);
|
||||
static char* StringToUTF8(String^ s);
|
||||
static void Init(FbxManager** pSdkManager, FbxScene** pScene);
|
||||
|
||||
ref class Exporter
|
||||
{
|
||||
public:
|
||||
static void Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision,
|
||||
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
|
||||
|
||||
private:
|
||||
bool exportSkins;
|
||||
float boneSize;
|
||||
IImported^ imported;
|
||||
HashSet<String^>^ framePaths;
|
||||
Dictionary<ImportedFrame^, size_t>^ frameToNode;
|
||||
List<ImportedFrame^>^ meshFrames;
|
||||
|
||||
char* cDest;
|
||||
FbxManager* pSdkManager;
|
||||
FbxScene* pScene;
|
||||
FbxExporter* pExporter;
|
||||
FbxArray<FbxSurfacePhong*>* pMaterials;
|
||||
FbxArray<FbxFileTexture*>* pTextures;
|
||||
FbxPose* pBindPose;
|
||||
|
||||
Exporter(String^ name, IImported^ imported, bool allNodes, bool skins, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
|
||||
~Exporter();
|
||||
|
||||
void Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop);
|
||||
void SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones);
|
||||
HashSet<String^>^ SearchHierarchy();
|
||||
void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames);
|
||||
void SetJointsFromImportedMeshes(bool allBones);
|
||||
void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame);
|
||||
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ iMesh);
|
||||
FbxFileTexture* ExportTexture(ImportedTexture^ matTex);
|
||||
void ExportAnimations(bool eulerFilter, float filterValue);
|
||||
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision);
|
||||
void ExportMorphs();
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>AssetStudioFBX</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp" />
|
||||
<ClCompile Include="AssetStudioFBX.cpp" />
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
|
||||
<Project>{7662f8c2-7bfd-442e-a948-a43b4f7eb06e}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBX.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,915 +0,0 @@
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
void Fbx::Exporter::Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision,
|
||||
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
|
||||
{
|
||||
FileInfo^ file = gcnew FileInfo(path);
|
||||
DirectoryInfo^ dir = file->Directory;
|
||||
if (!dir->Exists)
|
||||
{
|
||||
dir->Create();
|
||||
}
|
||||
String^ currentDir = Directory::GetCurrentDirectory();
|
||||
Directory::SetCurrentDirectory(dir->FullName);
|
||||
auto name = Path::GetFileName(path);
|
||||
Exporter^ exporter = gcnew Exporter(name, imported, allNodes, skins, castToBone, boneSize, scaleFactor, versionIndex, isAscii);
|
||||
if (blendShape)
|
||||
{
|
||||
exporter->ExportMorphs();
|
||||
}
|
||||
if (animation)
|
||||
{
|
||||
exporter->ExportAnimations(eulerFilter, filterPrecision);
|
||||
}
|
||||
exporter->pExporter->Export(exporter->pScene);
|
||||
delete exporter;
|
||||
|
||||
Directory::SetCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
Fbx::Exporter::Exporter(String^ name, IImported^ imported, bool allNodes, bool skins, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
|
||||
{
|
||||
this->imported = imported;
|
||||
exportSkins = skins;
|
||||
this->boneSize = boneSize;
|
||||
|
||||
cDest = NULL;
|
||||
pSdkManager = NULL;
|
||||
pScene = NULL;
|
||||
pExporter = NULL;
|
||||
pMaterials = NULL;
|
||||
pTextures = NULL;
|
||||
|
||||
pin_ptr<FbxManager*> pSdkManagerPin = &pSdkManager;
|
||||
pin_ptr<FbxScene*> pScenePin = &pScene;
|
||||
Init(pSdkManagerPin, pScenePin);
|
||||
|
||||
IOS_REF.SetBoolProp(EXP_FBX_MATERIAL, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_TEXTURE, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_EMBEDDED, false);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_SHAPE, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_GOBO, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_ANIMATION, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);
|
||||
|
||||
FbxGlobalSettings& globalSettings = pScene->GetGlobalSettings();
|
||||
globalSettings.SetSystemUnit(FbxSystemUnit(scaleFactor));
|
||||
|
||||
if (imported->AnimationList->Count > 0)
|
||||
{
|
||||
auto ani = imported->AnimationList[0];
|
||||
if (ani->SampleRate == 60.0f)
|
||||
{
|
||||
globalSettings.SetTimeMode(FbxTime::eFrames60);
|
||||
}
|
||||
}
|
||||
|
||||
cDest = StringToUTF8(name);
|
||||
pExporter = FbxExporter::Create(pScene, "");
|
||||
|
||||
int pFileFormat = 0;
|
||||
if (versionIndex == 0)
|
||||
{
|
||||
pFileFormat = 3;
|
||||
if (isAscii)
|
||||
{
|
||||
pFileFormat = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pExporter->SetFileExportVersion(FBXVersion[versionIndex]);
|
||||
if (isAscii)
|
||||
{
|
||||
pFileFormat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pExporter->Initialize(cDest, pFileFormat, pSdkManager->GetIOSettings()))
|
||||
{
|
||||
throw gcnew Exception(gcnew String("Failed to initialize FbxExporter: ") + gcnew String(pExporter->GetStatus().GetErrorString()));
|
||||
}
|
||||
|
||||
framePaths = nullptr;
|
||||
if (!allNodes)
|
||||
{
|
||||
framePaths = SearchHierarchy();
|
||||
if (!framePaths)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pBindPose = FbxPose::Create(pScene, "BindPose");
|
||||
pScene->AddPose(pBindPose);
|
||||
|
||||
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
|
||||
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
|
||||
ExportFrame(pScene->GetRootNode(), imported->RootFrame);
|
||||
|
||||
if (imported->MeshList != nullptr)
|
||||
{
|
||||
SetJointsFromImportedMeshes(castToBone);
|
||||
|
||||
pMaterials = new FbxArray<FbxSurfacePhong*>();
|
||||
pTextures = new FbxArray<FbxFileTexture*>();
|
||||
pMaterials->Reserve(imported->MaterialList->Count);
|
||||
pTextures->Reserve(imported->TextureList->Count);
|
||||
|
||||
for (int i = 0; i < meshFrames->Count; i++)
|
||||
{
|
||||
auto meshFram = meshFrames[i];
|
||||
FbxNode* meshNode = (FbxNode*)frameToNode[meshFram];
|
||||
ImportedMesh^ mesh = ImportedHelpers::FindMesh(meshFram->Path, imported->MeshList);
|
||||
ExportMesh(meshNode, mesh);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetJointsNode(imported->RootFrame, nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
Fbx::Exporter::~Exporter()
|
||||
{
|
||||
imported = nullptr;
|
||||
if (framePaths != nullptr)
|
||||
{
|
||||
framePaths->Clear();
|
||||
}
|
||||
if (frameToNode != nullptr)
|
||||
{
|
||||
frameToNode->Clear();
|
||||
}
|
||||
if (meshFrames != nullptr)
|
||||
{
|
||||
meshFrames->Clear();
|
||||
}
|
||||
|
||||
if (pMaterials != NULL)
|
||||
{
|
||||
delete pMaterials;
|
||||
}
|
||||
if (pTextures != NULL)
|
||||
{
|
||||
delete pTextures;
|
||||
}
|
||||
if (pExporter != NULL)
|
||||
{
|
||||
pExporter->Destroy();
|
||||
}
|
||||
if (pScene != NULL)
|
||||
{
|
||||
pScene->Destroy();
|
||||
}
|
||||
if (pSdkManager != NULL)
|
||||
{
|
||||
pSdkManager->Destroy();
|
||||
}
|
||||
if (cDest != NULL)
|
||||
{
|
||||
delete cDest;
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool castToBone)
|
||||
{
|
||||
size_t pointer;
|
||||
if (frameToNode->TryGetValue(frame, pointer))
|
||||
{
|
||||
auto pNode = (FbxNode*)pointer;
|
||||
if (castToBone)
|
||||
{
|
||||
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
|
||||
pJoint->Size.Set(FbxDouble(boneSize));
|
||||
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
|
||||
pNode->SetNodeAttribute(pJoint);
|
||||
}
|
||||
else if (bonePaths->Contains(frame->Path))
|
||||
{
|
||||
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
|
||||
pJoint->Size.Set(FbxDouble(boneSize));
|
||||
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
|
||||
pNode->SetNodeAttribute(pJoint);
|
||||
|
||||
pJoint = FbxSkeleton::Create(pScene, "");
|
||||
pJoint->Size.Set(FbxDouble(boneSize));
|
||||
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
|
||||
pNode->GetParent()->SetNodeAttribute(pJoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
FbxNull* pNull = FbxNull::Create(pScene, "");
|
||||
if (pNode->GetChildCount() > 0)
|
||||
{
|
||||
pNull->Look.Set(FbxNull::eNone);
|
||||
}
|
||||
|
||||
pNode->SetNodeAttribute(pNull);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
SetJointsNode(frame[i], bonePaths, castToBone);
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<String^>^ Fbx::Exporter::SearchHierarchy()
|
||||
{
|
||||
if (imported->MeshList == nullptr || imported->MeshList->Count == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
HashSet<String^>^ exportFrames = gcnew HashSet<String^>();
|
||||
SearchHierarchy(imported->RootFrame, exportFrames);
|
||||
return exportFrames;
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames)
|
||||
{
|
||||
ImportedMesh^ meshListSome = ImportedHelpers::FindMesh(frame->Path, imported->MeshList);
|
||||
if (meshListSome != nullptr)
|
||||
{
|
||||
ImportedFrame^ parent = frame;
|
||||
while (parent != nullptr)
|
||||
{
|
||||
exportFrames->Add(parent->Path);
|
||||
parent = parent->Parent;
|
||||
}
|
||||
|
||||
List<ImportedBone^>^ boneList = meshListSome->BoneList;
|
||||
if (boneList != nullptr)
|
||||
{
|
||||
for (int i = 0; i < boneList->Count; i++)
|
||||
{
|
||||
if (!exportFrames->Contains(boneList[i]->Path))
|
||||
{
|
||||
ImportedFrame^ boneParent = imported->RootFrame->FindFrameByPath(boneList[i]->Path);
|
||||
while (boneParent != nullptr)
|
||||
{
|
||||
exportFrames->Add(boneParent->Path);
|
||||
boneParent = boneParent->Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
SearchHierarchy(frame[i], exportFrames);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SetJointsFromImportedMeshes(bool castToBone)
|
||||
{
|
||||
if (!exportSkins)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HashSet<String^>^ bonePaths = gcnew HashSet<String^>();
|
||||
for (int i = 0; i < imported->MeshList->Count; i++)
|
||||
{
|
||||
ImportedMesh^ meshList = imported->MeshList[i];
|
||||
List<ImportedBone^>^ boneList = meshList->BoneList;
|
||||
if (boneList != nullptr)
|
||||
{
|
||||
for (int j = 0; j < boneList->Count; j++)
|
||||
{
|
||||
ImportedBone^ bone = boneList[j];
|
||||
bonePaths->Add(bone->Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetJointsNode(imported->RootFrame, bonePaths, castToBone);
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame)
|
||||
{
|
||||
if (framePaths == nullptr || framePaths->Contains(frame->Path))
|
||||
{
|
||||
FbxNode* pFrameNode;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pName,
|
||||
frame->Name,
|
||||
pFrameNode = FbxNode::Create(pScene, pName);
|
||||
);
|
||||
|
||||
pFrameNode->LclScaling.Set(FbxDouble3(frame->LocalScale.X, frame->LocalScale.Y, frame->LocalScale.Z));
|
||||
pFrameNode->LclRotation.Set(FbxDouble3(frame->LocalRotation.X, frame->LocalRotation.Y, frame->LocalRotation.Z));
|
||||
pFrameNode->LclTranslation.Set(FbxDouble3(frame->LocalPosition.X, frame->LocalPosition.Y, frame->LocalPosition.Z));
|
||||
pFrameNode->SetPreferedAngle(pFrameNode->LclRotation.Get());
|
||||
pParentNode->AddChild(pFrameNode);
|
||||
pBindPose->Add(pFrameNode, pFrameNode->EvaluateGlobalTransform());
|
||||
|
||||
if (imported->MeshList != nullptr && ImportedHelpers::FindMesh(frame->Path, imported->MeshList) != nullptr)
|
||||
{
|
||||
meshFrames->Add(frame);
|
||||
}
|
||||
|
||||
frameToNode->Add(frame, (size_t)pFrameNode);
|
||||
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
ExportFrame(pFrameNode, frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ iMesh)
|
||||
{
|
||||
List<ImportedBone^>^ boneList = iMesh->BoneList;
|
||||
bool hasBones;
|
||||
if (exportSkins && boneList != nullptr)
|
||||
{
|
||||
hasBones = boneList->Count > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasBones = false;
|
||||
}
|
||||
|
||||
FbxArray<FbxCluster*>* pClusterArray = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
if (hasBones)
|
||||
{
|
||||
pClusterArray = new FbxArray<FbxCluster*>(boneList->Count);
|
||||
|
||||
for (int i = 0; i < boneList->Count; i++)
|
||||
{
|
||||
auto bone = boneList[i];
|
||||
if (bone->Path != nullptr)
|
||||
{
|
||||
auto frame = imported->RootFrame->FindFrameByPath(bone->Path);
|
||||
auto boneNode = (FbxNode*)frameToNode[frame];
|
||||
FbxString lClusterName = boneNode->GetNameOnly() + FbxString("Cluster");
|
||||
FbxCluster* pCluster = FbxCluster::Create(pScene, lClusterName.Buffer());
|
||||
pCluster->SetLink(boneNode);
|
||||
pCluster->SetLinkMode(FbxCluster::eTotalOne);
|
||||
pClusterArray->Add(pCluster);
|
||||
}
|
||||
else
|
||||
{
|
||||
pClusterArray->Add(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FbxMesh* pMesh = FbxMesh::Create(pScene, pFrameNode->GetName());
|
||||
pFrameNode->SetNodeAttribute(pMesh);
|
||||
|
||||
int vertexCount = 0;
|
||||
for (int i = 0; i < iMesh->SubmeshList->Count; i++)
|
||||
{
|
||||
vertexCount += iMesh->SubmeshList[i]->VertexList->Count;
|
||||
}
|
||||
|
||||
pMesh->InitControlPoints(vertexCount);
|
||||
FbxVector4* pControlPoints = pMesh->GetControlPoints();
|
||||
|
||||
FbxGeometryElementNormal* lGeometryElementNormal = NULL;
|
||||
if (iMesh->hasNormal)
|
||||
{
|
||||
lGeometryElementNormal = pMesh->CreateElementNormal();
|
||||
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
if (iMesh->hasUV[0])
|
||||
{
|
||||
auto lGeometryElementUV = pMesh->CreateElementUV("UV0", FbxLayerElement::eTextureDiffuse);
|
||||
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
if (iMesh->hasUV[1])
|
||||
{
|
||||
auto lGeometryElementUV = pMesh->CreateElementUV("UV1", FbxLayerElement::eTextureNormalMap);
|
||||
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
/*for (int uv = 0; uv < 8; uv++)
|
||||
{
|
||||
if (iMesh->hasUV[uv])
|
||||
{
|
||||
auto lGeometryElementUV = pMesh->CreateElementUV(FbxString("UV") + FbxString(uv));
|
||||
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
}*/
|
||||
|
||||
FbxGeometryElementTangent* lGeometryElementTangent = NULL;
|
||||
if (iMesh->hasTangent)
|
||||
{
|
||||
lGeometryElementTangent = pMesh->CreateElementTangent();
|
||||
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
FbxGeometryElementVertexColor* lGeometryElementVertexColor = NULL;
|
||||
if (iMesh->hasColor)
|
||||
{
|
||||
lGeometryElementVertexColor = pMesh->CreateElementVertexColor();
|
||||
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
FbxGeometryElementMaterial* lGeometryElementMaterial = pMesh->CreateElementMaterial();
|
||||
lGeometryElementMaterial->SetMappingMode(FbxGeometryElement::eByPolygon);
|
||||
lGeometryElementMaterial->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
|
||||
|
||||
int firstVertex = 0;
|
||||
for (int i = 0; i < iMesh->SubmeshList->Count; i++)
|
||||
{
|
||||
ImportedSubmesh^ meshObj = iMesh->SubmeshList[i];
|
||||
List<ImportedVertex^>^ vertexList = meshObj->VertexList;
|
||||
List<ImportedFace^>^ faceList = meshObj->FaceList;
|
||||
|
||||
int materialIndex = 0;
|
||||
ImportedMaterial^ mat = ImportedHelpers::FindMaterial(meshObj->Material, imported->MaterialList);
|
||||
if (mat != nullptr)
|
||||
{
|
||||
char* pMatName = NULL;
|
||||
try
|
||||
{
|
||||
pMatName = StringToUTF8(mat->Name);
|
||||
int foundMat = -1;
|
||||
for (int j = 0; j < pMaterials->GetCount(); j++)
|
||||
{
|
||||
FbxSurfacePhong* pMatTemp = pMaterials->GetAt(j);
|
||||
if (strcmp(pMatTemp->GetName(), pMatName) == 0)
|
||||
{
|
||||
foundMat = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FbxSurfacePhong* pMat;
|
||||
if (foundMat >= 0)
|
||||
{
|
||||
pMat = pMaterials->GetAt(foundMat);
|
||||
}
|
||||
else
|
||||
{
|
||||
FbxString lShadingName = "Phong";
|
||||
Color diffuse = mat->Diffuse;
|
||||
Color ambient = mat->Ambient;
|
||||
Color emissive = mat->Emissive;
|
||||
Color specular = mat->Specular;
|
||||
Color reflection = mat->Reflection;
|
||||
pMat = FbxSurfacePhong::Create(pScene, pMatName);
|
||||
pMat->Diffuse.Set(FbxDouble3(diffuse.R, diffuse.G, diffuse.B));
|
||||
//pMat->DiffuseFactor.Set(FbxDouble(diffuse.A));
|
||||
pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B));
|
||||
//pMat->AmbientFactor.Set(FbxDouble(ambient.A));
|
||||
pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B));
|
||||
//pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
|
||||
pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B));
|
||||
//pMat->SpecularFactor.Set(FbxDouble(specular.A));
|
||||
pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B));
|
||||
//pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
|
||||
pMat->Shininess.Set(FbxDouble(mat->Shininess));
|
||||
pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency));
|
||||
pMat->ShadingModel.Set(lShadingName);
|
||||
pMaterials->Add(pMat);
|
||||
}
|
||||
materialIndex = pFrameNode->AddMaterial(pMat);
|
||||
|
||||
bool hasTexture = false;
|
||||
|
||||
for each (ImportedMaterialTexture ^ texture in mat->Textures)
|
||||
{
|
||||
auto pTexture = ExportTexture(ImportedHelpers::FindTexture(texture->Name, imported->TextureList));
|
||||
if (pTexture != NULL)
|
||||
{
|
||||
if (texture->Dest == 0)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Diffuse);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 1)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->NormalMap);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 2)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Specular);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 3)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Bump);
|
||||
hasTexture = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTexture)
|
||||
{
|
||||
pFrameNode->SetShadingMode(FbxNode::eTextureShading);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
delete pMatName;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < vertexList->Count; j++)
|
||||
{
|
||||
ImportedVertex^ iVertex = vertexList[j];
|
||||
|
||||
Vector3 vertex = iVertex->Vertex;
|
||||
pControlPoints[j + firstVertex] = FbxVector4(vertex.X, vertex.Y, vertex.Z, 0);
|
||||
|
||||
if (iMesh->hasNormal)
|
||||
{
|
||||
Vector3 normal = iVertex->Normal;
|
||||
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
|
||||
}
|
||||
|
||||
//for (int uv = 0; uv < 8; uv++)
|
||||
for (int uv = 0; uv < 2; uv++)
|
||||
{
|
||||
if (iMesh->hasUV[uv])
|
||||
{
|
||||
auto m_UV = iVertex->UV[uv];
|
||||
auto lGeometryElementUV = pMesh->GetElementUV(uv);
|
||||
lGeometryElementUV->GetDirectArray().Add(FbxVector2(m_UV[0], m_UV[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (iMesh->hasTangent)
|
||||
{
|
||||
Vector4 tangent = iVertex->Tangent;
|
||||
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
|
||||
}
|
||||
|
||||
if (iMesh->hasColor)
|
||||
{
|
||||
auto color = iVertex->Color;
|
||||
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(color.R, color.G, color.B, color.A));
|
||||
}
|
||||
|
||||
if (hasBones && iVertex->BoneIndices != nullptr)
|
||||
{
|
||||
auto boneIndices = iVertex->BoneIndices;
|
||||
auto weights4 = iVertex->Weights;
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
if (boneIndices[k] < boneList->Count && weights4[k] > 0)
|
||||
{
|
||||
FbxCluster* pCluster = pClusterArray->GetAt(boneIndices[k]);
|
||||
if (pCluster)
|
||||
{
|
||||
pCluster->AddControlPointIndex(j + firstVertex, weights4[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < faceList->Count; j++)
|
||||
{
|
||||
ImportedFace^ face = faceList[j];
|
||||
pMesh->BeginPolygon(materialIndex);
|
||||
pMesh->AddPolygon(face->VertexIndices[0] + firstVertex);
|
||||
pMesh->AddPolygon(face->VertexIndices[1] + firstVertex);
|
||||
pMesh->AddPolygon(face->VertexIndices[2] + firstVertex);
|
||||
pMesh->EndPolygon();
|
||||
}
|
||||
|
||||
firstVertex += vertexList->Count;
|
||||
}
|
||||
|
||||
if (hasBones)
|
||||
{
|
||||
FbxSkin* pSkin = FbxSkin::Create(pScene, "");
|
||||
FbxAMatrix lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
|
||||
for (int j = 0; j < boneList->Count; j++)
|
||||
{
|
||||
FbxCluster* pCluster = pClusterArray->GetAt(j);
|
||||
if (pCluster)
|
||||
{
|
||||
auto boneMatrix = boneList[j]->Matrix;
|
||||
FbxAMatrix lBoneMatrix;
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
lBoneMatrix.mData[m][n] = boneMatrix[m, n];
|
||||
}
|
||||
}
|
||||
|
||||
pCluster->SetTransformMatrix(lMeshMatrix);
|
||||
pCluster->SetTransformLinkMatrix(lMeshMatrix * lBoneMatrix.Inverse());
|
||||
|
||||
pSkin->AddCluster(pCluster);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkin->GetClusterCount() > 0)
|
||||
{
|
||||
pMesh->AddDeformer(pSkin);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pClusterArray != NULL)
|
||||
{
|
||||
delete pClusterArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FbxFileTexture* Fbx::Exporter::ExportTexture(ImportedTexture^ matTex)
|
||||
{
|
||||
FbxFileTexture* pTex = NULL;
|
||||
|
||||
if (matTex != nullptr)
|
||||
{
|
||||
String^ matTexName = matTex->Name;
|
||||
char* pTexName = NULL;
|
||||
try
|
||||
{
|
||||
pTexName = StringToUTF8(matTexName);
|
||||
int foundTex = -1;
|
||||
for (int i = 0; i < pTextures->GetCount(); i++)
|
||||
{
|
||||
FbxFileTexture* pTexTemp = pTextures->GetAt(i);
|
||||
if (strcmp(pTexTemp->GetName(), pTexName) == 0)
|
||||
{
|
||||
foundTex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundTex >= 0)
|
||||
{
|
||||
pTex = pTextures->GetAt(foundTex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pTex = FbxFileTexture::Create(pScene, pTexName);
|
||||
pTex->SetFileName(pTexName);
|
||||
pTex->SetTextureUse(FbxTexture::eStandard);
|
||||
pTex->SetMappingType(FbxTexture::eUV);
|
||||
pTex->SetMaterialUse(FbxFileTexture::eModelMaterial);
|
||||
pTex->SetSwapUV(false);
|
||||
pTex->SetTranslation(0.0, 0.0);
|
||||
pTex->SetScale(1.0, 1.0);
|
||||
pTex->SetRotation(0.0, 0.0);
|
||||
pTextures->Add(pTex);
|
||||
|
||||
FileInfo^ file = gcnew FileInfo(matTex->Name);
|
||||
BinaryWriter^ writer = gcnew BinaryWriter(file->Create());
|
||||
writer->Write(matTex->Data);
|
||||
writer->Close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
delete pTexName;
|
||||
}
|
||||
}
|
||||
|
||||
return pTex;
|
||||
}
|
||||
|
||||
void Fbx::Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop)
|
||||
{
|
||||
pTexture->SetTranslation(texture->Offset.X, texture->Offset.Y);
|
||||
pTexture->SetScale(texture->Scale.X, texture->Scale.Y);
|
||||
prop.ConnectSrcObject(pTexture);
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportAnimations(bool eulerFilter, float filterPrecision)
|
||||
{
|
||||
auto importedAnimationList = imported->AnimationList;
|
||||
if (importedAnimationList == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FbxAnimCurveFilterUnroll* lFilter = eulerFilter ? new FbxAnimCurveFilterUnroll() : NULL;
|
||||
|
||||
for (int i = 0; i < importedAnimationList->Count; i++)
|
||||
{
|
||||
auto importedAnimation = importedAnimationList[i];
|
||||
FbxString kTakeName;
|
||||
if (importedAnimation->Name)
|
||||
{
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pClipName,
|
||||
importedAnimation->Name,
|
||||
kTakeName = FbxString(pClipName);
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
kTakeName = FbxString("Take") + FbxString(i);
|
||||
}
|
||||
ExportKeyframedAnimation(importedAnimation, kTakeName, lFilter, filterPrecision);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision)
|
||||
{
|
||||
List<ImportedAnimationKeyframedTrack^>^ pAnimationList = parser->TrackList;
|
||||
|
||||
char* lTakeName = kTakeName.Buffer();
|
||||
|
||||
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, lTakeName);
|
||||
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
|
||||
lAnimStack->AddMember(lAnimLayer);
|
||||
|
||||
for (int j = 0; j < pAnimationList->Count; j++)
|
||||
{
|
||||
ImportedAnimationKeyframedTrack^ keyframeList = pAnimationList[j];
|
||||
if (keyframeList->Path == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto frame = imported->RootFrame->FindFrameByPath(keyframeList->Path);
|
||||
if (frame != nullptr)
|
||||
{
|
||||
FbxNode* pNode = (FbxNode*)frameToNode[frame];
|
||||
|
||||
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
FbxAnimCurve* lCurveRX = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveRY = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveRZ = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
FbxAnimCurve* lCurveTX = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveTY = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveTZ = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
|
||||
lCurveSX->KeyModifyBegin();
|
||||
lCurveSY->KeyModifyBegin();
|
||||
lCurveSZ->KeyModifyBegin();
|
||||
lCurveRX->KeyModifyBegin();
|
||||
lCurveRY->KeyModifyBegin();
|
||||
lCurveRZ->KeyModifyBegin();
|
||||
lCurveTX->KeyModifyBegin();
|
||||
lCurveTY->KeyModifyBegin();
|
||||
lCurveTZ->KeyModifyBegin();
|
||||
|
||||
FbxTime lTime;
|
||||
|
||||
for each (auto Scaling in keyframeList->Scalings)
|
||||
{
|
||||
lTime.SetSecondDouble(Scaling->time);
|
||||
|
||||
lCurveSX->KeySet(lCurveSX->KeyAdd(lTime), lTime, Scaling->value.X);
|
||||
lCurveSY->KeySet(lCurveSY->KeyAdd(lTime), lTime, Scaling->value.Y);
|
||||
lCurveSZ->KeySet(lCurveSZ->KeyAdd(lTime), lTime, Scaling->value.Z);
|
||||
}
|
||||
for each (auto Rotation in keyframeList->Rotations)
|
||||
{
|
||||
lTime.SetSecondDouble(Rotation->time);
|
||||
|
||||
lCurveRX->KeySet(lCurveRX->KeyAdd(lTime), lTime, Rotation->value.X);
|
||||
lCurveRY->KeySet(lCurveRY->KeyAdd(lTime), lTime, Rotation->value.Y);
|
||||
lCurveRZ->KeySet(lCurveRZ->KeyAdd(lTime), lTime, Rotation->value.Z);
|
||||
}
|
||||
for each (auto Translation in keyframeList->Translations)
|
||||
{
|
||||
lTime.SetSecondDouble(Translation->time);
|
||||
|
||||
lCurveTX->KeySet(lCurveTX->KeyAdd(lTime), lTime, Translation->value.X);
|
||||
lCurveTY->KeySet(lCurveTY->KeyAdd(lTime), lTime, Translation->value.Y);
|
||||
lCurveTZ->KeySet(lCurveTZ->KeyAdd(lTime), lTime, Translation->value.Z);
|
||||
}
|
||||
|
||||
lCurveSX->KeyModifyEnd();
|
||||
lCurveSY->KeyModifyEnd();
|
||||
lCurveSZ->KeyModifyEnd();
|
||||
lCurveRX->KeyModifyEnd();
|
||||
lCurveRY->KeyModifyEnd();
|
||||
lCurveRZ->KeyModifyEnd();
|
||||
lCurveTX->KeyModifyEnd();
|
||||
lCurveTY->KeyModifyEnd();
|
||||
lCurveTZ->KeyModifyEnd();
|
||||
|
||||
if (eulerFilter)
|
||||
{
|
||||
FbxAnimCurve* lCurve[3];
|
||||
lCurve[0] = lCurveRX;
|
||||
lCurve[1] = lCurveRY;
|
||||
lCurve[2] = lCurveRZ;
|
||||
eulerFilter->Reset();
|
||||
eulerFilter->SetQualityTolerance(filterPrecision);
|
||||
eulerFilter->Apply(lCurve, 3);
|
||||
}
|
||||
|
||||
//BlendShape
|
||||
if (keyframeList->BlendShape != nullptr)
|
||||
{
|
||||
FbxString channelName;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pClipName,
|
||||
keyframeList->BlendShape->ChannelName,
|
||||
channelName = FbxString(pClipName);
|
||||
);
|
||||
|
||||
auto lGeometry = (FbxGeometry*)pNode->GetNodeAttribute();
|
||||
int lBlendShapeDeformerCount = lGeometry->GetDeformerCount(FbxDeformer::eBlendShape);
|
||||
if (lBlendShapeDeformerCount > 0)
|
||||
{
|
||||
FbxBlendShape* lBlendShape = (FbxBlendShape*)lGeometry->GetDeformer(0, FbxDeformer::eBlendShape);
|
||||
int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount();
|
||||
for (int lChannelIndex = 0; lChannelIndex < lBlendShapeChannelCount; ++lChannelIndex)
|
||||
{
|
||||
FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex);
|
||||
FbxString lChannelName = lChannel->GetNameOnly();
|
||||
if (lChannelName == channelName)
|
||||
{
|
||||
FbxAnimCurve* lAnimCurve = lGeometry->GetShapeChannel(0, lChannelIndex, lAnimLayer, true);
|
||||
lAnimCurve->KeyModifyBegin();
|
||||
|
||||
for each (auto keyframe in keyframeList->BlendShape->Keyframes)
|
||||
{
|
||||
lTime.SetSecondDouble(keyframe->time);
|
||||
int lKeyIndex = lAnimCurve->KeyAdd(lTime);
|
||||
lAnimCurve->KeySetValue(lKeyIndex, keyframe->value);
|
||||
lAnimCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
|
||||
}
|
||||
|
||||
lAnimCurve->KeyModifyEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportMorphs()
|
||||
{
|
||||
if (imported->MeshList == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for each (ImportedMorph ^ morph in imported->MorphList)
|
||||
{
|
||||
auto frame = imported->RootFrame->FindFrameByPath(morph->Path);
|
||||
if (frame != nullptr)
|
||||
{
|
||||
FbxNode* pNode = (FbxNode*)frameToNode[frame];
|
||||
FbxMesh* pMesh = pNode->GetMesh();
|
||||
|
||||
FbxBlendShape* lBlendShape = FbxBlendShape::Create(pScene, pMesh->GetNameOnly() + FbxString("BlendShape"));
|
||||
pMesh->AddDeformer(lBlendShape);
|
||||
|
||||
for (int i = 0; i < morph->Channels->Count; i++)
|
||||
{
|
||||
auto channel = morph->Channels[i];
|
||||
|
||||
FbxBlendShapeChannel* lBlendShapeChannel;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pChannelName,
|
||||
channel->Name,
|
||||
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, pChannelName);
|
||||
);
|
||||
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
|
||||
|
||||
for each (ImportedMorphKeyframe ^ keyframe in channel->KeyframeList)
|
||||
{
|
||||
FbxShape* lShape = FbxShape::Create(pScene, FbxString(keyframe->Weight));
|
||||
lBlendShapeChannel->AddTargetShape(lShape, keyframe->Weight);
|
||||
|
||||
auto vectorCount = pMesh->GetControlPointsCount();
|
||||
FbxVector4* orilVector4 = pMesh->GetControlPoints();
|
||||
lShape->InitControlPoints(vectorCount);
|
||||
FbxVector4* lVector4 = lShape->GetControlPoints();
|
||||
|
||||
for (int j = 0; j < vectorCount; j++)
|
||||
{
|
||||
auto vertex = orilVector4[j];
|
||||
lVector4[j] = FbxVector4(vertex);
|
||||
}
|
||||
for (int j = 0; j < keyframe->VertexList->Count; j++)
|
||||
{
|
||||
auto index = keyframe->VertexList[j]->Index;
|
||||
auto vertex = keyframe->VertexList[j]->Vertex->Vertex;
|
||||
lVector4[index] = FbxVector4(vertex.X, vertex.Y, vertex.Z, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
AssetStudioFBXNative/AssetStudioFBXNative.rc
Normal file
99
AssetStudioFBXNative/AssetStudioFBXNative.rc
Normal file
@@ -0,0 +1,99 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Language neutral resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "AssetStudioFBXNative"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "InternalName", "AssetStudioFBXNative.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) Perfare 2018-2020; Copyright (C) hozuki 2020"
|
||||
VALUE "OriginalFilename", "AssetStudioFBXNative.dll"
|
||||
VALUE "ProductName", "AssetStudioFBXNative"
|
||||
VALUE "ProductVersion", "1.0.0.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // Language neutral resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
204
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj
Normal file
204
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{11ea25a3-ed68-40ee-a9d0-7fde3b583027}</ProjectGuid>
|
||||
<RootNamespace>AssetStudioFBXNative</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x86\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x64\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.2.1\lib\vs2019\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asfbx_anim_context.cpp" />
|
||||
<ClCompile Include="asfbx_context.cpp" />
|
||||
<ClCompile Include="api.cpp" />
|
||||
<ClCompile Include="asfbx_morph_context.cpp" />
|
||||
<ClCompile Include="asfbx_skin_context.cpp" />
|
||||
<ClCompile Include="utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="asfbx_anim_context.h" />
|
||||
<ClInclude Include="asfbx_context.h" />
|
||||
<ClInclude Include="asfbx_morph_context.h" />
|
||||
<ClInclude Include="asfbx_skin_context.h" />
|
||||
<ClInclude Include="bool32_t.h" />
|
||||
<ClInclude Include="dllexport.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AssetStudioFBXNative.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<Target Name="AfterBuild">
|
||||
<MSBuild Condition=" '$(Platform)' == 'Win32' " Projects="$(MSBuildProjectFile)" Properties="Platform=x64;PlatFormTarget=x64" RunEachTargetSeparately="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
74
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj.filters
Normal file
74
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj.filters
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="utils.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="api.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_skin_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_anim_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_morph_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dllexport.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bool32_t.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_skin_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_anim_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_morph_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AssetStudioFBXNative.rc">
|
||||
<Filter>资源文件</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1163
AssetStudioFBXNative/api.cpp
Normal file
1163
AssetStudioFBXNative/api.cpp
Normal file
File diff suppressed because it is too large
Load Diff
161
AssetStudioFBXNative/api.h
Normal file
161
AssetStudioFBXNative/api.h
Normal file
@@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#include "dllexport.h"
|
||||
#include "bool32_t.h"
|
||||
|
||||
namespace fbxsdk
|
||||
{
|
||||
class FbxNode;
|
||||
class FbxFileTexture;
|
||||
template<typename T, const int Alignment = 16>
|
||||
class FbxArray;
|
||||
class FbxCluster;
|
||||
class FbxMesh;
|
||||
class FbxSurfacePhong;
|
||||
}
|
||||
|
||||
struct AsFbxContext;
|
||||
struct AsFbxSkinContext;
|
||||
struct AsFbxAnimContext;
|
||||
struct AsFbxMorphContext;
|
||||
|
||||
AS_API(void) AsUtilQuaternionToEuler(float qx, float qy, float qz, float qw, float* vx, float* vy, float* vz);
|
||||
|
||||
AS_API(void) AsUtilEulerToQuaternion(float vx, float vy, float vz, float* qx, float* qy, float* qz, float* qw);
|
||||
|
||||
// All strings ([const] char *) in this header are UTF-8 strings.
|
||||
|
||||
AS_API(AsFbxContext*) AsFbxCreateContext();
|
||||
|
||||
// Do not free pErrMsg
|
||||
AS_API(bool32_t) AsFbxInitializeContext(AsFbxContext* pContext, const char* pFileName, float scaleFactor, int32_t versionIndex, bool32_t isAscii, bool32_t is60Fps, const char** pErrMsg);
|
||||
|
||||
AS_API(void) AsFbxDisposeContext(AsFbxContext** ppContext);
|
||||
|
||||
AS_API(void) AsFbxSetFramePaths(AsFbxContext* pContext, const char* ppPaths[], int32_t count);
|
||||
|
||||
AS_API(void) AsFbxExportScene(AsFbxContext* pContext);
|
||||
|
||||
AS_API(fbxsdk::FbxNode*) AsFbxGetSceneRootNode(AsFbxContext* pContext);
|
||||
|
||||
AS_API(fbxsdk::FbxNode*) AsFbxExportSingleFrame(AsFbxContext* pContext, fbxsdk::FbxNode* pParentNode, const char* pFramePath, const char* pFrameName, float localPositionX, float localPositionY, float localPositionZ, float localRotationX, float localRotationY, float localRotationZ, float localScaleX, float localScaleY, float localScaleZ);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_CastToBone(AsFbxContext* pContext, fbxsdk::FbxNode* pNode, float boneSize);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_BoneInPath(AsFbxContext* pContext, fbxsdk::FbxNode* pNode, float boneSize);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_Generic(AsFbxContext* pContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
AS_API(void) AsFbxPrepareMaterials(AsFbxContext* pContext, int32_t materialCount, int32_t textureCount);
|
||||
|
||||
AS_API(fbxsdk::FbxFileTexture*) AsFbxCreateTexture(AsFbxContext* pContext, const char* pMatTexName);
|
||||
|
||||
AS_API(void) AsFbxLinkTexture(int32_t dest, fbxsdk::FbxFileTexture* pTexture, fbxsdk::FbxSurfacePhong* pMaterial, float offsetX, float offsetY, float scaleX, float scaleY);
|
||||
|
||||
AS_API(fbxsdk::FbxArray<fbxsdk::FbxCluster*>*) AsFbxMeshCreateClusterArray(int32_t boneCount);
|
||||
|
||||
AS_API(void) AsFbxMeshDisposeClusterArray(fbxsdk::FbxArray<fbxsdk::FbxCluster*>** ppArray);
|
||||
|
||||
AS_API(fbxsdk::FbxCluster*) AsFbxMeshCreateCluster(AsFbxContext* pContext, fbxsdk::FbxNode* pBoneNode);
|
||||
|
||||
AS_API(void) AsFbxMeshAddCluster(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pArray, /* CanBeNull */ fbxsdk::FbxCluster* pCluster);
|
||||
|
||||
AS_API(fbxsdk::FbxMesh*) AsFbxMeshCreateMesh(AsFbxContext* pContext, fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshInitControlPoints(fbxsdk::FbxMesh* pMesh, int32_t vertexCount);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementNormal(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateDiffuseUV(fbxsdk::FbxMesh* pMesh, int32_t uv);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateNormalMapUV(fbxsdk::FbxMesh* pMesh, int32_t uv);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementTangent(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementVertexColor(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementMaterial(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(fbxsdk::FbxSurfacePhong*) AsFbxCreateMaterial(AsFbxContext* pContext, const char* pMatName,
|
||||
float diffuseR, float diffuseG, float diffuseB,
|
||||
float ambientR, float ambientG, float ambientB,
|
||||
float emissiveR, float emissiveG, float emissiveB,
|
||||
float specularR, float specularG, float specularB,
|
||||
float reflectR, float reflectG, float reflectB,
|
||||
float shininess, float transparency);
|
||||
|
||||
AS_API(int32_t) AsFbxAddMaterialToFrame(fbxsdk::FbxNode* pFrameNode, fbxsdk::FbxSurfacePhong* pMaterial);
|
||||
|
||||
AS_API(void) AsFbxSetFrameShadingModeToTextureShading(fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshSetControlPoint(fbxsdk::FbxMesh* pMesh, int32_t index, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMeshAddPolygon(fbxsdk::FbxMesh* pMesh, int32_t materialIndex, int32_t index0, int32_t index1, int32_t index2);
|
||||
|
||||
AS_API(void) AsFbxMeshElementNormalAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMeshElementUVAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float u, float v);
|
||||
|
||||
AS_API(void) AsFbxMeshElementTangentAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float x, float y, float z, float w);
|
||||
|
||||
AS_API(void) AsFbxMeshElementVertexColorAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float r, float g, float b, float a);
|
||||
|
||||
AS_API(void) AsFbxMeshSetBoneWeight(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t boneIndex, int32_t vertexIndex, float weight);
|
||||
|
||||
AS_API(AsFbxSkinContext*) AsFbxMeshCreateSkinContext(AsFbxContext* pContext, fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshDisposeSkinContext(AsFbxSkinContext** ppSkinContext);
|
||||
|
||||
AS_API(bool32_t) FbxClusterArray_HasItemAt(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t index);
|
||||
|
||||
AS_API(void) AsFbxMeshSkinAddCluster(AsFbxSkinContext* pSkinContext, fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t index, float pBoneMatrix[16]);
|
||||
|
||||
AS_API(void) AsFbxMeshAddDeformer(AsFbxSkinContext* pSkinContext, fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(AsFbxAnimContext*) AsFbxAnimCreateContext(bool32_t eulerFilter);
|
||||
|
||||
AS_API(void) AsFbxAnimDisposeContext(AsFbxAnimContext** ppAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimPrepareStackAndLayer(AsFbxContext* pContext, AsFbxAnimContext* pAnimContext, const char* pTakeName);
|
||||
|
||||
AS_API(void) AsFbxAnimLoadCurves(fbxsdk::FbxNode* pNode, AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimBeginKeyModify(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimEndKeyModify(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimAddScalingKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimAddRotationKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimAddTranslationKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimApplyEulerFilter(AsFbxAnimContext* pAnimContext, float filterPrecision);
|
||||
|
||||
AS_API(int32_t) AsFbxAnimGetCurrentBlendShapeChannelCount(AsFbxAnimContext* pAnimContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
AS_API(bool32_t) AsFbxAnimIsBlendShapeChannelMatch(AsFbxAnimContext* pAnimContext, int32_t channelIndex, const char* channelName);
|
||||
|
||||
AS_API(void) AsFbxAnimBeginBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext, int32_t channelIndex);
|
||||
|
||||
AS_API(void) AsFbxAnimEndBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimAddBlendShapeKeyframe(AsFbxAnimContext* pAnimContext, float time, float value);
|
||||
|
||||
AS_API(AsFbxMorphContext*) AsFbxMorphCreateContext();
|
||||
|
||||
AS_API(void) AsFbxMorphInitializeContext(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
AS_API(void) AsFbxMorphDisposeContext(AsFbxMorphContext** ppMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannel(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, const char* channelName);
|
||||
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight, const char* shapeName);
|
||||
|
||||
AS_API(void) AsFbxMorphCopyBlendShapeControlPoints(AsFbxMorphContext* pMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphSetBlendShapeVertex(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMorphCopyBlendShapeControlPointsNormal(AsFbxMorphContext* pMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphSetBlendShapeVertexNormal(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
|
||||
27
AssetStudioFBXNative/asfbx_anim_context.cpp
Normal file
27
AssetStudioFBXNative/asfbx_anim_context.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "asfbx_anim_context.h"
|
||||
|
||||
AsFbxAnimContext::AsFbxAnimContext(bool32_t eulerFilter)
|
||||
: lFilter(nullptr)
|
||||
{
|
||||
if (eulerFilter)
|
||||
{
|
||||
lFilter = new FbxAnimCurveFilterUnroll();
|
||||
}
|
||||
|
||||
lAnimStack = nullptr;
|
||||
lAnimLayer = nullptr;
|
||||
|
||||
lCurveSX = nullptr;
|
||||
lCurveSY = nullptr;
|
||||
lCurveSZ = nullptr;
|
||||
lCurveRX = nullptr;
|
||||
lCurveRY = nullptr;
|
||||
lCurveRZ = nullptr;
|
||||
lCurveTX = nullptr;
|
||||
lCurveTY = nullptr;
|
||||
lCurveTZ = nullptr;
|
||||
|
||||
pMesh = nullptr;
|
||||
lBlendShape = nullptr;
|
||||
lAnimCurve = nullptr;
|
||||
}
|
||||
32
AssetStudioFBXNative/asfbx_anim_context.h
Normal file
32
AssetStudioFBXNative/asfbx_anim_context.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#include "bool32_t.h"
|
||||
|
||||
struct AsFbxAnimContext
|
||||
{
|
||||
|
||||
FbxAnimCurveFilterUnroll* lFilter;
|
||||
|
||||
FbxAnimStack* lAnimStack;
|
||||
FbxAnimLayer* lAnimLayer;
|
||||
|
||||
FbxAnimCurve* lCurveSX;
|
||||
FbxAnimCurve* lCurveSY;
|
||||
FbxAnimCurve* lCurveSZ;
|
||||
FbxAnimCurve* lCurveRX;
|
||||
FbxAnimCurve* lCurveRY;
|
||||
FbxAnimCurve* lCurveRZ;
|
||||
FbxAnimCurve* lCurveTX;
|
||||
FbxAnimCurve* lCurveTY;
|
||||
FbxAnimCurve* lCurveTZ;
|
||||
|
||||
FbxMesh* pMesh;
|
||||
FbxBlendShape* lBlendShape;
|
||||
FbxAnimCurve* lAnimCurve;
|
||||
|
||||
AsFbxAnimContext(bool32_t eulerFilter);
|
||||
~AsFbxAnimContext() = default;
|
||||
|
||||
};
|
||||
33
AssetStudioFBXNative/asfbx_context.cpp
Normal file
33
AssetStudioFBXNative/asfbx_context.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#include "asfbx_context.h"
|
||||
|
||||
AsFbxContext::AsFbxContext()
|
||||
{
|
||||
pSdkManager = nullptr;
|
||||
pScene = nullptr;
|
||||
pTextures = nullptr;
|
||||
pMaterials = nullptr;
|
||||
pExporter = nullptr;
|
||||
pBindPose = nullptr;
|
||||
}
|
||||
|
||||
AsFbxContext::~AsFbxContext()
|
||||
{
|
||||
framePaths.clear();
|
||||
|
||||
delete pMaterials;
|
||||
delete pTextures;
|
||||
|
||||
if (pExporter != nullptr) {
|
||||
pExporter->Destroy();
|
||||
}
|
||||
|
||||
if (pScene != nullptr) {
|
||||
pScene->Destroy();
|
||||
}
|
||||
|
||||
if (pSdkManager != nullptr) {
|
||||
pSdkManager->Destroy();
|
||||
}
|
||||
}
|
||||
21
AssetStudioFBXNative/asfbx_context.h
Normal file
21
AssetStudioFBXNative/asfbx_context.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
struct AsFbxContext
|
||||
{
|
||||
|
||||
fbxsdk::FbxManager* pSdkManager;
|
||||
fbxsdk::FbxScene* pScene;
|
||||
fbxsdk::FbxArray<fbxsdk::FbxFileTexture*>* pTextures;
|
||||
fbxsdk::FbxArray<fbxsdk::FbxSurfacePhong*>* pMaterials;
|
||||
fbxsdk::FbxExporter* pExporter;
|
||||
fbxsdk::FbxPose* pBindPose;
|
||||
|
||||
std::unordered_set<std::string> framePaths;
|
||||
|
||||
AsFbxContext();
|
||||
~AsFbxContext();
|
||||
};
|
||||
9
AssetStudioFBXNative/asfbx_morph_context.cpp
Normal file
9
AssetStudioFBXNative/asfbx_morph_context.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "asfbx_morph_context.h"
|
||||
|
||||
AsFbxMorphContext::AsFbxMorphContext()
|
||||
{
|
||||
pMesh = nullptr;
|
||||
lBlendShape = nullptr;
|
||||
lBlendShapeChannel = nullptr;
|
||||
lShape = nullptr;
|
||||
}
|
||||
16
AssetStudioFBXNative/asfbx_morph_context.h
Normal file
16
AssetStudioFBXNative/asfbx_morph_context.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
struct AsFbxMorphContext
|
||||
{
|
||||
|
||||
FbxMesh* pMesh;
|
||||
FbxBlendShape* lBlendShape;
|
||||
FbxBlendShapeChannel* lBlendShapeChannel;
|
||||
FbxShape* lShape;
|
||||
|
||||
AsFbxMorphContext();
|
||||
~AsFbxMorphContext() = default;
|
||||
|
||||
};
|
||||
16
AssetStudioFBXNative/asfbx_skin_context.cpp
Normal file
16
AssetStudioFBXNative/asfbx_skin_context.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "asfbx_skin_context.h"
|
||||
#include "asfbx_context.h"
|
||||
|
||||
AsFbxSkinContext::AsFbxSkinContext(AsFbxContext* pContext, FbxNode* pFrameNode)
|
||||
: pSkin(nullptr)
|
||||
{
|
||||
if (pContext != nullptr && pContext->pScene != nullptr)
|
||||
{
|
||||
pSkin = FbxSkin::Create(pContext->pScene, "");
|
||||
}
|
||||
|
||||
if (pFrameNode != nullptr)
|
||||
{
|
||||
lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
|
||||
}
|
||||
}
|
||||
16
AssetStudioFBXNative/asfbx_skin_context.h
Normal file
16
AssetStudioFBXNative/asfbx_skin_context.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
struct AsFbxContext;
|
||||
|
||||
struct AsFbxSkinContext
|
||||
{
|
||||
|
||||
FbxSkin* pSkin;
|
||||
FbxAMatrix lMeshMatrix;
|
||||
|
||||
AsFbxSkinContext(AsFbxContext* pContext, FbxNode* pFrameNode);
|
||||
~AsFbxSkinContext() = default;
|
||||
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user