Compare commits

...

208 Commits

Author SHA1 Message Date
Perfare d158e864b5 support 2022.1 2022-06-16 18:41:55 +08:00
Perfare b70b5196e3 update enum 2022-06-16 17:45:54 +08:00
Perfare 4f88841026 Fixed #962 2022-06-01 15:33:01 +08:00
Perfare dc9429feac minor improvements 2022-05-21 21:16:34 +08:00
Kanglai Qian a3c16ed3d6 avoid useless search for non exist files (#967) 2022-05-21 21:10:02 +08:00
Perfare 5b83eebdda support 2021.3 2022-05-21 17:38:40 +08:00
Perfare 1fcf7a4364 BundleFile fix 2022-05-21 17:24:54 +08:00
Perfare 973d50ce8b Fix type conversion bug 2022-05-21 05:46:44 +08:00
Perfare 50485a9bd3 update project file 2022-03-24 10:38:52 +08:00
Perfare dbb3d3fef7 revert 2022-03-24 09:47:36 +08:00
Perfare e1cfff63c3 minor fixes and improvements 2022-03-23 01:41:59 +08:00
Perfare 44514a4e10 Fixed #941 2022-03-22 22:54:49 +08:00
Perfare b1205808e2 Fix and improve Texture2D convert 2022-03-22 01:00:20 +08:00
Perfare 7d3a4a10fc Create build.yml 2022-03-20 02:36:32 +08:00
Perfare b909857820 Fixed #924 2022-03-19 08:06:03 +08:00
Perfare b674e66407 Fixed #929 2022-03-19 07:48:39 +08:00
Perfare d7dcd3f405 improved Sprite export
Fixed #944
Fixed #923
2022-03-19 07:43:53 +08:00
Perfare 44145e0b9c using IProgress 2022-03-19 06:40:51 +08:00
Perfare d4e21f824c Fixed #919 2022-02-17 01:07:24 +08:00
Rudolf Kolbe e7a4604a65 fix apk loading issues (#913)
* fix apk loading issues

Someone contacted me some days ago and notified me that some problems showed up with my APK loading implementation.
Namely:

file reference registration (importFilesHash) was missing
split files weren't handled
external resource files weren't registered
This pr fixes those problems.

* revert weird changes

* fix missing }

* fix formatting

* use entry.FullName for the basePath instead of entry.Name
2022-02-15 11:19:50 +08:00
Rudolf Kolbe 8d193a63cd Zip (including APK) Loading (#902)
* load ZipFile

makes it possible to directly load apk files

* use LoadFile for recursive zip opening

* set System.IO.Compression version

* keep identical format in AssetStudio.csproj

* try/catch the loading of each zip entry

* remove extra new line in FileReader.cs

* apply requested changes
2021-12-27 15:59:18 +08:00
brianpow e61a317185 use FullPath instead of FileName for easier identification of broken file (#900)
* use FullPath instead of FileName for easier identification of broken file.

* use FullPath instead of FileName for easier identification of broken file
2021-12-24 13:23:09 +08:00
scriptkitz 0e1a886e0b 修正UV导出计算错误问题。 (#891) 2021-12-11 15:48:54 +08:00
Perfare 97b5f51f3a Fix build 2021-12-09 20:23:25 +08:00
Perfare 7295feda72 Update README.md 2021-12-09 19:16:13 +08:00
Perfare fe95c91759 Add net6.0 target framework 2021-12-09 19:00:59 +08:00
Perfare d220315d9b Add detailed export progress in the status bar 2021-12-09 18:08:56 +08:00
Perfare a94caa5e34 Update project 2021-12-09 17:21:44 +08:00
Perfare 3660b4ed67 Some improvements 2021-12-09 17:13:21 +08:00
Perfare 3370f93037 Fixed bug 2021-12-06 17:37:59 +08:00
Perfare 80653711cd Performance improvement 2021-12-06 13:36:22 +08:00
Perfare 88c5804586 Fixed #886 2021-12-04 09:23:41 +08:00
Perfare e501940f03 Use a better way to crop Sprite 2021-12-04 08:44:33 +08:00
Perfare d4060cde6d Fixed bug 2021-12-04 02:05:35 +08:00
Perfare 582a779441 Update project file 2021-12-03 19:46:20 +08:00
Perfare 5fa4934787 Add net5.0 target framework 2021-12-03 17:21:24 +08:00
Perfare 18277fbea8 fixed bug 2021-12-03 17:05:06 +08:00
Perfare 2ce9cae957 Modify the prompt statement 2021-11-20 03:11:02 +08:00
Perfare af5e50cfa9 Update README.md 2021-11-20 02:52:53 +08:00
Perfare ce1172ca9a rename. closed #817 2021-11-19 18:24:18 +08:00
Perfare a7e6d91f5b Fixed bug 2021-11-19 18:22:39 +08:00
Perfare 34a0af683a Fixed bug 2021-11-19 18:11:00 +08:00
Perfare 91410a33b1 Improve the handling of compressed files. 2021-11-19 17:54:06 +08:00
Perfare d08b78c2cf support 2021.2 2021-11-12 10:25:22 +08:00
Perfare 2ef52afe1e Fixed #835 2021-11-12 09:30:12 +08:00
Perfare 05a41d2f1e Merge pull request #855 from nikitalita/fix-assembly-loading
Fix AssemblyLoading bug
2021-11-08 09:36:03 +08:00
nikitalita 34c38e1415 Fix AssemblyLoading bug
If the AssemblyLoader attempted to load a non-csil dll
while iterating through the file list, it would catch the exception
OUTSIDE the loop, and wouldn't load the rest.
This fix makes it catch inside the loop so it will continue iterating.
2021-10-07 13:36:03 -07:00
Perfare c85873b729 0.16.0 2021-07-06 16:03:54 +08:00
Perfare b146d251a7 add option to not show error message 2021-07-06 15:57:59 +08:00
Perfare 3129d67fc1 Improve ShaderConverter 2021-07-06 12:45:24 +08:00
Perfare 850ba63a10 support exporting VideoClips with a size above 2gb. close #765 2021-07-02 03:26:46 +08:00
Perfare 17b91984d6 fixed bug 2021-07-02 02:29:03 +08:00
Perfare 7ab2cda120 refactor the file reading part 2021-07-02 02:17:59 +08:00
Perfare 4345885cc9 remember the last opened path, close #646 2021-06-30 22:41:16 +08:00
Perfare 53720e37ab Fixed #435 2021-06-30 06:31:05 +08:00
Perfare 7c3cb36630 update project files 2021-06-29 11:03:19 +08:00
Perfare c1cddce031 added option to support version stripped files, close #766 2021-06-29 10:32:19 +08:00
Perfare 973a1076e4 support exporting AnimationClip versions below 4.3 2021-06-29 02:43:42 +08:00
Perfare 089e164756 improved Sprite export 2021-06-28 07:14:02 +08:00
Perfare c2b6691fd9 fix build 2021-06-27 09:42:13 +08:00
Perfare 8dec094304 update project files 2021-06-27 09:27:40 +08:00
Perfare bedee240be Use ImageSharp to process textures 2021-06-27 07:33:20 +08:00
Perfare d963d71b12 clean up TypeDefinitionConverter code 2021-06-26 13:16:12 +08:00
Perfare 77a0c9c40a Fbx multiple uv export 2021-06-24 13:48:56 +08:00
Perfare f3e406983b Merge pull request #768 from Fraxul/master
Fix blend shape export with multiple submeshes
2021-06-24 12:59:31 +08:00
Dan Weatherford 08b7bfcf9a Fix blend shape export with multiple submeshes
Share a single vertex list between submeshes in the exported mesh, which
makes the blend target vertex list indices line up correctly.

As a bonus, the exported FBX file will be smaller for meshes with more
than one submesh, since we're not duplicating vertices anymore.
2021-06-20 00:18:22 -05:00
Patrick King 57e4f7cefd Add an option to export all UVs as diffuse maps. 2021-06-11 17:12:15 -06:00
Patrick King c9cf2d188e Enable FBX export for higher UV maps. 2021-06-11 14:26:37 -06:00
Perfare ab98585b6a Fix Shader reading. Close #720 2021-05-29 05:11:05 +08:00
Perfare 075d53a455 small improvement 2021-05-28 23:19:31 +08:00
Perfare 432116d834 Improve SerializedFile reading. 2021-05-28 22:23:07 +08:00
Perfare caa45216ef fix compilation error 2021-05-28 22:16:50 +08:00
Perfare c9394cd957 Fixed #734 2021-05-28 03:49:46 +08:00
Perfare 46c0e8ffe1 Improve stream file processing 2021-05-28 03:43:32 +08:00
Perfare d14c232015 Improve the error message 2021-05-28 03:27:50 +08:00
Perfare 4002bdecb8 Update README.md 2021-05-27 03:55:37 +08:00
StarHeart 17259e00c7 correct grammar (#749) 2021-05-27 03:49:40 +08:00
Perfare 44b02b92d8 fix lzma decompression 2021-05-27 03:46:15 +08:00
Joshua May 251854cc41 Adds exporter for list of assets to XML (#710) 2021-04-18 01:27:15 +08:00
Perfare 6f7b77245d Merge pull request #639 from sk-zk/nul-fix
[GUI] Fix \0 chars in TextAssets cutting off preview
2021-04-18 01:21:16 +08:00
Perfare 6d99f5ebf6 Improve vertex format parsing. Close #689 2021-04-12 15:11:17 +08:00
Perfare f1f2430f97 Support 2021.1 2021-04-11 23:49:44 +08:00
Perfare b52696c965 Merge pull request #713 from K0lb3/patch-1
Update ClassIDType according to official reference
2021-04-11 21:54:45 +08:00
K0lb3 5fba52dc83 Update ClassIDType according to official reference
I noticed that Unity has made a [ClassID Reference table](https://docs.unity3d.com/Manual/ClassIDReference.html) and thought that copying it over here might be useful for dumps.
2021-03-28 14:24:20 -07:00
Perfare dfb74baf79 Fix for mesh weights output 2021-01-15 09:32:57 +08:00
Perfare 978e90a403 Fix if AudioClip does not contain subsound. Close #672 2021-01-15 05:39:45 +08:00
Perfare c17d7d6331 Update README.md 2021-01-15 04:38:54 +08:00
Perfare 9fef18d6ea fixes bug 2021-01-15 04:33:54 +08:00
Perfare ee0cd4ab52 Fixed #609 2021-01-15 03:43:52 +08:00
Perfare f904bc138b typo 2021-01-15 02:17:11 +08:00
Perfare 7ed5345b1b Fixed #652 2021-01-15 02:12:54 +08:00
Perfare d7f652d572 improved Sprite export 2021-01-14 19:27:57 +08:00
Perfare 32ce032655 Support 2020.2 2021-01-14 05:23:19 +08:00
Perfare e1cf36aa3c Fixed #650 2020-12-14 21:20:04 +08:00
sk-zk f644396a15 Fix \0 chars in TextAssets cutting off preview 2020-10-30 23:08:06 +01:00
Perfare 3e77c34bd5 Fixed #618 2020-09-29 07:08:14 +08:00
Perfare 052c60f629 Fix file occupation conflict 2020-09-26 23:29:38 +08:00
Perfare a1f2e3e7fe Merge pull request #613 from Ishotihadus/master
Problems in exporting fbx with multiple blendshapes
2020-09-26 10:18:42 -05:00
Ishotihadus 32ee8b326f fix problems in exporting fbx with multiple blendshapes 2020-09-16 19:44:11 +09:00
Perfare 06ce479eb6 Fixes #591 2020-08-26 09:50:25 +08:00
Perfare 03f74bac64 Fix BlendShape output error 2020-08-24 22:00:53 +08:00
Perfare 344b675745 Update README.md 2020-08-16 18:53:55 +08:00
Perfare 86590d95a5 Add dump viewer 2020-08-14 17:38:43 +08:00
Perfare bbea1341b2 Update README.md 2020-08-14 15:50:45 +08:00
Perfare ca60dd9834 Support exporting MonoBehaviour to json. Close #477 2020-08-14 15:45:48 +08:00
Perfare 7aa35b5b8c Fix get class from divided UnityEngine.dll 2020-08-14 01:31:49 +08:00
Perfare bd2decdb8f Fix element alignment errors 2020-08-14 01:18:43 +08:00
Perfare 9b2c85bcae Refactor MonoBehaviour reading 2020-08-14 00:02:59 +08:00
Perfare efbab7c43a using Nuget 2020-08-12 22:22:04 +08:00
Perfare 729a8a8263 implemented SPIR-V shader export 2020-08-12 22:11:26 +08:00
Perfare 0ec29f62ca Improve shader conversion, fixes #589 2020-08-12 20:49:36 +08:00
Perfare 796317f9d9 support 2020.1 2020-08-12 19:13:10 +08:00
Perfare 7596dcc7cd keep path when extracting folder 2020-08-12 02:55:02 +08:00
Perfare 422851cdab Fix mesh index errors 2020-08-12 02:24:08 +08:00
Perfare ec0a2a47f1 can choose the directory to save the extracted files 2020-08-10 14:07:29 +08:00
Perfare 8ce5b947f6 Update README.md 2020-08-10 11:01:37 +08:00
Perfare 419ca63f9d Set Runtime Library to /MT 2020-08-10 09:52:09 +08:00
Perfare 6fdb0c7b0e add ResourceManager 2020-08-06 23:17:44 +08:00
Perfare 4e97b4b898 improve export 2020-08-06 21:07:37 +08:00
Perfare 1766dcbdeb Fixed #570 2020-08-06 13:31:17 +08:00
Perfare ef38471ff1 move code 2020-08-06 13:11:41 +08:00
Perfare 217a7993e9 fixed bug 2020-08-06 12:56:47 +08:00
Perfare 0a41615763 fix UV problems 2020-08-06 12:34:59 +08:00
Perfare 9d34f668d5 modify project file 2020-08-06 11:59:35 +08:00
Perfare 9269a36725 Merge pull request #555 from Jayatubi/allowdrag
Allow drag and drop files or folder
2020-08-05 21:42:32 -05:00
Jayatubi 813e8b10a6 Export local keywords of shader as well as global keywords (#554)
* Export local keywords of shader

* Export local keywords of shader
2020-08-06 10:39:48 +08:00
Tahvohck 84c75fadf5 Sort code for PathID (change to numeric) (#550)
* Sort code for PathID (change to numeric)

* Remove comments (were only for reference)

* Match Perfare formatting
2020-08-06 10:38:12 +08:00
hozuki c76e41b1ab Replace C++/CLI components with P/Invoke components (#562)
* Replace C++/CLI components with P/Invoke

* Deleted C++/CLI projects

* Use Utf8StringHandle to marshal UTF-8 strings

* Use plaform-default calling convention

* Handle DLL preloading on Linux and macOS

* Change intermediate and output directories of native projects

* Improve P/Invoke documentation
2020-08-06 10:35:50 +08:00
jayatubi fefeea5f35 Allow drag and drop files or folder 2020-05-18 14:17:42 +08:00
Perfare 4a81c461e8 Modify Sprite processing function as an extension function 2020-04-10 18:57:04 +08:00
Perfare b10d03d50d fixed bug 2020-04-10 18:51:43 +08:00
Perfare da98a0c5b8 fixed bug 2020-04-10 18:20:45 +08:00
Perfare 76d17bacf5 improve type read 2020-04-10 18:11:56 +08:00
Perfare 6678ce082b refactor BundleFile read 2020-04-07 16:13:04 +08:00
Perfare 07074b3deb improve SerializedFile read 2020-04-07 08:59:04 +08:00
Perfare df5d9f90d4 Add copy function to assetListView 2020-04-07 08:55:51 +08:00
Perfare 4f2d30552a set UV1 to NormalMap channel 2020-04-07 08:23:13 +08:00
Perfare d259c7a5cd multiple uv export 2020-04-06 19:29:15 +08:00
Perfare c71ceb7ea6 improve SerializedType read 2020-04-06 19:21:48 +08:00
Perfare 85cf134a49 Fixed if the container has the same key 2020-03-30 09:01:25 +08:00
Perfare 687b1d3a0d Fixed get triangles of mesh #510 2020-03-30 08:52:16 +08:00
Perfare a30a0d0bc5 Update README.md 2020-03-28 15:52:15 +08:00
Perfare e1dc54d6d7 use list to store objects in their original order 2020-03-28 14:13:25 +08:00
Perfare c4270e186d fixed bug 2020-03-28 13:46:30 +08:00
Perfare 182a42ace2 optimize ResourceReader 2020-03-28 13:33:37 +08:00
Perfare 06fbe69a97 performance improvement 2020-03-28 04:24:32 +08:00
Perfare a0bf4f9acd update LICENSE 2020-03-28 01:22:26 +08:00
Perfare 12568ba044 fix ico 2020-03-27 21:52:16 +08:00
Perfare de95b02285 update to .net framework 4.7.2 2020-03-27 21:42:40 +08:00
Perfare 286edfe72c improve texture channel filter 2020-03-27 16:52:21 +08:00
Perfare d717b223b7 delete some useless features 2020-03-27 01:06:22 +08:00
Perfare 9e195832ef reduce memory usage 2020-03-26 03:44:07 +08:00
Perfare c8d08b2793 improve file type check 2020-03-26 02:17:48 +08:00
Perfare 2bcd9662be improve export 2020-03-26 01:01:02 +08:00
Perfare ea461ee3d2 improve Texture2D decode 2020-03-25 22:45:53 +08:00
Perfare fda821b441 add more information to the asset list 2020-03-25 14:01:59 +08:00
Perfare 5c193c761a using strong typing for setting 2020-03-25 11:18:12 +08:00
Perfare 14f47c6d30 fixed bug 2020-03-24 14:09:54 +08:00
Perfare e53eacef78 improved 2020-03-24 11:31:57 +08:00
Perfare ada26db659 improved 2020-03-24 10:42:39 +08:00
Perfare 48ca96807f Merge pull request #485 from K0lb3/patch-1
kSPMTight fix
2020-03-24 10:29:01 +08:00
Perfare 2018028853 fixed bug 2020-03-24 09:17:26 +08:00
Perfare 6f138dcc05 Update README.md 2020-03-24 08:52:30 +08:00
Perfare 69bcd2be67 update project 2020-03-24 07:45:47 +08:00
Perfare 45ad53b19a using Nuget 2020-03-24 07:19:59 +08:00
Perfare 6230240ee3 Merge pull request #499 from qiankanglai/master
corner case as protection
2020-03-24 07:09:18 +08:00
Perfare 73ec9f4bee update FBX SDK 2020.0.1 VS2017 2020-03-24 07:04:42 +08:00
Perfare f3a0bf505e refactor Texture2D convert 2020-03-24 06:41:58 +08:00
Kanglai Qian 290708876d corner case as protection 2020-03-14 21:17:34 +08:00
Perfare 5b96a29cca move file 2020-03-14 16:06:21 +08:00
Perfare 948e2c4d92 Merge pull request #495 from qiankanglai/texchannel
texture channel support
2020-03-14 00:02:33 +08:00
Perfare 76da1c33ae Merge pull request #493 from Druhin13/master
Optimized images
2020-03-14 00:01:13 +08:00
Perfare 72b84ee24d Merge pull request #494 from qiankanglai/tga
support exporting texture2d as tga
2020-03-14 00:00:40 +08:00
Kanglai Qian 7b33d41172 texture channel 2020-03-03 12:46:51 +08:00
Kanglai Qian c7043c1a83 support export texture2d as tga 2020-03-03 11:23:36 +08:00
Druhin Tarafder d0baf26c61 Merge pull request #1 from Druhin13/imgbot
Optimized images
2020-03-02 14:39:00 +05:30
ImgBotApp 60ac10b043 [ImgBot] Optimize images
/AssetStudioGUI/Resources/preview.png -- 6.89kb -> 3.87kb (43.78%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2020-03-02 08:56:17 +00:00
Perfare 80dc24b487 Update README.md 2020-02-28 15:41:39 +08:00
Perfare 9d32a9dd6a 2019.3 support 2020-02-28 15:39:11 +08:00
Perfare d96cc3c762 Merge pull request #489 from DaZombieKiller/2020
Support for SerializedFile version 22
2020-02-27 23:09:26 +08:00
Zombie 509df42730 Support for SerializedFile version 22 2020-02-27 20:29:02 +10:00
K0lb3 4efa5b0507 kSPMTight fix
SpritePackingMode.kSPMTight can occur outside of settingsRaw.packed == 1.

[sample file](https://cdn.discordapp.com/attachments/603359898507673632/678238497894563860/kuroyukiwedding_base_1_a)
from Dengeki Bunko: Crossing Void
2020-02-20 09:42:19 +01:00
Perfare cffe96b409 Skip reading failed assets 2019-10-20 08:05:55 +08:00
Perfare 16dddc01e3 always show the debug menu 2019-08-12 05:50:04 +08:00
Perfare b5d2c2cadb improved 2019-08-12 04:36:07 +08:00
Perfare 1d2c0ab6cb Fixed #428 2019-08-12 04:17:06 +08:00
Perfare c6b7e04c47 improved 2019-08-06 17:57:14 +08:00
Perfare 5704813b28 Improved UI 2019-08-06 17:43:51 +08:00
Perfare 465c989e75 fixed bug 2019-08-06 15:49:41 +08:00
Perfare d335aaef9e improved 2019-08-06 09:48:21 +08:00
Perfare 495b48c783 improved Sprite export 2019-08-01 15:23:36 +08:00
Perfare 05b55722fb change text 2019-07-30 03:34:15 +08:00
Perfare de54257eef improved bone export 2019-07-29 13:41:42 +08:00
Perfare e62b6c3d77 improved 2019-07-29 00:31:43 +08:00
Perfare dc05e5b5eb Fixed bug 2019-07-29 00:25:26 +08:00
Perfare f377381e26 Support for exporting raw data 2019-07-28 19:48:06 +08:00
Perfare 20f9fe493f add more options for export model 2019-07-28 18:55:08 +08:00
Perfare 0b462754a5 Implemented BlendShape export 2019-07-28 16:41:23 +08:00
Perfare b1ea8dd346 clean up code 2019-07-28 03:47:12 +08:00
Perfare 4a46f897bd add default values to materials 2019-07-28 00:26:56 +08:00
Perfare 6a5ec80de7 fixed bug 2019-07-27 23:20:47 +08:00
Perfare 4f2046d412 improved 2019-07-27 22:54:18 +08:00
Perfare 1cf59e8d67 fixed bug 2019-07-27 18:01:57 +08:00
Perfare e9e8390bbc Supported merge GameObject to export 2019-07-17 12:51:00 +08:00
Perfare 738b084440 Fixed bug 2019-07-16 17:53:50 +08:00
Perfare 32cce894ac Fixed #373 2019-07-16 17:49:10 +08:00
Perfare a6264b39d1 improved morph export 2019-07-16 13:21:32 +08:00
Perfare eb4981808b Fixed coding errors 2019-07-16 05:32:54 +08:00
221 changed files with 34429 additions and 7807 deletions
+57
View 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
+151 -21
View File
@@ -1,7 +1,10 @@
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files # User-specific files
*.rsuser
*.suo *.suo
*.user *.user
*.userosscache *.userosscache
@@ -15,13 +18,22 @@
[Dd]ebugPublic/ [Dd]ebugPublic/
[Rr]elease/ [Rr]elease/
[Rr]eleases/ [Rr]eleases/
build/ x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory # Visual Studio 2015/2017 cache/options directory
.vs/ .vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results # MSTest test Results
[Tt]est[Rr]esult*/ [Tt]est[Rr]esult*/
@@ -36,18 +48,28 @@ TestResult.xml
[Rr]eleasePS/ [Rr]eleasePS/
dlldata.c dlldata.c
# DNX # Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json project.lock.json
project.fragment.lock.json
artifacts/ artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c *_i.c
*_p.c *_p.c
*_i.h *_h.h
*.ilk *.ilk
*.meta *.meta
*.obj *.obj
*.iobj
*.pch *.pch
*.pdb *.pdb
*.ipdb
*.pgc *.pgc
*.pgd *.pgd
*.rsp *.rsp
@@ -57,6 +79,7 @@ artifacts/
*.tlh *.tlh
*.tmp *.tmp
*.tmp_proj *.tmp_proj
*_wpftmp.csproj
*.log *.log
*.vspscc *.vspscc
*.vssscc *.vssscc
@@ -72,14 +95,21 @@ _Chutzpah*
ipch/ ipch/
*.aps *.aps
*.ncb *.ncb
*.opendb
*.opensdf *.opensdf
*.sdf *.sdf
*.cachefile *.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler # Visual Studio profiler
*.psess *.psess
*.vsp *.vsp
*.vspx *.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace # TFS 2012 Local Workspace
$tf/ $tf/
@@ -101,9 +131,18 @@ _TeamCity*
# DotCover is a Code Coverage Tool # DotCover is a Code Coverage Tool
*.dotCover *.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch # NCrunch
_NCrunch_* _NCrunch_*
.*crunch*.local.xml .*crunch*.local.xml
nCrunchTemp_*
# MightyMoose # MightyMoose
*.mm.* *.mm.*
@@ -131,47 +170,68 @@ publish/
# Publish Web Output # Publish Web Output
*.[Pp]ublish.xml *.[Pp]ublish.xml
*.azurePubxml *.azurePubxml
## TODO: Comment the next line if you want to checkin your # Note: Comment the next line if you want to checkin your web deploy settings,
## web deploy settings but do note that will include unencrypted # but database connection strings (with potential passwords) will be unencrypted
## passwords *.pubxml
#*.pubxml
*.publishproj *.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages # NuGet Packages
*.nupkg *.nupkg
# The packages folder can be ignored because of Package Restore # The packages folder can be ignored because of Package Restore
**/packages/* **/[Pp]ackages/*
# except build/, which is used as an MSBuild target. # except build/, which is used as an MSBuild target.
!**/packages/build/ !**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed # Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config #!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Windows Azure Build Output # Microsoft Azure Build Output
csx/ csx/
*.build.csdef *.build.csdef
# Windows Store app package directory # Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files # Visual Studio cache files
# files ending in .cache can be ignored # files ending in .cache can be ignored
*.[Cc]ache *.[Cc]ache
# but keep track of directories ending in .cache # but keep track of directories ending in .cache
!*.[Cc]ache/ !?*.[Cc]ache/
# Others # Others
ClientBin/ ClientBin/
[Ss]tyle[Cc]op.*
~$* ~$*
*~ *~
*.dbmdl *.dbmdl
*.dbproj.schemaview *.dbproj.schemaview
*.jfm
*.pfx *.pfx
*.publishsettings *.publishsettings
node_modules/
orleans.codegen.cs orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects # RIA/Silverlight projects
Generated_Code/ Generated_Code/
@@ -182,21 +242,30 @@ _UpgradeReport_Files/
Backup*/ Backup*/
UpgradeLog*.XML UpgradeLog*.XML
UpgradeLog*.htm UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files # SQL Server files
*.mdf *.mdf
*.ldf *.ldf
*.ndf
# Business Intelligence projects # Business Intelligence projects
*.rdl.data *.rdl.data
*.bim.layout *.bim.layout
*.bim_*.settings *.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes # Microsoft Fakes
FakesAssemblies/ FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio # Node.js Tools for Visual Studio
.ntvs_analysis.dat .ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log # Visual Studio 6 build log
*.plg *.plg
@@ -204,7 +273,68 @@ FakesAssemblies/
# Visual Studio 6 workspace options file # Visual Studio 6 workspace options file
*.opt *.opt
# LightSwitch generated files # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
GeneratedArtifacts/ *.vbw
_Pvt_Extensions/
ModelManifest.xml # Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;net5.0;net6.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.16.0.0</Version>
<AssemblyVersion>0.16.0.0</AssemblyVersion>
<FileVersion>0.16.0.0</FileVersion>
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project>
+124
View File
@@ -0,0 +1,124 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace AssetStudio.PInvoke
{
public static class DllLoader
{
public static void PreloadDll(string dllName)
{
var dllDir = GetDirectedDllDirectory();
// Not using OperatingSystem.Platform.
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Win32.LoadDll(dllDir, dllName);
}
else
{
Posix.LoadDll(dllDir, dllName);
}
}
private static string GetDirectedDllDirectory()
{
var localPath = Process.GetCurrentProcess().MainModule.FileName;
var localDir = Path.GetDirectoryName(localPath);
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
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;
}
private static class Posix
{
internal static void LoadDll(string dllDir, string dllName)
{
string dllExtension;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
dllExtension = ".so";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
dllExtension = ".dylib";
}
else
{
throw new NotSupportedException();
}
var dllFileName = $"lib{dllName}{dllExtension}";
var directedDllPath = Path.Combine(dllDir, dllFileName);
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
var hLibrary = DlOpen(directedDllPath, ldFlags);
if (hLibrary == IntPtr.Zero)
{
var pErrStr = DlError();
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
// the codepage is UTF-8 so the error message should be handled correctly.
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
throw new DllNotFoundException(errorMessage);
}
}
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
// void *dlopen(const char *filename, int flag);
[DllImport("libdl", EntryPoint = "dlopen")]
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
// char *dlerror(void);
[DllImport("libdl", EntryPoint = "dlerror")]
private static extern IntPtr DlError();
private const int RTLD_LAZY = 0x1;
private const int RTLD_NOW = 0x2;
private const int RTLD_GLOBAL = 0x100;
}
}
}
+100
View 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;
}
}
+119 -39
View File
@@ -1,61 +1,141 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
VisualStudioVersion = 15.0.27130.2024 VisualStudioVersion = 16.0.31410.357
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{422FEC21-EF60-4F29-AA56-95DFDA23C913}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio.PInvoke", "AssetStudio.PInvoke\AssetStudio.PInvoke.csproj", "{0B2BE613-3049-4021-85D1-21C325F729F4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}" 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{AF56B63C-1764-41B7-9E60-8D485422AC3B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{29EAD018-1C67-497A-AB8E-727D595AD756}"
EndProject
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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64 Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x64.ActiveCfg = Debug|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x64.Build.0 = Debug|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.ActiveCfg = Debug|x86 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.ActiveCfg = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.Build.0 = Debug|x86 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.Build.0 = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x64.ActiveCfg = Release|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.ActiveCfg = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x64.Build.0 = Release|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.Build.0 = Debug|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.ActiveCfg = Release|x86 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.Build.0 = Release|x86 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.Build.0 = Release|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x64.ActiveCfg = Debug|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.ActiveCfg = Release|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x64.Build.0 = Debug|x64 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.Build.0 = Release|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x86.ActiveCfg = Debug|Win32 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.ActiveCfg = Release|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x86.Build.0 = Debug|Win32 {422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.Build.0 = Release|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x64.ActiveCfg = Release|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x64.Build.0 = Release|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x86.ActiveCfg = Release|Win32 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.ActiveCfg = Debug|Any CPU
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x86.Build.0 = Release|Win32 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.Build.0 = Debug|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x64.ActiveCfg = Debug|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.ActiveCfg = Debug|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x64.Build.0 = Debug|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.Build.0 = Debug|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x86.ActiveCfg = Debug|x86 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x86.Build.0 = Debug|x86 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.Build.0 = Release|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x64.ActiveCfg = Release|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.ActiveCfg = Release|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x64.Build.0 = Release|x64 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.Build.0 = Release|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x86.ActiveCfg = Release|x86 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.ActiveCfg = Release|Any CPU
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x86.Build.0 = Release|x86 {0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.Build.0 = Release|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x64.ActiveCfg = Debug|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x64.Build.0 = Debug|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x86.ActiveCfg = Debug|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x86.Build.0 = Debug|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.Build.0 = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x64.ActiveCfg = Release|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.ActiveCfg = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x64.Build.0 = Release|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.Build.0 = Debug|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x86.ActiveCfg = Release|Any CPU {E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x86.Build.0 = 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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F5C476A6-2B3B-416F-8BD5-6FE454FF3972} SolutionGuid = {3C074481-9CDD-4780-B9F6-57BBC5092EA2}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
+17 -148
View File
@@ -1,153 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<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')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <TargetFrameworks>net472;netstandard2.0;net5.0;net6.0</TargetFrameworks>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Version>0.16.0.0</Version>
<ProjectGuid>{AF56B63C-1764-41B7-9E60-8D485422AC3B}</ProjectGuid> <AssemblyVersion>0.16.0.0</AssemblyVersion>
<OutputType>Library</OutputType> <FileVersion>0.16.0.0</FileVersion>
<AppDesignerFolder>Properties</AppDesignerFolder> <Copyright>Copyright © Perfare 2018-2022</Copyright>
<RootNamespace>AssetStudio</RootNamespace> <DebugType>embedded</DebugType>
<AssemblyName>AssetStudio</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
<DebugType>full</DebugType> <PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
<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.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="7zip\Common\CommandLineParser.cs" /> <ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<Compile Include="7zip\Common\CRC.cs" /> <PackageReference Include="System.Memory" Version="4.5.4" />
<Compile Include="7zip\Common\InBuffer.cs" /> <PackageReference Include="System.IO.Compression" Version="4.0.0" />
<Compile Include="7zip\Common\OutBuffer.cs" /> <PackageReference Include="K4os.Compression.LZ4" Version="1.1.11" />
<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="Classes\RuntimeAnimatorController.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="UType.cs" />
<Compile Include="ResourceReader.cs" />
<Compile Include="IImported.cs" />
<Compile Include="SerializedFile.cs" />
<Compile Include="AssetsManager.cs" />
<Compile Include="Extensions\BinaryReaderExtensions.cs" />
<Compile Include="Extensions\BinaryWriterExtensions.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\RectTransform.cs" />
<Compile Include="Classes\Renderer.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="FileIdentifier.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="ObjectInfo.cs" />
<Compile Include="ObjectReader.cs" />
<Compile Include="Classes\PPtr.cs" />
<Compile Include="Progress.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SerializedFileHeader.cs" />
<Compile Include="SerializedType.cs" />
<Compile Include="SevenZipHelper.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="TypeTreeHelper.cs" />
<Compile Include="TypeTreeNode.cs" />
<Compile Include="WebFile.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>
+343 -154
View File
@@ -1,23 +1,29 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text;
using static AssetStudio.ImportHelper; using static AssetStudio.ImportHelper;
namespace AssetStudio namespace AssetStudio
{ {
public class AssetsManager public class AssetsManager
{ {
public string SpecifyUnityVersion;
public List<SerializedFile> assetsFileList = new List<SerializedFile>(); public List<SerializedFile> assetsFileList = new List<SerializedFile>();
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>();
internal Dictionary<string, EndianBinaryReader> resourceFileReaders = new Dictionary<string, EndianBinaryReader>(); 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 List<string> importFiles = new List<string>();
private HashSet<string> importFilesHash = new HashSet<string>(); private HashSet<string> importFilesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> assetsFileListHash = new HashSet<string>(); 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 LoadFiles(params string[] files)
{ {
var path = Path.GetDirectoryName(files[0]); var path = Path.GetDirectoryName(Path.GetFullPath(files[0]));
MergeSplitAssets(path); MergeSplitAssets(path);
var toReadFile = ProcessingSplitFiles(files.ToList()); var toReadFile = ProcessingSplitFiles(files.ToList());
Load(toReadFile); Load(toReadFile);
@@ -36,7 +42,7 @@ namespace AssetStudio
foreach (var file in files) foreach (var file in files)
{ {
importFiles.Add(file); importFiles.Add(file);
importFilesHash.Add(Path.GetFileName(file).ToUpper()); importFilesHash.Add(Path.GetFileName(file));
} }
Progress.Reset(); Progress.Reset();
@@ -49,124 +55,153 @@ namespace AssetStudio
importFiles.Clear(); importFiles.Clear();
importFilesHash.Clear(); importFilesHash.Clear();
noexistFiles.Clear();
assetsFileListHash.Clear(); assetsFileListHash.Clear();
ReadAssets(); ReadAssets();
ProcessGameObject(); ProcessAssets();
} }
private void LoadFile(string fullName) 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: case FileType.AssetsFile:
LoadAssetsFile(fullName, reader); LoadAssetsFile(reader);
break; break;
case FileType.BundleFile: case FileType.BundleFile:
LoadBundleFile(fullName, reader); LoadBundleFile(reader);
break; break;
case FileType.WebFile: 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; break;
} }
} }
private void LoadAssetsFile(string fullName, EndianBinaryReader reader) private void LoadAssetsFile(FileReader reader)
{ {
var fileName = Path.GetFileName(fullName); if (!assetsFileListHash.Contains(reader.FileName))
if (!assetsFileListHash.Contains(fileName.ToUpper()))
{ {
Logger.Info($"Loading {fileName}"); Logger.Info($"Loading {reader.FullPath}");
try try
{ {
var assetsFile = new SerializedFile(this, fullName, reader); var assetsFile = new SerializedFile(reader, this);
CheckStrippedVersion(assetsFile);
assetsFileList.Add(assetsFile); assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.upperFileName); assetsFileListHash.Add(assetsFile.fileName);
foreach (var sharedFile in assetsFile.m_Externals) foreach (var sharedFile in assetsFile.m_Externals)
{ {
var sharedFilePath = Path.GetDirectoryName(fullName) + "\\" + sharedFile.fileName;
var sharedFileName = sharedFile.fileName; var sharedFileName = sharedFile.fileName;
if (!importFilesHash.Contains(sharedFileName.ToUpper())) 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 (!File.Exists(sharedFilePath))
if (findFiles.Length > 0)
{ {
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.ToUpper());
} }
} }
} }
} }
catch catch (Exception e)
{ {
Logger.Error($"Error while reading assets file {reader.FullPath}", e);
reader.Dispose(); reader.Dispose();
//Logger.Error($"Unable to load assets file {fileName}");
} }
} }
else else
{ {
Logger.Info($"Skipping {reader.FullPath}");
reader.Dispose(); 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 upperFileName = Path.GetFileName(fullName).ToUpper(); if (!assetsFileListHash.Contains(reader.FileName))
if (!assetsFileListHash.Contains(upperFileName))
{ {
try try
{ {
var assetsFile = new SerializedFile(this, fullName, reader); var assetsFile = new SerializedFile(reader, this);
assetsFile.originalPath = originalPath; assetsFile.originalPath = originalPath;
if (assetsFile.header.m_Version < 7) if (!string.IsNullOrEmpty(unityVersion) && assetsFile.header.m_Version < SerializedFileFormatVersion.Unknown_7)
{ {
assetsFile.SetVersion(unityVersion); assetsFile.SetVersion(unityVersion);
} }
CheckStrippedVersion(assetsFile);
assetsFileList.Add(assetsFile); assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.upperFileName); assetsFileListHash.Add(assetsFile.fileName);
} }
catch catch (Exception e)
{ {
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}"); Logger.Error($"Error while reading assets file {reader.FullPath} from {Path.GetFileName(originalPath)}", e);
} resourceFileReaders.Add(reader.FileName, reader);
finally
{
resourceFileReaders.Add(upperFileName, 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 " + reader.FullPath);
Logger.Info("Loading " + fileName);
try try
{ {
var bundleFile = new BundleFile(reader, fullName); var bundleFile = new BundleFile(reader);
foreach (var file in bundleFile.fileList) foreach (var file in bundleFile.fileList)
{ {
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName; var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
LoadAssetsFromMemory(dummyPath, new EndianBinaryReader(file.stream), parentPath ?? fullName, bundleFile.versionEngine); var subReader = new FileReader(dummyPath, file.stream);
if (subReader.FileType == FileType.AssetsFile)
{
LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision);
}
else
{
resourceFileReaders[file.fileName] = subReader; //TODO
}
} }
} }
catch catch (Exception e)
{ {
/*var str = $"Unable to load bundle file {fileName}"; var str = $"Error while reading bundle file {reader.FullPath}";
if (parentPath != null) if (originalPath != null)
{ {
str += $" from {Path.GetFileName(parentPath)}"; str += $" from {Path.GetFileName(originalPath)}";
} }
Logger.Error(str);*/ Logger.Error(str, e);
} }
finally finally
{ {
@@ -174,33 +209,36 @@ namespace AssetStudio
} }
} }
private void LoadWebFile(string fullName, EndianBinaryReader reader) private void LoadWebFile(FileReader reader)
{ {
var fileName = Path.GetFileName(fullName); Logger.Info("Loading " + reader.FullPath);
Logger.Info("Loading " + fileName);
try try
{ {
var webFile = new WebFile(reader); var webFile = new WebFile(reader);
foreach (var file in webFile.fileList) foreach (var file in webFile.fileList)
{ {
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName; var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
switch (CheckFileType(file.stream, out var fileReader)) var subReader = new FileReader(dummyPath, file.stream);
switch (subReader.FileType)
{ {
case FileType.AssetsFile: case FileType.AssetsFile:
LoadAssetsFromMemory(dummyPath, fileReader, fullName); LoadAssetsFromMemory(subReader, reader.FullPath);
break; break;
case FileType.BundleFile: case FileType.BundleFile:
LoadBundleFile(dummyPath, fileReader, fullName); LoadBundleFile(subReader, reader.FullPath);
break; break;
case FileType.WebFile: case FileType.WebFile:
LoadWebFile(dummyPath, fileReader); LoadWebFile(subReader);
break;
case FileType.ResourceFile:
resourceFileReaders[file.fileName] = subReader; //TODO
break; break;
} }
} }
} }
catch catch (Exception e)
{ {
//Logger.Error($"Unable to load web file {fileName}"); Logger.Error($"Error while reading web file {reader.FullPath}", e);
} }
finally finally
{ {
@@ -208,6 +246,118 @@ namespace AssetStudio
} }
} }
private void LoadZipFile(FileReader reader)
{
Logger.Info("Loading " + 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.Error($"Error while reading zip split file {basePath}", e);
}
}
// load all entries
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);
}
}
}
catch (Exception e)
{
Logger.Error($"Error while reading zip entry {entry.FullName}", 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 Exception("The Unity version has been stripped, please set the version in the options");
}
if (!string.IsNullOrEmpty(SpecifyUnityVersion))
{
assetsFile.SetVersion(SpecifyUnityVersion);
}
}
public void Clear() public void Clear()
{ {
foreach (var assetsFile in assetsFileList) foreach (var assetsFile in assetsFileList)
@@ -235,96 +385,114 @@ namespace AssetStudio
Progress.Reset(); Progress.Reset();
foreach (var assetsFile in assetsFileList) foreach (var assetsFile in assetsFileList)
{ {
assetsFile.Objects = new Dictionary<long, Object>(assetsFile.m_Objects.Count);
foreach (var objectInfo in assetsFile.m_Objects) foreach (var objectInfo in assetsFile.m_Objects)
{ {
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo); var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo);
switch (objectReader.type) try
{ {
case ClassIDType.Animation: Object obj;
assetsFile.Objects.Add(objectInfo.m_PathID, new Animation(objectReader)); switch (objectReader.type)
break; {
case ClassIDType.AnimationClip: case ClassIDType.Animation:
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimationClip(objectReader)); obj = new Animation(objectReader);
break; break;
case ClassIDType.Animator: case ClassIDType.AnimationClip:
assetsFile.Objects.Add(objectInfo.m_PathID, new Animator(objectReader)); obj = new AnimationClip(objectReader);
break; break;
case ClassIDType.AnimatorController: case ClassIDType.Animator:
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorController(objectReader)); obj = new Animator(objectReader);
break; break;
case ClassIDType.AnimatorOverrideController: case ClassIDType.AnimatorController:
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorOverrideController(objectReader)); obj = new AnimatorController(objectReader);
break; break;
case ClassIDType.AssetBundle: case ClassIDType.AnimatorOverrideController:
assetsFile.Objects.Add(objectInfo.m_PathID, new AssetBundle(objectReader)); obj = new AnimatorOverrideController(objectReader);
break; break;
case ClassIDType.AudioClip: case ClassIDType.AssetBundle:
assetsFile.Objects.Add(objectInfo.m_PathID, new AudioClip(objectReader)); obj = new AssetBundle(objectReader);
break; break;
case ClassIDType.Avatar: case ClassIDType.AudioClip:
assetsFile.Objects.Add(objectInfo.m_PathID, new Avatar(objectReader)); obj = new AudioClip(objectReader);
break; break;
case ClassIDType.Font: case ClassIDType.Avatar:
assetsFile.Objects.Add(objectInfo.m_PathID, new Font(objectReader)); obj = new Avatar(objectReader);
break; break;
case ClassIDType.GameObject: case ClassIDType.Font:
assetsFile.Objects.Add(objectInfo.m_PathID, new GameObject(objectReader)); obj = new Font(objectReader);
break; break;
case ClassIDType.Material: case ClassIDType.GameObject:
assetsFile.Objects.Add(objectInfo.m_PathID, new Material(objectReader)); obj = new GameObject(objectReader);
break; break;
case ClassIDType.Mesh: case ClassIDType.Material:
assetsFile.Objects.Add(objectInfo.m_PathID, new Mesh(objectReader)); obj = new Material(objectReader);
break; break;
case ClassIDType.MeshFilter: case ClassIDType.Mesh:
assetsFile.Objects.Add(objectInfo.m_PathID, new MeshFilter(objectReader)); obj = new Mesh(objectReader);
break; break;
case ClassIDType.MeshRenderer: case ClassIDType.MeshFilter:
assetsFile.Objects.Add(objectInfo.m_PathID, new MeshRenderer(objectReader)); obj = new MeshFilter(objectReader);
break; break;
case ClassIDType.MonoBehaviour: case ClassIDType.MeshRenderer:
assetsFile.Objects.Add(objectInfo.m_PathID, new MonoBehaviour(objectReader)); obj = new MeshRenderer(objectReader);
break; break;
case ClassIDType.MonoScript: case ClassIDType.MonoBehaviour:
assetsFile.Objects.Add(objectInfo.m_PathID, new MonoScript(objectReader)); obj = new MonoBehaviour(objectReader);
break; break;
case ClassIDType.MovieTexture: case ClassIDType.MonoScript:
assetsFile.Objects.Add(objectInfo.m_PathID, new MovieTexture(objectReader)); obj = new MonoScript(objectReader);
break; break;
case ClassIDType.PlayerSettings: case ClassIDType.MovieTexture:
assetsFile.Objects.Add(objectInfo.m_PathID, new PlayerSettings(objectReader)); obj = new MovieTexture(objectReader);
break; break;
case ClassIDType.RectTransform: case ClassIDType.PlayerSettings:
assetsFile.Objects.Add(objectInfo.m_PathID, new RectTransform(objectReader)); obj = new PlayerSettings(objectReader);
break; break;
case ClassIDType.Shader: case ClassIDType.RectTransform:
assetsFile.Objects.Add(objectInfo.m_PathID, new Shader(objectReader)); obj = new RectTransform(objectReader);
break; break;
case ClassIDType.SkinnedMeshRenderer: case ClassIDType.Shader:
assetsFile.Objects.Add(objectInfo.m_PathID, new SkinnedMeshRenderer(objectReader)); obj = new Shader(objectReader);
break; break;
case ClassIDType.Sprite: case ClassIDType.SkinnedMeshRenderer:
assetsFile.Objects.Add(objectInfo.m_PathID, new Sprite(objectReader)); obj = new SkinnedMeshRenderer(objectReader);
break; break;
case ClassIDType.SpriteAtlas: case ClassIDType.Sprite:
assetsFile.Objects.Add(objectInfo.m_PathID, new SpriteAtlas(objectReader)); obj = new Sprite(objectReader);
break; break;
case ClassIDType.TextAsset: case ClassIDType.SpriteAtlas:
assetsFile.Objects.Add(objectInfo.m_PathID, new TextAsset(objectReader)); obj = new SpriteAtlas(objectReader);
break; break;
case ClassIDType.Texture2D: case ClassIDType.TextAsset:
assetsFile.Objects.Add(objectInfo.m_PathID, new Texture2D(objectReader)); obj = new TextAsset(objectReader);
break; break;
case ClassIDType.Transform: case ClassIDType.Texture2D:
assetsFile.Objects.Add(objectInfo.m_PathID, new Transform(objectReader)); obj = new Texture2D(objectReader);
break; break;
case ClassIDType.VideoClip: case ClassIDType.Transform:
assetsFile.Objects.Add(objectInfo.m_PathID, new VideoClip(objectReader)); obj = new Transform(objectReader);
break; break;
default: case ClassIDType.VideoClip:
assetsFile.Objects.Add(objectInfo.m_PathID, new Object(objectReader)); obj = new VideoClip(objectReader);
break; break;
case ClassIDType.ResourceManager:
obj = new ResourceManager(objectReader);
break;
default:
obj = new Object(objectReader);
break;
}
assetsFile.AddObject(obj);
}
catch (Exception e)
{
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());
} }
Progress.Report(++i, progressCount); Progress.Report(++i, progressCount);
@@ -332,13 +500,13 @@ namespace AssetStudio
} }
} }
private void ProcessGameObject() private void ProcessAssets()
{ {
Logger.Info("Process GameObject..."); Logger.Info("Process Assets...");
foreach (var assetsFile in assetsFileList) foreach (var assetsFile in assetsFileList)
{ {
foreach (var obj in assetsFile.Objects.Values) foreach (var obj in assetsFile.Objects)
{ {
if (obj is GameObject m_GameObject) if (obj is GameObject m_GameObject)
{ {
@@ -370,6 +538,27 @@ namespace AssetStudio
} }
} }
} }
else if (obj is SpriteAtlas m_SpriteAtlas)
{
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
{
if (m_PackedSprite.TryGet(out var m_Sprite))
{
if (m_Sprite.m_SpriteAtlas.IsNull)
{
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);
}
}
}
}
}
} }
} }
} }
+10
View 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;
}
}
+14 -3
View File
@@ -7,8 +7,9 @@ namespace AssetStudio
{ {
public enum BuildTarget public enum BuildTarget
{ {
UnknownPlatform = 3716, NoTarget = -2,
DashboardWidget = 1, AnyPlayer = -1,
ValidPlayer = 1,
StandaloneOSX = 2, StandaloneOSX = 2,
StandaloneOSXPPC = 3, StandaloneOSXPPC = 3,
StandaloneOSXIntel = 4, StandaloneOSXIntel = 4,
@@ -19,8 +20,10 @@ namespace AssetStudio
iOS = 9, iOS = 9,
PS3, PS3,
XBOX360, XBOX360,
Broadcom = 12,
Android = 13, Android = 13,
StandaloneGLESEmu = 14, StandaloneGLESEmu = 14,
StandaloneGLES20Emu = 15,
NaCl = 16, NaCl = 16,
StandaloneLinux = 17, StandaloneLinux = 17,
FlashPlayer = 18, FlashPlayer = 18,
@@ -42,6 +45,14 @@ namespace AssetStudio
WiiU, WiiU,
tvOS, tvOS,
Switch, Switch,
NoTarget = -2 Lumin,
Stadia,
CloudRendering,
GameCoreXboxSeries,
GameCoreXboxOne,
PS5,
EmbeddedLinux,
QNX,
UnknownPlatform = 9999
} }
} }
+302 -189
View File
@@ -1,246 +1,359 @@
using System.Collections.Generic; using K4os.Compression.LZ4;
using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Lz4;
namespace AssetStudio namespace AssetStudio
{ {
public class StreamFile [Flags]
public enum ArchiveFlags
{ {
public string fileName; CompressionTypeMask = 0x3f,
public Stream stream; BlocksAndDirectoryInfoCombined = 0x40,
BlocksInfoAtTheEnd = 0x80,
OldWebPluginCompatibility = 0x100,
BlockInfoNeedPaddingAtStart = 0x200
} }
public class BlockInfo [Flags]
public enum StorageBlockFlags
{ {
public uint compressedSize; CompressionTypeMask = 0x3f,
public uint uncompressedSize; Streamed = 0x40
public short flag; }
public enum CompressionType
{
None,
Lzma,
Lz4,
Lz4HC,
Lzham
} }
public class BundleFile public class BundleFile
{ {
private string path; public class Header
public string versionPlayer;
public string versionEngine;
public List<StreamFile> fileList = new List<StreamFile>();
public BundleFile(EndianBinaryReader bundleReader, string path)
{ {
this.path = path; public string signature;
var signature = bundleReader.ReadStringToNull(); public uint version;
switch (signature) public string unityVersion;
public string unityRevision;
public long size;
public uint compressedBlocksInfoSize;
public uint uncompressedBlocksInfoSize;
public ArchiveFlags flags;
}
public class StorageBlock
{
public uint compressedSize;
public uint uncompressedSize;
public StorageBlockFlags flags;
}
public class Node
{
public long offset;
public long size;
public uint flags;
public string path;
}
public Header m_Header;
private StorageBlock[] m_BlocksInfo;
private Node[] m_DirectoryInfo;
public StreamFile[] fileList;
public BundleFile(FileReader reader)
{
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 "UnityWeb":
case "UnityRaw": case "UnityRaw":
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": if (m_Header.version == 6)
{ {
var format = bundleReader.ReadInt32(); goto case "UnityFS";
versionPlayer = bundleReader.ReadStringToNull();
versionEngine = bundleReader.ReadStringToNull();
if (format < 6)
{
int bundleSize = bundleReader.ReadInt32();
}
else if (format == 6)
{
ReadFormat6(bundleReader, true);
return;
}
short dummy2 = bundleReader.ReadInt16();
int offset = bundleReader.ReadInt16();
int dummy3 = bundleReader.ReadInt32();
int lzmaChunks = bundleReader.ReadInt32();
int lzmaSize = 0;
long streamSize = 0;
for (int i = 0; i < lzmaChunks; i++)
{
lzmaSize = bundleReader.ReadInt32();
streamSize = bundleReader.ReadInt32();
}
bundleReader.Position = offset;
switch (signature)
{
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": //.bytes
case "UnityWeb":
{
var lzmaBuffer = bundleReader.ReadBytes(lzmaSize);
using (var lzmaStream = new EndianBinaryReader(SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer))))
{
GetAssetsFiles(lzmaStream, 0);
}
break;
}
case "UnityRaw":
{
GetAssetsFiles(bundleReader, offset);
break;
}
}
break;
} }
ReadHeaderAndBlocksInfo(reader);
using (var blocksStream = CreateBlocksStream(reader.FullPath))
{
ReadBlocksAndDirectory(reader, blocksStream);
ReadFiles(blocksStream, reader.FullPath);
}
break;
case "UnityFS": case "UnityFS":
ReadHeader(reader);
ReadBlocksInfoAndDirectory(reader);
using (var blocksStream = CreateBlocksStream(reader.FullPath))
{ {
var format = bundleReader.ReadInt32(); ReadBlocks(reader, blocksStream);
versionPlayer = bundleReader.ReadStringToNull(); ReadFiles(blocksStream, reader.FullPath);
versionEngine = bundleReader.ReadStringToNull();
if (format == 6)
{
ReadFormat6(bundleReader);
}
break;
} }
break;
} }
} }
private void GetAssetsFiles(EndianBinaryReader reader, int offset) private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
{ {
int fileCount = reader.ReadInt32(); if (m_Header.version >= 4)
for (int i = 0; i < fileCount; i++)
{ {
var file = new StreamFile(); var hash = reader.ReadBytes(16);
file.fileName = Path.GetFileName(reader.ReadStringToNull()); var crc = reader.ReadUInt32();
int fileOffset = reader.ReadInt32();
fileOffset += offset;
int fileSize = reader.ReadInt32();
long nextFile = reader.Position;
reader.Position = fileOffset;
var buffer = reader.ReadBytes(fileSize);
file.stream = new MemoryStream(buffer);
fileList.Add(file);
reader.Position = nextFile;
} }
var minimumStreamedBytes = reader.ReadUInt32();
m_Header.size = reader.ReadUInt32();
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
var levelCount = reader.ReadInt32();
m_BlocksInfo = new StorageBlock[1];
for (int i = 0; i < levelCount; i++)
{
var storageBlock = new StorageBlock()
{
compressedSize = reader.ReadUInt32(),
uncompressedSize = reader.ReadUInt32(),
};
if (i == levelCount - 1)
{
m_BlocksInfo[0] = storageBlock;
}
}
if (m_Header.version >= 2)
{
var completeFileSize = reader.ReadUInt32();
}
if (m_Header.version >= 3)
{
var fileInfoHeaderSize = reader.ReadUInt32();
}
reader.Position = m_Header.size;
} }
private void ReadFormat6(EndianBinaryReader bundleReader, bool padding = false) private Stream CreateBlocksStream(string path)
{ {
var bundleSize = bundleReader.ReadInt64(); Stream blocksStream;
int compressedSize = bundleReader.ReadInt32(); var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
int uncompressedSize = bundleReader.ReadInt32(); if (uncompressedSizeSum >= int.MaxValue)
int flag = bundleReader.ReadInt32();
if (padding)
bundleReader.ReadByte();
byte[] blocksInfoBytes;
if ((flag & 0x80) != 0)//at end of file
{ {
var position = bundleReader.Position; /*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
bundleReader.Position = bundleReader.BaseStream.Length - compressedSize; assetsDataStream = memoryMappedFile.CreateViewStream();*/
blocksInfoBytes = bundleReader.ReadBytes(compressedSize); blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
bundleReader.Position = position;
} }
else else
{ {
blocksInfoBytes = bundleReader.ReadBytes(compressedSize); blocksStream = new MemoryStream((int)uncompressedSizeSum);
} }
MemoryStream blocksInfoStream; return blocksStream;
switch (flag & 0x3F) }
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
{
var isCompressed = m_Header.signature == "UnityWeb";
foreach (var blockInfo in m_BlocksInfo)
{ {
default://None var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
if (isCompressed)
{
using (var memoryStream = new MemoryStream(uncompressedBytes))
{ {
blocksInfoStream = new MemoryStream(blocksInfoBytes); using (var decompressStream = SevenZipHelper.StreamDecompress(memoryStream))
break;
}
case 1://LZMA
{
blocksInfoStream = SevenZipHelper.StreamDecompress(new MemoryStream(blocksInfoBytes));
break;
}
case 2://LZ4
case 3://LZ4HC
{
byte[] uncompressedBytes = new byte[uncompressedSize];
using (var decoder = new Lz4DecoderStream(new MemoryStream(blocksInfoBytes)))
{ {
decoder.Read(uncompressedBytes, 0, uncompressedSize); uncompressedBytes = decompressStream.ToArray();
} }
blocksInfoStream = new MemoryStream(uncompressedBytes);
break;
} }
//case 4:LZHAM?
}
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoStream))
{
blocksInfoReader.Position = 0x10;
int blockcount = blocksInfoReader.ReadInt32();
var blockInfos = new BlockInfo[blockcount];
for (int i = 0; i < blockcount; i++)
{
blockInfos[i] = new BlockInfo
{
uncompressedSize = blocksInfoReader.ReadUInt32(),
compressedSize = blocksInfoReader.ReadUInt32(),
flag = blocksInfoReader.ReadInt16()
};
} }
Stream dataStream; blocksStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
var uncompressedSizeSum = blockInfos.Sum(x => x.uncompressedSize); }
if (uncompressedSizeSum > int.MaxValue) blocksStream.Position = 0;
var blocksReader = new EndianBinaryReader(blocksStream);
var nodesCount = blocksReader.ReadInt32();
m_DirectoryInfo = new Node[nodesCount];
for (int i = 0; i < nodesCount; i++)
{
m_DirectoryInfo[i] = new Node
{ {
/*var memoryMappedFile = MemoryMappedFile.CreateNew(Path.GetFileName(path), uncompressedSizeSum); path = blocksReader.ReadStringToNull(),
assetsDataStream = memoryMappedFile.CreateViewStream();*/ offset = blocksReader.ReadUInt32(),
dataStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose); size = blocksReader.ReadUInt32()
};
}
}
public void ReadFiles(Stream blocksStream, string path)
{
fileList = new StreamFile[m_DirectoryInfo.Length];
for (int i = 0; i < m_DirectoryInfo.Length; i++)
{
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(null, entryinfo_size);
file.stream = memoryMappedFile.CreateViewStream();*/
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
Directory.CreateDirectory(extractPath);
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
} }
else else
{ {
dataStream = new MemoryStream(); file.stream = new MemoryStream((int)node.size);
} }
foreach (var blockInfo in blockInfos) blocksStream.Position = node.offset;
{ blocksStream.CopyTo(file.stream, node.size);
switch (blockInfo.flag & 0x3F) file.stream.Position = 0;
}
}
private void ReadHeader(EndianBinaryReader reader)
{
m_Header.size = reader.ReadInt64();
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
m_Header.flags = (ArchiveFlags)reader.ReadUInt32();
if (m_Header.signature != "UnityFS")
{
reader.ReadByte();
}
}
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
{
byte[] blocksInfoBytes;
if (m_Header.version >= 7)
{
reader.AlignStream(16);
}
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 BlocksAndDirectoryInfoCombined
{
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
}
MemoryStream blocksInfoUncompresseddStream;
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
switch (compressionType)
{
case CompressionType.None:
{ {
default://None blocksInfoUncompresseddStream = new MemoryStream(blocksInfoBytes);
{ break;
bundleReader.BaseStream.CopyTo(dataStream, blockInfo.compressedSize);
break;
}
case 1://LZMA
{
SevenZipHelper.StreamDecompress(bundleReader.BaseStream, dataStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
case 2://LZ4
case 3://LZ4HC
{
var lz4Stream = new Lz4DecoderStream(bundleReader.BaseStream, blockInfo.compressedSize);
lz4Stream.CopyTo(dataStream, blockInfo.uncompressedSize);
break;
}
//case 4:LZHAM?
} }
case CompressionType.Lzma:
{
blocksInfoUncompresseddStream = new MemoryStream((int)(uncompressedSize));
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
{
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
}
blocksInfoUncompresseddStream.Position = 0;
break;
}
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))
{
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
var blocksInfoCount = blocksInfoReader.ReadInt32();
m_BlocksInfo = new StorageBlock[blocksInfoCount];
for (int i = 0; i < blocksInfoCount; i++)
{
m_BlocksInfo[i] = new StorageBlock
{
uncompressedSize = blocksInfoReader.ReadUInt32(),
compressedSize = blocksInfoReader.ReadUInt32(),
flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16()
};
} }
dataStream.Position = 0;
using (dataStream) var nodesCount = blocksInfoReader.ReadInt32();
m_DirectoryInfo = new Node[nodesCount];
for (int i = 0; i < nodesCount; i++)
{ {
var entryinfo_count = blocksInfoReader.ReadInt32(); m_DirectoryInfo[i] = new Node
for (int i = 0; i < entryinfo_count; i++)
{ {
var file = new StreamFile(); offset = blocksInfoReader.ReadInt64(),
var entryinfo_offset = blocksInfoReader.ReadInt64(); size = blocksInfoReader.ReadInt64(),
var entryinfo_size = blocksInfoReader.ReadInt64(); flags = blocksInfoReader.ReadUInt32(),
flag = blocksInfoReader.ReadInt32(); path = blocksInfoReader.ReadStringToNull(),
file.fileName = Path.GetFileName(blocksInfoReader.ReadStringToNull()); };
if (entryinfo_size > int.MaxValue)
{
/*var memoryMappedFile = MemoryMappedFile.CreateNew(file.fileName, entryinfo_size);
file.stream = memoryMappedFile.CreateViewStream();*/
var extractPath = path + "_unpacked\\";
Directory.CreateDirectory(extractPath);
file.stream = File.Create(extractPath + file.fileName);
}
else
{
file.stream = new MemoryStream();
}
dataStream.Position = entryinfo_offset;
dataStream.CopyTo(file.stream, entryinfo_size);
file.stream.Position = 0;
fileList.Add(file);
}
} }
} }
if ((m_Header.flags & ArchiveFlags.BlockInfoNeedPaddingAtStart) != 0)
{
reader.AlignStream(16);
}
}
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
{
foreach (var blockInfo in m_BlocksInfo)
{
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
switch (compressionType)
{
case CompressionType.None:
{
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
break;
}
case CompressionType.Lzma:
{
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
case CompressionType.Lz4:
case CompressionType.Lz4HC:
{
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)
{
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;
} }
} }
} }
+103 -10
View File
@@ -1,4 +1,5 @@
namespace AssetStudio // official Class ID Reference: https://docs.unity3d.com/Manual/ClassIDReference.html
namespace AssetStudio
{ {
public enum ClassIDType public enum ClassIDType
{ {
@@ -26,7 +27,7 @@
ParticleRenderer = 26, ParticleRenderer = 26,
Texture = 27, Texture = 27,
Texture2D = 28, Texture2D = 28,
SceneSettings = 29, OcclusionCullingSettings = 29,
GraphicsSettings = 30, GraphicsSettings = 30,
MeshFilter = 33, MeshFilter = 33,
OcclusionPortal = 41, OcclusionPortal = 41,
@@ -49,7 +50,7 @@
PhysicsMaterial2D = 62, PhysicsMaterial2D = 62,
MeshCollider = 64, MeshCollider = 64,
BoxCollider = 65, BoxCollider = 65,
SpriteCollider2D = 66, CompositeCollider2D = 66,
EdgeCollider2D = 68, EdgeCollider2D = 68,
CapsuleCollider2D = 70, CapsuleCollider2D = 70,
ComputeShader = 72, ComputeShader = 72,
@@ -92,6 +93,7 @@
FlareLayer = 124, FlareLayer = 124,
HaloLayer = 125, HaloLayer = 125,
NavMeshAreas = 126, NavMeshAreas = 126,
NavMeshProjectSettings = 126,
HaloManager = 127, HaloManager = 127,
Font = 128, Font = 128,
PlayerSettings = 129, PlayerSettings = 129,
@@ -158,7 +160,7 @@
BlendTree = 206, BlendTree = 206,
Motion = 207, Motion = 207,
NavMeshObstacle = 208, NavMeshObstacle = 208,
TerrainInstance = 210, SortingGroup = 210,
SpriteRenderer = 212, SpriteRenderer = 212,
Sprite = 213, Sprite = 213,
CachedSpriteAtlas = 214, CachedSpriteAtlas = 214,
@@ -216,15 +218,19 @@
PerformanceReportingManager = 305, PerformanceReportingManager = 305,
UnityConnectSettings = 310, UnityConnectSettings = 310,
AvatarMask = 319, AvatarMask = 319,
PlayableDirector = 320,
VideoPlayer = 328, VideoPlayer = 328,
VideoClip = 329, VideoClip = 329,
ParticleSystemForceField = 330,
SpriteMask = 331,
WorldAnchor = 362,
OcclusionCullingData = 363, OcclusionCullingData = 363,
//kLargestRuntimeClassID = 364 //kLargestRuntimeClassID = 364
SmallestEditorClassID = 1000, SmallestEditorClassID = 1000,
Prefab = 1001, PrefabInstance = 1001,
EditorExtensionImpl = 1002, EditorExtensionImpl = 1002,
AssetImporter = 1003, AssetImporter = 1003,
AssetDatabase = 1004, AssetDatabaseV1 = 1004,
Mesh3DSImporter = 1005, Mesh3DSImporter = 1005,
TextureImporter = 1006, TextureImporter = 1006,
ShaderImporter = 1007, ShaderImporter = 1007,
@@ -259,13 +265,13 @@
AnimatorState = 1102, AnimatorState = 1102,
HumanTemplate = 1105, HumanTemplate = 1105,
AnimatorStateMachine = 1107, AnimatorStateMachine = 1107,
PreviewAssetType = 1108, PreviewAnimationClip = 1108,
AnimatorTransition = 1109, AnimatorTransition = 1109,
SpeedTreeImporter = 1110, SpeedTreeImporter = 1110,
AnimatorTransitionBase = 1111, AnimatorTransitionBase = 1111,
SubstanceImporter = 1112, SubstanceImporter = 1112,
LightmapParameters = 1113, LightmapParameters = 1113,
LightmapSnapshot = 1120, LightingDataAsset = 1120,
GISRaster = 1121, GISRaster = 1121,
GISRasterImporter = 1122, GISRasterImporter = 1122,
CadImporter = 1123, CadImporter = 1123,
@@ -276,11 +282,98 @@
ActivationLogComponent = 2000, ActivationLogComponent = 2000,
//kLargestEditorClassID = 2001 //kLargestEditorClassID = 2001
//kClassIdOutOfHierarchy = 100000 //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, 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, 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, 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, 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
} }
} }
+59 -6
View File
@@ -292,7 +292,7 @@ namespace AssetStudio
public AnimationCurve<float> curve; public AnimationCurve<float> curve;
public string attribute; public string attribute;
public string path; public string path;
public int classID; public ClassIDType classID;
public PPtr<MonoScript> script; public PPtr<MonoScript> script;
@@ -301,7 +301,7 @@ namespace AssetStudio
curve = new AnimationCurve<float>(reader, reader.ReadSingle); curve = new AnimationCurve<float>(reader, reader.ReadSingle);
attribute = reader.ReadAlignedString(); attribute = reader.ReadAlignedString();
path = reader.ReadAlignedString(); path = reader.ReadAlignedString();
classID = reader.ReadInt32(); classID = (ClassIDType)reader.ReadInt32();
script = new PPtr<MonoScript>(reader); script = new PPtr<MonoScript>(reader);
} }
} }
@@ -637,6 +637,50 @@ namespace AssetStudio
m_Binding = new ValueArrayConstant(reader); 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 public class ValueDelta
@@ -753,6 +797,9 @@ namespace AssetStudio
public ClassIDType typeID; public ClassIDType typeID;
public byte customType; public byte customType;
public byte isPPtrCurve; public byte isPPtrCurve;
public byte isIntCurve;
public GenericBinding() { }
public GenericBinding(ObjectReader reader) public GenericBinding(ObjectReader reader)
{ {
@@ -770,6 +817,10 @@ namespace AssetStudio
} }
customType = reader.ReadByte(); customType = reader.ReadByte();
isPPtrCurve = reader.ReadByte(); isPPtrCurve = reader.ReadByte();
if (version[0] > 2022 || (version[0] == 2022 && version[1] >= 1)) //2022.1 and up
{
isIntCurve = reader.ReadByte();
}
reader.AlignStream(); reader.AlignStream();
} }
} }
@@ -779,6 +830,8 @@ namespace AssetStudio
public GenericBinding[] genericBindings; public GenericBinding[] genericBindings;
public PPtr<Object>[] pptrCurveMapping; public PPtr<Object>[] pptrCurveMapping;
public AnimationClipBindingConstant() { }
public AnimationClipBindingConstant(ObjectReader reader) public AnimationClipBindingConstant(ObjectReader reader)
{ {
int numBindings = reader.ReadInt32(); int numBindings = reader.ReadInt32();
@@ -861,9 +914,9 @@ namespace AssetStudio
public enum AnimationType public enum AnimationType
{ {
kLegacy = 1, Legacy = 1,
kGeneric = 2, Generic = 2,
kHumanoid = 3 Humanoid = 3
}; };
public sealed class AnimationClip : NamedObject public sealed class AnimationClip : NamedObject
@@ -897,7 +950,7 @@ namespace AssetStudio
else if (version[0] >= 4)//4.0 and up else if (version[0] >= 4)//4.0 and up
{ {
m_AnimationType = (AnimationType)reader.ReadInt32(); m_AnimationType = (AnimationType)reader.ReadInt32();
if (m_AnimationType == AnimationType.kLegacy) if (m_AnimationType == AnimationType.Legacy)
m_Legacy = true; m_Legacy = true;
} }
else else
+4
View File
@@ -31,6 +31,10 @@ namespace AssetStudio
if (version[0] >= 5) //5.0 and up if (version[0] >= 5) //5.0 and up
{ {
var m_LinearVelocityBlending = reader.ReadBoolean(); 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(); reader.AlignStream();
} }
+47 -29
View File
@@ -9,7 +9,7 @@ namespace AssetStudio
public sealed class AudioClip : NamedObject public sealed class AudioClip : NamedObject
{ {
public int m_Format; public int m_Format;
public AudioType m_Type; public FMODSoundType m_Type;
public bool m_3D; public bool m_3D;
public bool m_UseHardware; public bool m_UseHardware;
@@ -27,16 +27,16 @@ namespace AssetStudio
public AudioCompressionFormat m_CompressionFormat; public AudioCompressionFormat m_CompressionFormat;
public string m_Source; public string m_Source;
public long m_Offset; public long m_Offset; //ulong
public long m_Size; public long m_Size; //ulong
public Lazy<byte[]> m_AudioData; public ResourceReader m_AudioData;
public AudioClip(ObjectReader reader) : base(reader) public AudioClip(ObjectReader reader) : base(reader)
{ {
if (version[0] < 5) if (version[0] < 5)
{ {
m_Format = reader.ReadInt32(); m_Format = reader.ReadInt32();
m_Type = (AudioType)reader.ReadInt32(); m_Type = (FMODSoundType)reader.ReadInt32();
m_3D = reader.ReadBoolean(); m_3D = reader.ReadBoolean();
m_UseHardware = reader.ReadBoolean(); m_UseHardware = reader.ReadBoolean();
reader.AlignStream(); reader.AlignStream();
@@ -48,7 +48,7 @@ namespace AssetStudio
var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size; var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size;
if (reader.byteSize + reader.byteStart - reader.Position != tsize) if (reader.byteSize + reader.byteStart - reader.Position != tsize)
{ {
m_Offset = reader.ReadInt32(); m_Offset = reader.ReadUInt32();
m_Source = assetsFile.fullName + ".resS"; m_Source = assetsFile.fullName + ".resS";
} }
} }
@@ -72,6 +72,7 @@ namespace AssetStudio
m_Legacy3D = reader.ReadBoolean(); m_Legacy3D = reader.ReadBoolean();
reader.AlignStream(); reader.AlignStream();
//StreamedResource m_Resource
m_Source = reader.ReadAlignedString(); m_Source = reader.ReadAlignedString();
m_Offset = reader.ReadInt64(); m_Offset = reader.ReadInt64();
m_Size = reader.ReadInt64(); m_Size = reader.ReadInt64();
@@ -81,44 +82,61 @@ namespace AssetStudio
ResourceReader resourceReader; ResourceReader resourceReader;
if (!string.IsNullOrEmpty(m_Source)) 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 else
{ {
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size); resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_Size);
} }
m_AudioData = new Lazy<byte[]>(resourceReader.GetData); m_AudioData = resourceReader;
} }
} }
public enum AudioType public enum FMODSoundType
{ {
UNKNOWN, UNKNOWN = 0,
ACC, ACC = 1,
AIFF, AIFF = 2,
ASF = 3,
AT3 = 4,
CDDA = 5,
DLS = 6,
FLAC = 7,
FSB = 8,
GCADPCM = 9,
IT = 10, IT = 10,
MIDI = 11,
MOD = 12, MOD = 12,
MPEG, MPEG = 13,
OGGVORBIS, OGGVORBIS = 14,
PLAYLIST = 15,
RAW = 16,
S3M = 17, S3M = 17,
SF2 = 18,
USER = 19,
WAV = 20, WAV = 20,
XM, XM = 21,
XMA, XMA = 22,
VAG, VAG = 23,
AUDIOQUEUE AUDIOQUEUE = 24,
XWMA = 25,
BCWAV = 26,
AT9 = 27,
VORBIS = 28,
MEDIA_FOUNDATION = 29
} }
public enum AudioCompressionFormat public enum AudioCompressionFormat
{ {
PCM, PCM = 0,
Vorbis, Vorbis = 1,
ADPCM, ADPCM = 2,
MP3, MP3 = 3,
VAG, PSMVAG = 4,
HEVAG, HEVAG = 5,
XMA, XMA = 6,
AAC, AAC = 7,
GCADPCM, GCADPCM = 8,
ATRAC9 ATRAC9 = 9
} }
} }
+25 -1
View File
@@ -19,11 +19,14 @@ namespace AssetStudio
public class UnityPropertySheet public class UnityPropertySheet
{ {
public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs; public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs;
public KeyValuePair<string, int>[] m_Ints;
public KeyValuePair<string, float>[] m_Floats; public KeyValuePair<string, float>[] m_Floats;
public KeyValuePair<string, Color>[] m_Colors; public KeyValuePair<string, Color>[] m_Colors;
public UnityPropertySheet(ObjectReader reader) public UnityPropertySheet(ObjectReader reader)
{ {
var version = reader.version;
int m_TexEnvsSize = reader.ReadInt32(); int m_TexEnvsSize = reader.ReadInt32();
m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize]; m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize];
for (int i = 0; i < m_TexEnvsSize; i++) 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)); 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(); int m_FloatsSize = reader.ReadInt32();
m_Floats = new KeyValuePair<string, float>[m_FloatsSize]; m_Floats = new KeyValuePair<string, float>[m_FloatsSize];
for (int i = 0; i < m_FloatsSize; i++) for (int i = 0; i < m_FloatsSize; i++)
@@ -61,9 +74,18 @@ namespace AssetStudio
var m_ShaderKeywords = reader.ReadStringArray(); 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(); var m_ShaderKeywords = reader.ReadAlignedString();
}
if (version[0] >= 5) //5.0 and up
{
var m_LightmapFlags = reader.ReadUInt32(); var m_LightmapFlags = reader.ReadUInt32();
} }
@@ -95,6 +117,8 @@ namespace AssetStudio
} }
m_SavedProperties = new UnityPropertySheet(reader); m_SavedProperties = new UnityPropertySheet(reader);
//vector m_BuildTextureStacks 2020 and up
} }
} }
} }
+360 -101
View File
@@ -166,19 +166,19 @@ namespace AssetStudio
if (version[0] < 4) //4.0 down if (version[0] < 4) //4.0 down
{ {
GetChannels(); GetChannels(version);
} }
} }
else //5.0 and up else //5.0 and up
{ {
GetStreams(); GetStreams(version);
} }
m_DataSize = reader.ReadBytes(reader.ReadInt32()); m_DataSize = reader.ReadUInt8Array();
reader.AlignStream(); reader.AlignStream();
} }
private void GetStreams() private void GetStreams(int[] version)
{ {
var streamCount = m_Channels.Max(x => x.stream) + 1; var streamCount = m_Channels.Max(x => x.stream) + 1;
m_Streams = new StreamInfo[streamCount]; m_Streams = new StreamInfo[streamCount];
@@ -195,7 +195,7 @@ namespace AssetStudio
if (m_Channel.dimension > 0) if (m_Channel.dimension > 0)
{ {
chnMask |= 1u << chn; chnMask |= 1u << chn;
stride += m_Channel.dimension * MeshHelper.GetChannelFormatSize(m_Channel.format); stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
} }
} }
} }
@@ -213,7 +213,7 @@ namespace AssetStudio
} }
} }
private void GetChannels() private void GetChannels(int[] version)
{ {
m_Channels = new ChannelInfo[6]; m_Channels = new ChannelInfo[6];
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
@@ -253,7 +253,7 @@ namespace AssetStudio
m_Channel.dimension = 4; m_Channel.dimension = 4;
break; break;
} }
offset += (byte)(m_Channel.dimension * MeshHelper.GetChannelFormatSize(m_Channel.format)); offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
} }
} }
} }
@@ -396,11 +396,21 @@ namespace AssetStudio
} }
} }
public enum GfxPrimitiveType
{
Triangles = 0,
TriangleStrip = 1,
Quads = 2,
Lines = 3,
LineStrip = 4,
Points = 5
};
public class SubMesh public class SubMesh
{ {
public uint firstByte; public uint firstByte;
public uint indexCount; public uint indexCount;
public int topology; public GfxPrimitiveType topology;
public uint triangleCount; public uint triangleCount;
public uint baseVertex; public uint baseVertex;
public uint firstVertex; public uint firstVertex;
@@ -413,7 +423,7 @@ namespace AssetStudio
firstByte = reader.ReadUInt32(); firstByte = reader.ReadUInt32();
indexCount = reader.ReadUInt32(); indexCount = reader.ReadUInt32();
topology = reader.ReadInt32(); topology = (GfxPrimitiveType)reader.ReadInt32();
if (version[0] < 4) //4.0 down if (version[0] < 4) //4.0 down
{ {
@@ -436,7 +446,7 @@ namespace AssetStudio
public sealed class Mesh : NamedObject 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; public SubMesh[] m_SubMeshes;
private uint[] m_IndexBuffer; private uint[] m_IndexBuffer;
public BlendShapeData m_Shapes; public BlendShapeData m_Shapes;
@@ -451,12 +461,16 @@ namespace AssetStudio
public float[] m_UV1; public float[] m_UV1;
public float[] m_UV2; public float[] m_UV2;
public float[] m_UV3; public float[] m_UV3;
public float[] m_UV4;
public float[] m_UV5;
public float[] m_UV6;
public float[] m_UV7;
public float[] m_Tangents; public float[] m_Tangents;
private VertexData m_VertexData; private VertexData m_VertexData;
private CompressedMesh m_CompressedMesh; private CompressedMesh m_CompressedMesh;
private StreamingInfo m_StreamData; private StreamingInfo m_StreamData;
public List<uint> m_Indices = new List<uint>(); //use a list because I don't always know the facecount for triangle strips public List<uint> m_Indices = new List<uint>();
public Mesh(ObjectReader reader) : base(reader) public Mesh(ObjectReader reader) : base(reader)
{ {
@@ -536,6 +550,7 @@ namespace AssetStudio
((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression ((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression
{ {
var m_IndexFormat = reader.ReadInt32(); var m_IndexFormat = reader.ReadInt32();
m_Use16BitIndices = m_IndexFormat == 0;
} }
int m_IndexBuffer_size = reader.ReadInt32(); int m_IndexBuffer_size = reader.ReadInt32();
@@ -636,11 +651,16 @@ namespace AssetStudio
int m_MeshUsageFlags = reader.ReadInt32(); 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 if (version[0] >= 5) //5.0 and up
{ {
var m_BakedConvexCollisionMesh = reader.ReadBytes(reader.ReadInt32()); var m_BakedConvexCollisionMesh = reader.ReadUInt8Array();
reader.AlignStream(); reader.AlignStream();
var m_BakedTriangleCollisionMesh = reader.ReadBytes(reader.ReadInt32()); var m_BakedTriangleCollisionMesh = reader.ReadUInt8Array();
reader.AlignStream(); reader.AlignStream();
} }
@@ -666,7 +686,7 @@ namespace AssetStudio
{ {
if (m_VertexData.m_VertexCount > 0) 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(); m_VertexData.m_DataSize = resourceReader.GetData();
} }
} }
@@ -680,7 +700,7 @@ namespace AssetStudio
DecompressCompressedMesh(); DecompressCompressedMesh();
} }
BuildFaces(); GetTriangles();
} }
private void ReadVertexData() private void ReadVertexData()
@@ -696,12 +716,13 @@ namespace AssetStudio
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask }); var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
if (channelMask.Get(chn)) 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; m_Channel.dimension = 4;
} }
var componentByteSize = (int)MeshHelper.GetChannelFormatSize(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]; var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
for (int v = 0; v < m_VertexCount; v++) for (int v = 0; v < m_VertexCount; v++)
{ {
@@ -713,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++) for (var i = 0; i < componentBytes.Length / componentByteSize; i++)
{ {
@@ -726,10 +747,10 @@ namespace AssetStudio
int[] componentsIntArray = null; int[] componentsIntArray = null;
float[] componentsFloatArray = null; float[] componentsFloatArray = null;
if (m_Channel.format == 10 || m_Channel.format == 11) if (MeshHelper.IsIntFormat(vertexFormat))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes); componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
else else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize); componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
if (version[0] >= 2018) if (version[0] >= 2018)
{ {
@@ -759,10 +780,18 @@ namespace AssetStudio
case 7: //kShaderChannelTexCoord3 case 7: //kShaderChannelTexCoord3
m_UV3 = componentsFloatArray; m_UV3 = componentsFloatArray;
break; break;
//kShaderChannelTexCoord4 8 case 8: //kShaderChannelTexCoord4
//kShaderChannelTexCoord5 9 m_UV4 = componentsFloatArray;
//kShaderChannelTexCoord6 10 break;
//kShaderChannelTexCoord7 11 case 9: //kShaderChannelTexCoord5
m_UV5 = componentsFloatArray;
break;
case 10: //kShaderChannelTexCoord6
m_UV6 = componentsFloatArray;
break;
case 11: //kShaderChannelTexCoord7
m_UV7 = componentsFloatArray;
break;
//2018.2 and up //2018.2 and up
case 12: //kShaderChannelBlendWeight case 12: //kShaderChannelBlendWeight
if (m_Skin == null) if (m_Skin == null)
@@ -840,23 +869,40 @@ namespace AssetStudio
if (m_CompressedMesh.m_Vertices.m_NumItems > 0) if (m_CompressedMesh.m_Vertices.m_NumItems > 0)
{ {
m_VertexCount = (int)m_CompressedMesh.m_Vertices.m_NumItems / 3; m_VertexCount = (int)m_CompressedMesh.m_Vertices.m_NumItems / 3;
m_Vertices = m_CompressedMesh.m_Vertices.UnpackFloats(3, 4); m_Vertices = m_CompressedMesh.m_Vertices.UnpackFloats(3, 3 * 4);
} }
//UV //UV
if (m_CompressedMesh.m_UV.m_NumItems > 0) if (m_CompressedMesh.m_UV.m_NumItems > 0)
{ {
m_UV0 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, 0, m_VertexCount); var m_UVInfo = m_CompressedMesh.m_UVInfo;
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 4) if (m_UVInfo != 0)
{ {
m_UV1 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 2, m_VertexCount); const int kInfoBitsPerUV = 4;
const int kUVDimensionMask = 3;
const int kUVChannelExists = 4;
const int kMaxTexCoordShaderChannels = 8;
int uvSrcOffset = 0;
for (int uv = 0; uv < kMaxTexCoordShaderChannels; uv++)
{
var texCoordBits = m_UVInfo >> (uv * kInfoBitsPerUV);
texCoordBits &= (1u << kInfoBitsPerUV) - 1u;
if ((texCoordBits & kUVChannelExists) != 0)
{
var uvDim = 1 + (int)(texCoordBits & kUVDimensionMask);
var m_UV = m_CompressedMesh.m_UV.UnpackFloats(uvDim, uvDim * 4, uvSrcOffset, m_VertexCount);
SetUV(uv, m_UV);
uvSrcOffset += uvDim * m_VertexCount;
}
}
} }
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 6) else
{ {
m_UV2 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 4, m_VertexCount); m_UV0 = m_CompressedMesh.m_UV.UnpackFloats(2, 2 * 4, 0, m_VertexCount);
} if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 4)
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 8) {
{ m_UV1 = m_CompressedMesh.m_UV.UnpackFloats(2, 2 * 4, m_VertexCount * 2, m_VertexCount);
m_UV3 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 6, m_VertexCount); }
} }
} }
//BindPose //BindPose
@@ -1008,7 +1054,7 @@ namespace AssetStudio
} }
} }
private void BuildFaces() private void GetTriangles()
{ {
foreach (var m_SubMesh in m_SubMeshes) foreach (var m_SubMesh in m_SubMeshes)
{ {
@@ -1017,43 +1063,65 @@ namespace AssetStudio
{ {
firstIndex /= 2; firstIndex /= 2;
} }
var indexCount = m_SubMesh.indexCount;
if (m_SubMesh.topology == 0) var topology = m_SubMesh.topology;
if (topology == GfxPrimitiveType.Triangles)
{ {
for (int i = 0; i < m_SubMesh.indexCount / 3; i++) for (int i = 0; i < indexCount; i += 3)
{ {
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); m_Indices.Add(m_IndexBuffer[firstIndex + i]);
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); m_Indices.Add(m_IndexBuffer[firstIndex + i + 1]);
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); m_Indices.Add(m_IndexBuffer[firstIndex + i + 2]);
} }
} }
else if (version[0] < 4 || topology == GfxPrimitiveType.TriangleStrip)
{
// de-stripify :
uint triIndex = 0;
for (int i = 0; i < indexCount - 2; i++)
{
var a = m_IndexBuffer[firstIndex + i];
var b = m_IndexBuffer[firstIndex + i + 1];
var c = m_IndexBuffer[firstIndex + i + 2];
// skip degenerates
if (a == b || a == c || b == c)
continue;
// do the winding flip-flop of strips :
if ((i & 1) == 1)
{
m_Indices.Add(b);
m_Indices.Add(a);
}
else
{
m_Indices.Add(a);
m_Indices.Add(b);
}
m_Indices.Add(c);
triIndex += 3;
}
//fix indexCount
m_SubMesh.indexCount = triIndex;
}
else if (topology == GfxPrimitiveType.Quads)
{
for (int q = 0; q < indexCount; q += 4)
{
m_Indices.Add(m_IndexBuffer[firstIndex + q]);
m_Indices.Add(m_IndexBuffer[firstIndex + q + 1]);
m_Indices.Add(m_IndexBuffer[firstIndex + q + 2]);
m_Indices.Add(m_IndexBuffer[firstIndex + q]);
m_Indices.Add(m_IndexBuffer[firstIndex + q + 2]);
m_Indices.Add(m_IndexBuffer[firstIndex + q + 3]);
}
//fix indexCount
m_SubMesh.indexCount = indexCount / 2 * 3;
}
else else
{ {
uint j = 0; throw new NotSupportedException("Failed getting triangles. Submesh topology is lines or points.");
for (int i = 0; i < m_SubMesh.indexCount - 2; i++)
{
uint fa = m_IndexBuffer[firstIndex + i];
uint fb = m_IndexBuffer[firstIndex + i + 1];
uint fc = m_IndexBuffer[firstIndex + i + 2];
if ((fa != fb) && (fa != fc) && (fc != fb))
{
m_Indices.Add(fa);
if ((i % 2) == 0)
{
m_Indices.Add(fb);
m_Indices.Add(fc);
}
else
{
m_Indices.Add(fc);
m_Indices.Add(fb);
}
j++;
}
}
//fix indexCount
m_SubMesh.indexCount = j * 3;
} }
} }
} }
@@ -1066,62 +1134,253 @@ namespace AssetStudio
m_Skin[i] = new BoneWeights4(); m_Skin[i] = new BoneWeights4();
} }
} }
private void SetUV(int uv, float[] m_UV)
{
switch (uv)
{
case 0:
m_UV0 = m_UV;
break;
case 1:
m_UV1 = m_UV;
break;
case 2:
m_UV2 = m_UV;
break;
case 3:
m_UV3 = m_UV;
break;
case 4:
m_UV4 = m_UV;
break;
case 5:
m_UV5 = m_UV;
break;
case 6:
m_UV6 = m_UV;
break;
case 7:
m_UV7 = m_UV;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public float[] GetUV(int uv)
{
switch (uv)
{
case 0:
return m_UV0;
case 1:
return m_UV1;
case 2:
return m_UV2;
case 3:
return m_UV3;
case 4:
return m_UV4;
case 5:
return m_UV5;
case 6:
return m_UV6;
case 7:
return m_UV7;
default:
throw new ArgumentOutOfRangeException();
}
}
} }
public static class MeshHelper public static class MeshHelper
{ {
public static uint GetChannelFormatSize(int format) public enum VertexChannelFormat
{ {
switch (format) Float,
Float16,
Color,
Byte,
UInt32
}
public enum VertexFormat2017
{
Float,
Float16,
Color,
UNorm8,
SNorm8,
UNorm16,
SNorm16,
UInt8,
SInt8,
UInt16,
SInt16,
UInt32,
SInt32
}
public enum VertexFormat
{
Float,
Float16,
UNorm8,
SNorm8,
UNorm16,
SNorm16,
UInt8,
SInt8,
UInt16,
SInt16,
UInt32,
SInt32
}
public static VertexFormat ToVertexFormat(int format, int[] version)
{
if (version[0] < 2017)
{ {
case 0: //kChannelFormatFloat switch ((VertexChannelFormat)format)
return 4u; {
case 1: //kChannelFormatFloat16 case VertexChannelFormat.Float:
return 2u; return VertexFormat.Float;
case 2: //kChannelFormatColor case VertexChannelFormat.Float16:
return 1u; return VertexFormat.Float16;
case 3: //kChannelFormatByte case VertexChannelFormat.Color: //in 4.x is size 4
return 1u; return VertexFormat.UNorm8;
case 4: //kChannelFormatUInt32 case VertexChannelFormat.Byte:
return 4u; return VertexFormat.UInt8;
case 10: //kChannelFormatInt32 case VertexChannelFormat.UInt32: //in 5.x
return 4u; return VertexFormat.UInt32;
case 11: //kChannelFormatInt32 default:
return 4u; throw new ArgumentOutOfRangeException(nameof(format), format, null);
default: }
return 0; }
else if (version[0] < 2019)
{
switch ((VertexFormat2017)format)
{
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
{
return (VertexFormat)format;
} }
} }
public static float[] BytesToFloatArray(byte[] inputBytes, int size)
public static uint GetFormatSize(VertexFormat format)
{ {
var result = new float[inputBytes.Length / size]; switch (format)
for (int i = 0; i < inputBytes.Length / size; i++)
{ {
var value = 0f; case VertexFormat.Float:
switch (size) 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 bool IsIntFormat(VertexFormat format)
{
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++)
{
switch (format)
{ {
case 1: case VertexFormat.Float:
value = inputBytes[i] / 255.0f; result[i] = BitConverter.ToSingle(inputBytes, i * 4);
break; break;
case 2: case VertexFormat.Float16:
value = Half.ToHalf(inputBytes, i * 2); result[i] = Half.ToHalf(inputBytes, i * 2);
break; break;
case 4: case VertexFormat.UNorm8:
value = BitConverter.ToSingle(inputBytes, i * 4); 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; break;
} }
result[i] = value;
} }
return result; return result;
} }
public static int[] BytesToIntArray(byte[] inputBytes) public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
{ {
var result = new int[inputBytes.Length / 4]; var size = GetFormatSize(format);
for (int i = 0; i < inputBytes.Length / 4; i++) var len = inputBytes.Length / size;
var result = new int[len];
for (int i = 0; i < len; i++)
{ {
result[i] = BitConverter.ToInt32(inputBytes, i * 4); switch (format)
{
case VertexFormat.UInt8:
case VertexFormat.SInt8:
result[i] = inputBytes[i];
break;
case VertexFormat.UInt16:
case VertexFormat.SInt16:
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
break;
case VertexFormat.UInt32:
case VertexFormat.SInt32:
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
break;
}
} }
return result; return result;
} }
+1 -1
View File
@@ -8,7 +8,7 @@ namespace AssetStudio
public sealed class MonoScript : NamedObject public sealed class MonoScript : NamedObject
{ {
public string m_ClassName; public string m_ClassName;
public string m_Namespace = string.Empty; public string m_Namespace;
public string m_AssemblyName; public string m_AssemblyName;
public MonoScript(ObjectReader reader) : base(reader) public MonoScript(ObjectReader reader) : base(reader)
+1 -1
View File
@@ -15,7 +15,7 @@ namespace AssetStudio
var m_Loop = reader.ReadBoolean(); var m_Loop = reader.ReadBoolean();
reader.AlignStream(); reader.AlignStream();
m_AudioClip = new PPtr<AudioClip>(reader); m_AudioClip = new PPtr<AudioClip>(reader);
m_MovieData = reader.ReadBytes(reader.ReadInt32()); m_MovieData = reader.ReadUInt8Array();
} }
} }
} }
+30 -14
View File
@@ -1,7 +1,4 @@
using System; using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssetStudio 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() public string Dump()
{ {
reader.Reset(); if (serializedType?.m_Type != null)
if (serializedType?.m_Nodes != null)
{ {
var sb = new StringBuilder(); return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader); }
return sb.ToString(); 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; return null;
} }
+9 -9
View File
@@ -13,7 +13,7 @@ namespace AssetStudio
public PPtr(ObjectReader reader) public PPtr(ObjectReader reader)
{ {
m_FileID = reader.ReadInt32(); 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; assetsFile = reader.assetsFile;
} }
@@ -35,10 +35,10 @@ namespace AssetStudio
if (index == -2) if (index == -2)
{ {
var m_External = assetsFile.m_Externals[m_FileID - 1]; var m_External = assetsFile.m_Externals[m_FileID - 1];
var name = m_External.fileName.ToUpper(); var name = m_External.fileName;
if (!assetsFileIndexCache.TryGetValue(name, out index)) if (!assetsFileIndexCache.TryGetValue(name, out index))
{ {
index = assetsFileList.FindIndex(x => x.upperFileName == name); index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, index); assetsFileIndexCache.Add(name, index);
} }
} }
@@ -57,7 +57,7 @@ namespace AssetStudio
{ {
if (TryGetAssetsFile(out var sourceFile)) if (TryGetAssetsFile(out var sourceFile))
{ {
if (sourceFile.Objects.TryGetValue(m_PathID, out var obj)) if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
{ {
if (obj is T variable) if (obj is T variable)
{ {
@@ -75,7 +75,7 @@ namespace AssetStudio
{ {
if (TryGetAssetsFile(out var sourceFile)) if (TryGetAssetsFile(out var sourceFile))
{ {
if (sourceFile.Objects.TryGetValue(m_PathID, out var obj)) if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
{ {
if (obj is T2 variable) if (obj is T2 variable)
{ {
@@ -91,8 +91,8 @@ namespace AssetStudio
public void Set(T m_Object) public void Set(T m_Object)
{ {
var name = m_Object.assetsFile.upperFileName; var name = m_Object.assetsFile.fileName;
if (string.Equals(assetsFile.upperFileName, name, StringComparison.Ordinal)) if (string.Equals(assetsFile.fileName, name, StringComparison.OrdinalIgnoreCase))
{ {
m_FileID = 0; m_FileID = 0;
} }
@@ -119,13 +119,13 @@ namespace AssetStudio
if (!assetsFileIndexCache.TryGetValue(name, out index)) if (!assetsFileIndexCache.TryGetValue(name, out index))
{ {
index = assetsFileList.FindIndex(x => x.upperFileName == name); index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
assetsFileIndexCache.Add(name, index); assetsFileIndexCache.Add(name, index);
} }
m_PathID = m_Object.m_PathID; m_PathID = m_Object.m_PathID;
} }
public bool IsNull() => m_PathID == 0 || m_FileID < 0; public bool IsNull => m_PathID == 0 || m_FileID < 0;
} }
} }
+13 -1
View File
@@ -39,13 +39,25 @@ namespace AssetStudio
var m_Enabled = reader.ReadBoolean(); var m_Enabled = reader.ReadBoolean();
var m_CastShadows = reader.ReadByte(); var m_CastShadows = reader.ReadByte();
var m_ReceiveShadows = reader.ReadByte(); var m_ReceiveShadows = reader.ReadByte();
if (version[0] > 2017 || (version[0] == 2017 && version[0] >= 2)) //2017.2 and up if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
{ {
var m_DynamicOccludee = reader.ReadByte(); 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_MotionVectors = reader.ReadByte();
var m_LightProbeUsage = reader.ReadByte(); var m_LightProbeUsage = reader.ReadByte();
var m_ReflectionProbeUsage = reader.ReadByte(); var m_ReflectionProbeUsage = reader.ReadByte();
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
var m_RayTracingMode = reader.ReadByte();
}
if (version[0] >= 2020) //2020.1 and up
{
var m_RayTraceProcedural = reader.ReadByte();
}
reader.AlignStream(); reader.AlignStream();
} }
else else
+19
View 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));
}
}
}
}
+370 -119
View File
@@ -5,6 +5,16 @@ using System.Linq;
namespace AssetStudio namespace AssetStudio
{ {
public class Hash128
{
public byte[] bytes;
public Hash128(BinaryReader reader)
{
bytes = reader.ReadBytes(16);
}
}
public class StructParameter public class StructParameter
{ {
public MatrixParameter[] m_MatrixParams; public MatrixParameter[] m_MatrixParams;
@@ -46,15 +56,14 @@ namespace AssetStudio
} }
public enum TextureDimension public enum TextureDimension
{ {
kTexDimUnknown = -1, Unknown = -1,
kTexDimNone = 0, None = 0,
kTexDimAny = 1, Any = 1,
kTexDim2D = 2, Tex2D = 2,
kTexDim3D = 3, Tex3D = 3,
kTexDimCUBE = 4, Cube = 4,
kTexDim2DArray = 5, Tex2DArray = 5,
kTexDimCubeArray = 6, CubeArray = 6
kTexDimForce32Bit = 2147483647
}; };
public class SerializedTextureProperty public class SerializedTextureProperty
@@ -71,11 +80,12 @@ namespace AssetStudio
public enum SerializedPropertyType public enum SerializedPropertyType
{ {
kColor = 0, Color = 0,
kVector = 1, Vector = 1,
kFloat = 2, Float = 2,
kRange = 3, Range = 3,
kTexture = 4 Texture = 4,
Int = 5
}; };
public class SerializedProperty public class SerializedProperty
@@ -185,11 +195,11 @@ namespace AssetStudio
public enum FogMode public enum FogMode
{ {
kFogUnknown = -1, Unknown = -1,
kFogDisabled = 0, Disabled = 0,
kFogLinear = 1, Linear = 1,
kFogExp = 2, Exp = 2,
kFogExp2 = 3 Exp2 = 3
}; };
public class SerializedShaderState public class SerializedShaderState
@@ -201,6 +211,7 @@ namespace AssetStudio
public SerializedShaderFloatValue zTest; public SerializedShaderFloatValue zTest;
public SerializedShaderFloatValue zWrite; public SerializedShaderFloatValue zWrite;
public SerializedShaderFloatValue culling; public SerializedShaderFloatValue culling;
public SerializedShaderFloatValue conservative;
public SerializedShaderFloatValue offsetFactor; public SerializedShaderFloatValue offsetFactor;
public SerializedShaderFloatValue offsetUnits; public SerializedShaderFloatValue offsetUnits;
public SerializedShaderFloatValue alphaToMask; public SerializedShaderFloatValue alphaToMask;
@@ -239,6 +250,10 @@ namespace AssetStudio
zTest = new SerializedShaderFloatValue(reader); zTest = new SerializedShaderFloatValue(reader);
zWrite = new SerializedShaderFloatValue(reader); zWrite = new SerializedShaderFloatValue(reader);
culling = new SerializedShaderFloatValue(reader); culling = new SerializedShaderFloatValue(reader);
if (version[0] >= 2020) //2020.1 and up
{
conservative = new SerializedShaderFloatValue(reader);
}
offsetFactor = new SerializedShaderFloatValue(reader); offsetFactor = new SerializedShaderFloatValue(reader);
offsetUnits = new SerializedShaderFloatValue(reader); offsetUnits = new SerializedShaderFloatValue(reader);
alphaToMask = new SerializedShaderFloatValue(reader); alphaToMask = new SerializedShaderFloatValue(reader);
@@ -357,11 +372,18 @@ namespace AssetStudio
{ {
public int m_NameIndex; public int m_NameIndex;
public int m_Index; 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_NameIndex = reader.ReadInt32();
m_Index = 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 VectorParameter[] m_VectorParams;
public StructParameter[] m_StructParams; public StructParameter[] m_StructParams;
public int m_Size; public int m_Size;
public bool m_IsPartialCB;
public ConstantBuffer(ObjectReader reader) public ConstantBuffer(ObjectReader reader)
{ {
@@ -402,6 +425,16 @@ namespace AssetStudio
} }
} }
m_Size = reader.ReadInt32(); 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 public enum ShaderGpuProgramType
{ {
kShaderGpuProgramUnknown = 0, Unknown = 0,
kShaderGpuProgramGLLegacy = 1, GLLegacy = 1,
kShaderGpuProgramGLES31AEP = 2, GLES31AEP = 2,
kShaderGpuProgramGLES31 = 3, GLES31 = 3,
kShaderGpuProgramGLES3 = 4, GLES3 = 4,
kShaderGpuProgramGLES = 5, GLES = 5,
kShaderGpuProgramGLCore32 = 6, GLCore32 = 6,
kShaderGpuProgramGLCore41 = 7, GLCore41 = 7,
kShaderGpuProgramGLCore43 = 8, GLCore43 = 8,
kShaderGpuProgramDX9VertexSM20 = 9, DX9VertexSM20 = 9,
kShaderGpuProgramDX9VertexSM30 = 10, DX9VertexSM30 = 10,
kShaderGpuProgramDX9PixelSM20 = 11, DX9PixelSM20 = 11,
kShaderGpuProgramDX9PixelSM30 = 12, DX9PixelSM30 = 12,
kShaderGpuProgramDX10Level9Vertex = 13, DX10Level9Vertex = 13,
kShaderGpuProgramDX10Level9Pixel = 14, DX10Level9Pixel = 14,
kShaderGpuProgramDX11VertexSM40 = 15, DX11VertexSM40 = 15,
kShaderGpuProgramDX11VertexSM50 = 16, DX11VertexSM50 = 16,
kShaderGpuProgramDX11PixelSM40 = 17, DX11PixelSM40 = 17,
kShaderGpuProgramDX11PixelSM50 = 18, DX11PixelSM50 = 18,
kShaderGpuProgramDX11GeometrySM40 = 19, DX11GeometrySM40 = 19,
kShaderGpuProgramDX11GeometrySM50 = 20, DX11GeometrySM50 = 20,
kShaderGpuProgramDX11HullSM50 = 21, DX11HullSM50 = 21,
kShaderGpuProgramDX11DomainSM50 = 22, DX11DomainSM50 = 22,
kShaderGpuProgramMetalVS = 23, MetalVS = 23,
kShaderGpuProgramMetalFS = 24, MetalFS = 24,
kShaderGpuProgramSPIRV = 25, SPIRV = 25,
kShaderGpuProgramConsole = 26 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 VectorParameter[] m_VectorParams;
public MatrixParameter[] m_MatrixParams; public MatrixParameter[] m_MatrixParams;
public TextureParameter[] m_TextureParams; public TextureParameter[] m_TextureParams;
@@ -466,33 +500,8 @@ namespace AssetStudio
public UAVParameter[] m_UAVParams; public UAVParameter[] m_UAVParams;
public SamplerParameter[] m_Samplers; 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(); int numVectorParams = reader.ReadInt32();
m_VectorParams = new VectorParameter[numVectorParams]; m_VectorParams = new VectorParameter[numVectorParams];
for (int i = 0; i < numVectorParams; i++) for (int i = 0; i < numVectorParams; i++)
@@ -542,18 +551,139 @@ namespace AssetStudio
m_UAVParams[i] = new UAVParameter(reader); 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[i] = new SamplerParameter(reader);
m_Samplers = new SamplerParameter[numSamplers]; }
for (int i = 0; i < numSamplers; i++) }
}
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 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 class SerializedProgram
{ {
public SerializedSubProgram[] m_SubPrograms; public SerializedSubProgram[] m_SubPrograms;
public SerializedProgramParameters m_CommonParameters;
public ushort[] m_SerializedKeywordStateMask;
public SerializedProgram(ObjectReader reader) public SerializedProgram(ObjectReader reader)
{ {
var version = reader.version;
int numSubPrograms = reader.ReadInt32(); int numSubPrograms = reader.ReadInt32();
m_SubPrograms = new SerializedSubProgram[numSubPrograms]; m_SubPrograms = new SerializedSubProgram[numSubPrograms];
for (int i = 0; i < numSubPrograms; i++) for (int i = 0; i < numSubPrograms; i++)
{ {
m_SubPrograms[i] = new SerializedSubProgram(reader); 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 public enum PassType
{ {
kPassTypeNormal = 0, Normal = 0,
kPassTypeUse = 1, Use = 1,
kPassTypeGrab = 2 Grab = 2
}; };
public class SerializedPass 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 KeyValuePair<string, int>[] m_NameIndices;
public PassType m_Type; public PassType m_Type;
public SerializedShaderState m_State; public SerializedShaderState m_State;
@@ -591,16 +744,38 @@ namespace AssetStudio
public SerializedProgram progGeometry; public SerializedProgram progGeometry;
public SerializedProgram progHull; public SerializedProgram progHull;
public SerializedProgram progDomain; public SerializedProgram progDomain;
public SerializedProgram progRayTracing;
public bool m_HasInstancingVariant; public bool m_HasInstancingVariant;
public string m_UseName; public string m_UseName;
public string m_Name; public string m_Name;
public string m_TextureName; public string m_TextureName;
public SerializedTagMap m_Tags; public SerializedTagMap m_Tags;
public ushort[] m_SerializedKeywordStateMask;
public SerializedPass(ObjectReader reader) public SerializedPass(ObjectReader reader)
{ {
var version = reader.version; 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(); int numIndices = reader.ReadInt32();
m_NameIndices = new KeyValuePair<string, int>[numIndices]; m_NameIndices = new KeyValuePair<string, int>[numIndices];
for (int i = 0; i < numIndices; i++) for (int i = 0; i < numIndices; i++)
@@ -616,6 +791,10 @@ namespace AssetStudio
progGeometry = new SerializedProgram(reader); progGeometry = new SerializedProgram(reader);
progHull = new SerializedProgram(reader); progHull = new SerializedProgram(reader);
progDomain = new SerializedProgram(reader); progDomain = new SerializedProgram(reader);
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
progRayTracing = new SerializedProgram(reader);
}
m_HasInstancingVariant = reader.ReadBoolean(); m_HasInstancingVariant = reader.ReadBoolean();
if (version[0] >= 2018) //2018 and up if (version[0] >= 2018) //2018 and up
{ {
@@ -626,6 +805,11 @@ namespace AssetStudio
m_Name = reader.ReadAlignedString(); m_Name = reader.ReadAlignedString();
m_TextureName = reader.ReadAlignedString(); m_TextureName = reader.ReadAlignedString();
m_Tags = new SerializedTagMap(reader); m_Tags = new SerializedTagMap(reader);
if (version[0] == 2021 && version[1] >= 2) //2021.2 ~2021.x
{
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
reader.AlignStream();
}
} }
} }
@@ -676,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 class SerializedShader
{ {
public SerializedProperties m_PropInfo; public SerializedProperties m_PropInfo;
public SerializedSubShader[] m_SubShaders; public SerializedSubShader[] m_SubShaders;
public string[] m_KeywordNames;
public byte[] m_KeywordFlags;
public string m_Name; public string m_Name;
public string m_CustomEditorName; public string m_CustomEditorName;
public string m_FallbackName; public string m_FallbackName;
public SerializedShaderDependency[] m_Dependencies; public SerializedShaderDependency[] m_Dependencies;
public SerializedCustomEditorForRenderPipeline[] m_CustomEditorForRenderPipelines;
public bool m_DisableNoSubshadersMessage; public bool m_DisableNoSubshadersMessage;
public SerializedShader(ObjectReader reader) public SerializedShader(ObjectReader reader)
{ {
var version = reader.version;
m_PropInfo = new SerializedProperties(reader); m_PropInfo = new SerializedProperties(reader);
int numSubShaders = reader.ReadInt32(); int numSubShaders = reader.ReadInt32();
@@ -697,6 +898,13 @@ namespace AssetStudio
m_SubShaders[i] = new SerializedSubShader(reader); 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_Name = reader.ReadAlignedString();
m_CustomEditorName = reader.ReadAlignedString(); m_CustomEditorName = reader.ReadAlignedString();
m_FallbackName = reader.ReadAlignedString(); m_FallbackName = reader.ReadAlignedString();
@@ -708,6 +916,16 @@ namespace AssetStudio
m_Dependencies[i] = new SerializedShaderDependency(reader); 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(); m_DisableNoSubshadersMessage = reader.ReadBoolean();
reader.AlignStream(); reader.AlignStream();
} }
@@ -715,28 +933,32 @@ namespace AssetStudio
public enum ShaderCompilerPlatform public enum ShaderCompilerPlatform
{ {
kShaderCompPlatformNone = -1, None = -1,
kShaderCompPlatformGL = 0, GL = 0,
kShaderCompPlatformD3D9 = 1, D3D9 = 1,
kShaderCompPlatformXbox360 = 2, Xbox360 = 2,
kShaderCompPlatformPS3 = 3, PS3 = 3,
kShaderCompPlatformD3D11 = 4, D3D11 = 4,
kShaderCompPlatformGLES20 = 5, GLES20 = 5,
kShaderCompPlatformNaCl = 6, NaCl = 6,
kShaderCompPlatformFlash = 7, Flash = 7,
kShaderCompPlatformD3D11_9x = 8, D3D11_9x = 8,
kShaderCompPlatformGLES3Plus = 9, GLES3Plus = 9,
kShaderCompPlatformPSP2 = 10, PSP2 = 10,
kShaderCompPlatformPS4 = 11, PS4 = 11,
kShaderCompPlatformXboxOne = 12, XboxOne = 12,
kShaderCompPlatformPSM = 13, PSM = 13,
kShaderCompPlatformMetal = 14, Metal = 14,
kShaderCompPlatformOpenGLCore = 15, OpenGLCore = 15,
kShaderCompPlatformN3DS = 16, N3DS = 16,
kShaderCompPlatformWiiU = 17, WiiU = 17,
kShaderCompPlatformVulkan = 18, Vulkan = 18,
kShaderCompPlatformSwitch = 19, Switch = 19,
kShaderCompPlatformXboxOneD3D12 = 20 XboxOneD3D12 = 20,
GameCoreXboxOne = 21,
GameCoreScarlett = 22,
PS5 = 23,
PS5NGGC = 24
}; };
public class Shader : NamedObject public class Shader : NamedObject
@@ -748,9 +970,9 @@ namespace AssetStudio
//5.5 and up //5.5 and up
public SerializedShader m_ParsedForm; public SerializedShader m_ParsedForm;
public ShaderCompilerPlatform[] platforms; public ShaderCompilerPlatform[] platforms;
public uint[] offsets; public uint[][] offsets;
public uint[] compressedLengths; public uint[][] compressedLengths;
public uint[] decompressedLengths; public uint[][] decompressedLengths;
public byte[] compressedBlob; public byte[] compressedBlob;
public Shader(ObjectReader reader) : base(reader) public Shader(ObjectReader reader) : base(reader)
@@ -759,20 +981,49 @@ namespace AssetStudio
{ {
m_ParsedForm = new SerializedShader(reader); m_ParsedForm = new SerializedShader(reader);
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray(); platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
offsets = reader.ReadUInt32Array(); if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
compressedLengths = reader.ReadUInt32Array(); {
decompressedLengths = reader.ReadUInt32Array(); offsets = reader.ReadUInt32ArrayArray();
compressedBlob = reader.ReadBytes(reader.ReadInt32()); compressedLengths = reader.ReadUInt32ArrayArray();
decompressedLengths = reader.ReadUInt32ArrayArray();
}
else
{
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.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 else
{ {
m_Script = reader.ReadBytes(reader.ReadInt32()); m_Script = reader.ReadUInt8Array();
reader.AlignStream(); reader.AlignStream();
var m_PathName = reader.ReadAlignedString(); var m_PathName = reader.ReadAlignedString();
if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4 if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4
{ {
decompressedSize = reader.ReadUInt32(); decompressedSize = reader.ReadUInt32();
m_SubProgramBlob = reader.ReadBytes(reader.ReadInt32()); m_SubProgramBlob = reader.ReadUInt8Array();
} }
} }
} }
+37 -16
View File
@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.IO; using System.IO;
namespace AssetStudio namespace AssetStudio
@@ -19,17 +18,23 @@ namespace AssetStudio
public enum SpritePackingRotation public enum SpritePackingRotation
{ {
kSPRNone = 0, None = 0,
kSPRFlipHorizontal = 1, FlipHorizontal = 1,
kSPRFlipVertical = 2, FlipVertical = 2,
kSPRRotate180 = 3, Rotate180 = 3,
kSPRRotate90 = 4 Rotate90 = 4
}; };
public enum SpritePackingMode public enum SpritePackingMode
{ {
kSPMTight = 0, Tight = 0,
kSPMRectangle Rectangle
};
public enum SpriteMeshType
{
FullRect,
Tight
}; };
public class SpriteSettings public class SpriteSettings
@@ -39,6 +44,7 @@ namespace AssetStudio
public uint packed; public uint packed;
public SpritePackingMode packingMode; public SpritePackingMode packingMode;
public SpritePackingRotation packingRotation; public SpritePackingRotation packingRotation;
public SpriteMeshType meshType;
public SpriteSettings(BinaryReader reader) public SpriteSettings(BinaryReader reader)
{ {
@@ -47,8 +53,7 @@ namespace AssetStudio
packed = settingsRaw & 1; //1 packed = settingsRaw & 1; //1
packingMode = (SpritePackingMode)((settingsRaw >> 1) & 1); //1 packingMode = (SpritePackingMode)((settingsRaw >> 1) & 1); //1
packingRotation = (SpritePackingRotation)((settingsRaw >> 2) & 0xf); //4 packingRotation = (SpritePackingRotation)((settingsRaw >> 2) & 0xf); //4
meshType = (SpriteMeshType)((settingsRaw >> 6) & 1); //1
//meshType = (settingsRaw >> 6) & 1; //1
//reserved //reserved
} }
} }
@@ -82,7 +87,7 @@ namespace AssetStudio
public ushort[] indices; public ushort[] indices;
public Matrix4x4[] m_Bindpose; public Matrix4x4[] m_Bindpose;
public BoneWeights4[] m_SourceSkin; public BoneWeights4[] m_SourceSkin;
public RectangleF textureRect; public Rectf textureRect;
public Vector2 textureRectOffset; public Vector2 textureRectOffset;
public Vector2 atlasRectOffset; public Vector2 atlasRectOffset;
public SpriteSettings settingsRaw; public SpriteSettings settingsRaw;
@@ -118,7 +123,7 @@ namespace AssetStudio
m_SubMeshes[i] = new SubMesh(reader); m_SubMeshes[i] = new SubMesh(reader);
} }
m_IndexBuffer = reader.ReadBytes(reader.ReadInt32()); m_IndexBuffer = reader.ReadUInt8Array();
reader.AlignStream(); reader.AlignStream();
m_VertexData = new VertexData(reader); m_VertexData = new VertexData(reader);
@@ -150,7 +155,7 @@ namespace AssetStudio
} }
} }
textureRect = reader.ReadRectangleF(); textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2(); textureRectOffset = reader.ReadVector2();
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
{ {
@@ -170,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 sealed class Sprite : NamedObject
{ {
public RectangleF m_Rect; public Rectf m_Rect;
public Vector2 m_Offset; public Vector2 m_Offset;
public Vector4 m_Border; public Vector4 m_Border;
public float m_PixelsToUnits; public float m_PixelsToUnits;
public Vector2 m_Pivot; public Vector2 m_Pivot = new Vector2(0.5f, 0.5f);
public uint m_Extrude; public uint m_Extrude;
public bool m_IsPolygon; public bool m_IsPolygon;
public KeyValuePair<Guid, long> m_RenderDataKey; public KeyValuePair<Guid, long> m_RenderDataKey;
@@ -187,7 +208,7 @@ namespace AssetStudio
public Sprite(ObjectReader reader) : base(reader) public Sprite(ObjectReader reader) : base(reader)
{ {
m_Rect = reader.ReadRectangleF(); m_Rect = new Rectf(reader);
m_Offset = reader.ReadVector2(); m_Offset = reader.ReadVector2();
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
{ {
+17 -4
View File
@@ -7,19 +7,20 @@ namespace AssetStudio
{ {
public PPtr<Texture2D> texture; public PPtr<Texture2D> texture;
public PPtr<Texture2D> alphaTexture; public PPtr<Texture2D> alphaTexture;
public System.Drawing.RectangleF textureRect; public Rectf textureRect;
public Vector2 textureRectOffset; public Vector2 textureRectOffset;
public Vector2 atlasRectOffset; public Vector2 atlasRectOffset;
public Vector4 uvTransform; public Vector4 uvTransform;
public float downscaleMultiplier; public float downscaleMultiplier;
public SpriteSettings settingsRaw; public SpriteSettings settingsRaw;
public SecondarySpriteTexture[] secondaryTextures;
public SpriteAtlasData(ObjectReader reader) public SpriteAtlasData(ObjectReader reader)
{ {
var version = reader.version; var version = reader.version;
texture = new PPtr<Texture2D>(reader); texture = new PPtr<Texture2D>(reader);
alphaTexture = new PPtr<Texture2D>(reader); alphaTexture = new PPtr<Texture2D>(reader);
textureRect = reader.ReadRectangleF(); textureRect = new Rectf(reader);
textureRectOffset = reader.ReadVector2(); textureRectOffset = reader.ReadVector2();
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
{ {
@@ -28,6 +29,16 @@ namespace AssetStudio
uvTransform = reader.ReadVector4(); uvTransform = reader.ReadVector4();
downscaleMultiplier = reader.ReadSingle(); downscaleMultiplier = reader.ReadSingle();
settingsRaw = new SpriteSettings(reader); 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 PPtr<Sprite>[] m_PackedSprites;
public Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> m_RenderDataMap; public Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> m_RenderDataMap;
public bool m_IsVariant;
public SpriteAtlas(ObjectReader reader) : base(reader) public SpriteAtlas(ObjectReader reader) : base(reader)
{ {
@@ -56,8 +68,9 @@ namespace AssetStudio
var value = new SpriteAtlasData(reader); var value = new SpriteAtlasData(reader);
m_RenderDataMap.Add(new KeyValuePair<Guid, long>(first, second), value); m_RenderDataMap.Add(new KeyValuePair<Guid, long>(first, second), value);
} }
//string m_Tag var m_Tag = reader.ReadAlignedString();
//bool m_IsVariant m_IsVariant = reader.ReadBoolean();
reader.AlignStream();
} }
} }
} }
+1 -1
View File
@@ -12,7 +12,7 @@ namespace AssetStudio
public TextAsset(ObjectReader reader) : base(reader) public TextAsset(ObjectReader reader) : base(reader)
{ {
m_Script = reader.ReadBytes(reader.ReadInt32()); m_Script = reader.ReadUInt8Array();
} }
} }
} }
+4
View File
@@ -13,6 +13,10 @@ namespace AssetStudio
{ {
var m_ForcedFallbackFormat = reader.ReadInt32(); var m_ForcedFallbackFormat = reader.ReadInt32();
var m_DownscaleFallback = reader.ReadBoolean(); 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(); reader.AlignStream();
} }
} }
+66 -20
View File
@@ -1,21 +1,25 @@
using System; using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace AssetStudio namespace AssetStudio
{ {
public class StreamingInfo public class StreamingInfo
{ {
public uint offset; public long offset; //ulong
public uint size; public uint size;
public string path; public string path;
public StreamingInfo(ObjectReader reader) 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(); size = reader.ReadUInt32();
path = reader.ReadAlignedString(); path = reader.ReadAlignedString();
} }
@@ -56,7 +60,7 @@ namespace AssetStudio
public bool m_MipMap; public bool m_MipMap;
public int m_MipCount; public int m_MipCount;
public GLTextureSettings m_TextureSettings; public GLTextureSettings m_TextureSettings;
public Lazy<byte[]> image_data; public ResourceReader image_data;
public StreamingInfo m_StreamData; public StreamingInfo m_StreamData;
public Texture2D(ObjectReader reader) : base(reader) public Texture2D(ObjectReader reader) : base(reader)
@@ -64,6 +68,10 @@ namespace AssetStudio
m_Width = reader.ReadInt32(); m_Width = reader.ReadInt32();
m_Height = reader.ReadInt32(); m_Height = reader.ReadInt32();
var m_CompleteImageSize = 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(); m_TextureFormat = (TextureFormat)reader.ReadInt32();
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
{ {
@@ -73,9 +81,29 @@ namespace AssetStudio
{ {
m_MipCount = reader.ReadInt32(); m_MipCount = reader.ReadInt32();
} }
var m_IsReadable = reader.ReadBoolean(); //2.6.0 and up if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
var m_ReadAllowed = reader.ReadBoolean(); //3.0.0 - 5.4 {
//bool m_StreamingMipmaps 2018.2 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(); reader.AlignStream();
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
{ {
@@ -92,6 +120,11 @@ namespace AssetStudio
{ {
var m_ColorSpace = reader.ReadInt32(); 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(); var image_data_size = reader.ReadInt32();
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
{ {
@@ -101,13 +134,13 @@ namespace AssetStudio
ResourceReader resourceReader; ResourceReader resourceReader;
if (!string.IsNullOrEmpty(m_StreamData?.path)) 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 else
{ {
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size); resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
} }
image_data = new Lazy<byte[]>(resourceReader.GetData); image_data = resourceReader;
} }
} }
@@ -118,10 +151,13 @@ namespace AssetStudio
RGB24, RGB24,
RGBA32, RGBA32,
ARGB32, ARGB32,
RGB565 = 7, ARGBFloat,
R16 = 9, RGB565,
BGR24,
R16,
DXT1, DXT1,
DXT5 = 12, DXT3,
DXT5,
RGBA4444, RGBA4444,
BGRA32, BGRA32,
RHalf, RHalf,
@@ -132,11 +168,12 @@ namespace AssetStudio
RGBAFloat, RGBAFloat,
YUY2, YUY2,
RGB9e5Float, RGB9e5Float,
BC4 = 26, RGBFloat,
BC5, BC6H,
BC6H = 24,
BC7, BC7,
DXT1Crunched = 28, BC4,
BC5,
DXT1Crunched,
DXT5Crunched, DXT5Crunched,
PVRTC_RGB2, PVRTC_RGB2,
PVRTC_RGBA2, PVRTC_RGBA2,
@@ -170,5 +207,14 @@ namespace AssetStudio
R8, R8,
ETC_RGB4Crunched, ETC_RGB4Crunched,
ETC2_RGBA8Crunched, ETC2_RGBA8Crunched,
ASTC_HDR_4x4,
ASTC_HDR_5x5,
ASTC_HDR_6x6,
ASTC_HDR_8x8,
ASTC_HDR_10x10,
ASTC_HDR_12x12,
RG32,
RGB48,
RGBA64
} }
} }
+35 -16
View File
@@ -1,17 +1,26 @@
using System; using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudio 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 sealed class VideoClip : NamedObject
{ {
public Lazy<byte[]> m_VideoData; public ResourceReader m_VideoData;
public string m_OriginalPath; public string m_OriginalPath;
public string m_Source; public StreamedResource m_ExternalResources;
public ulong m_Size;
public VideoClip(ObjectReader reader) : base(reader) public VideoClip(ObjectReader reader) : base(reader)
{ {
@@ -32,22 +41,32 @@ namespace AssetStudio
reader.AlignStream(); reader.AlignStream();
var m_AudioSampleRate = reader.ReadUInt32Array(); var m_AudioSampleRate = reader.ReadUInt32Array();
var m_AudioLanguage = reader.ReadStringArray(); var m_AudioLanguage = reader.ReadStringArray();
//StreamedResource m_ExternalResources if (version[0] >= 2020) //2020.1 and up
m_Source = reader.ReadAlignedString(); {
var m_Offset = reader.ReadUInt64(); var m_VideoShadersSize = reader.ReadInt32();
m_Size = reader.ReadUInt64(); 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);
var m_HasSplitAlpha = reader.ReadBoolean(); var m_HasSplitAlpha = reader.ReadBoolean();
if (version[0] >= 2020) //2020.1 and up
{
var m_sRGB = reader.ReadBoolean();
}
ResourceReader resourceReader; 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 else
{ {
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size); resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_ExternalResources.m_Size);
} }
m_VideoData = new Lazy<byte[]>(resourceReader.GetData); m_VideoData = resourceReader;
} }
} }
} }
+3 -1
View File
@@ -112,7 +112,9 @@ namespace AssetStudio
{1083, "BoundsInt"}, {1083, "BoundsInt"},
{1093, "m_CorrespondingSourceObject"}, {1093, "m_CorrespondingSourceObject"},
{1121, "m_PrefabInstance"}, {1121, "m_PrefabInstance"},
{1138, "m_PrefabAsset"} {1138, "m_PrefabAsset"},
{1152, "FileSize"},
{1161, "Hash128"}
}; };
} }
} }
+32 -42
View File
@@ -1,23 +1,19 @@
using System; using System;
using System.Collections.Generic; using System.Buffers.Binary;
using System.Text;
using System.IO; using System.IO;
namespace AssetStudio namespace AssetStudio
{ {
public enum EndianType
{
LittleEndian,
BigEndian
}
public class EndianBinaryReader : BinaryReader public class EndianBinaryReader : BinaryReader
{ {
public EndianType endian; private readonly byte[] buffer;
public EndianType Endian;
public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream) public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream)
{ {
this.endian = endian; Endian = endian;
buffer = new byte[8];
} }
public long Position public long Position
@@ -28,88 +24,82 @@ namespace AssetStudio
public override short ReadInt16() public override short ReadInt16()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(2); Read(buffer, 0, 2);
Array.Reverse(buff); return BinaryPrimitives.ReadInt16BigEndian(buffer);
return BitConverter.ToInt16(buff, 0);
} }
return base.ReadInt16(); return base.ReadInt16();
} }
public override int ReadInt32() public override int ReadInt32()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(4); Read(buffer, 0, 4);
Array.Reverse(buff); return BinaryPrimitives.ReadInt32BigEndian(buffer);
return BitConverter.ToInt32(buff, 0);
} }
return base.ReadInt32(); return base.ReadInt32();
} }
public override long ReadInt64() public override long ReadInt64()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(8); Read(buffer, 0, 8);
Array.Reverse(buff); return BinaryPrimitives.ReadInt64BigEndian(buffer);
return BitConverter.ToInt64(buff, 0);
} }
return base.ReadInt64(); return base.ReadInt64();
} }
public override ushort ReadUInt16() public override ushort ReadUInt16()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(2); Read(buffer, 0, 2);
Array.Reverse(buff); return BinaryPrimitives.ReadUInt16BigEndian(buffer);
return BitConverter.ToUInt16(buff, 0);
} }
return base.ReadUInt16(); return base.ReadUInt16();
} }
public override uint ReadUInt32() public override uint ReadUInt32()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(4); Read(buffer, 0, 4);
Array.Reverse(buff); return BinaryPrimitives.ReadUInt32BigEndian(buffer);
return BitConverter.ToUInt32(buff, 0);
} }
return base.ReadUInt32(); return base.ReadUInt32();
} }
public override ulong ReadUInt64() public override ulong ReadUInt64()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(8); Read(buffer, 0, 8);
Array.Reverse(buff); return BinaryPrimitives.ReadUInt64BigEndian(buffer);
return BitConverter.ToUInt64(buff, 0);
} }
return base.ReadUInt64(); return base.ReadUInt64();
} }
public override float ReadSingle() public override float ReadSingle()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(4); Read(buffer, 0, 4);
Array.Reverse(buff); Array.Reverse(buffer, 0, 4);
return BitConverter.ToSingle(buff, 0); return BitConverter.ToSingle(buffer, 0);
} }
return base.ReadSingle(); return base.ReadSingle();
} }
public override double ReadDouble() public override double ReadDouble()
{ {
if (endian == EndianType.BigEndian) if (Endian == EndianType.BigEndian)
{ {
var buff = ReadBytes(8); Read(buffer, 0, 8);
Array.Reverse(buff); Array.Reverse(buffer);
return BitConverter.ToUInt64(buff, 0); return BitConverter.ToDouble(buffer, 0);
} }
return base.ReadDouble(); return base.ReadDouble();
} }
+14
View 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()); 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) public static Color ReadColor4(this BinaryReader reader)
{ {
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
@@ -102,6 +97,11 @@ namespace AssetStudio
return ReadArray(reader.ReadBoolean, reader.ReadInt32()); 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) public static ushort[] ReadUInt16Array(this BinaryReader reader)
{ {
return ReadArray(reader.ReadUInt16, reader.ReadInt32()); return ReadArray(reader.ReadUInt16, reader.ReadInt32());
@@ -122,6 +122,11 @@ namespace AssetStudio
return ReadArray(reader.ReadUInt32, reader.ReadInt32()); return ReadArray(reader.ReadUInt32, reader.ReadInt32());
} }
public static uint[][] ReadUInt32ArrayArray(this BinaryReader reader)
{
return ReadArray(reader.ReadUInt32Array, reader.ReadInt32());
}
public static uint[] ReadUInt32Array(this BinaryReader reader, int length) public static uint[] ReadUInt32Array(this BinaryReader reader, int length)
{ {
return ReadArray(reader.ReadUInt32, length); return ReadArray(reader.ReadUInt32, length);
+103
View 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
View 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
}
}
+56 -19
View File
@@ -73,6 +73,28 @@ namespace AssetStudio
return null; 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) public ImportedFrame FindFrame(string name)
{ {
if (Name == name) if (Name == name)
@@ -132,30 +154,31 @@ namespace AssetStudio
public class ImportedMesh public class ImportedMesh
{ {
public string Path { get; set; } public string Path { get; set; }
public List<ImportedVertex> VertexList { get; set; }
public List<ImportedSubmesh> SubmeshList { get; set; } public List<ImportedSubmesh> SubmeshList { get; set; }
public List<ImportedBone> BoneList { get; set; } public List<ImportedBone> BoneList { get; set; }
public bool hasNormal { get; set; }
public bool[] hasUV { get; set; }
public bool hasTangent { get; set; }
public bool hasColor { get; set; }
} }
public class ImportedSubmesh public class ImportedSubmesh
{ {
public List<ImportedVertex> VertexList { get; set; }
public List<ImportedFace> FaceList { get; set; } public List<ImportedFace> FaceList { get; set; }
public string Material { get; set; } public string Material { get; set; }
public int BaseVertex { get; set; }
} }
public class ImportedVertex public class ImportedVertex
{ {
public Vector3 Position { get; set; } public Vector3 Vertex { get; set; }
public Vector3 Normal { get; set; }
public float[][] UV { get; set; }
public Vector4 Tangent { get; set; }
public Color Color { get; set; }
public float[] Weights { get; set; } public float[] Weights { get; set; }
public int[] BoneIndices { get; set; } public int[] BoneIndices { get; set; }
public Vector3 Normal { get; set; }
public float[] UV { get; set; }
public Vector4 Tangent { get; set; }
}
public class ImportedVertexWithColour : ImportedVertex
{
public Color Colour { get; set; }
} }
public class ImportedFace public class ImportedFace
@@ -205,7 +228,7 @@ namespace AssetStudio
public class ImportedKeyframedAnimation public class ImportedKeyframedAnimation
{ {
public string Name { get; set; } public string Name { get; set; }
public float SampleRate { get; set; }
public List<ImportedAnimationKeyframedTrack> TrackList { get; set; } public List<ImportedAnimationKeyframedTrack> TrackList { get; set; }
public ImportedAnimationKeyframedTrack FindTrack(string path) public ImportedAnimationKeyframedTrack FindTrack(string path)
@@ -227,14 +250,13 @@ namespace AssetStudio
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>(); public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>(); public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>(); public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
public ImportedBlendShape BlendShape;
} }
public class ImportedKeyframe<T> public class ImportedKeyframe<T>
{ {
public float time { get; set; } public float time { get; set; }
public T value { get; set; } public T value { get; set; }
public T inSlope { get; set; }
public T outSlope { get; set; }
public ImportedKeyframe(float time, T value) public ImportedKeyframe(float time, T value)
{ {
@@ -243,21 +265,36 @@ namespace AssetStudio
} }
} }
public class ImportedBlendShape
{
public string ChannelName;
public List<ImportedKeyframe<float>> Keyframes = new List<ImportedKeyframe<float>>();
}
public class ImportedMorph public class ImportedMorph
{ {
public string Path { get; set; } public string Path { get; set; }
public string ClipName { get; set; } public List<ImportedMorphChannel> Channels { get; set; }
public List<Tuple<float, int, int>> Channels { get; set; } }
public class ImportedMorphChannel
{
public string Name { get; set; }
public List<ImportedMorphKeyframe> KeyframeList { get; set; } public List<ImportedMorphKeyframe> KeyframeList { get; set; }
public List<ushort> MorphedVertexIndices { get; set; }
} }
public class ImportedMorphKeyframe public class ImportedMorphKeyframe
{ {
public string Name { get; set; } public bool hasNormals { get; set; }
public List<ImportedVertex> VertexList { get; set; } public bool hasTangents { get; set; }
public List<ushort> MorphedVertexIndices { get; set; }
public float Weight { get; set; } public float Weight { get; set; }
public List<ImportedMorphVertex> VertexList { get; set; }
}
public class ImportedMorphVertex
{
public uint Index { get; set; }
public ImportedVertex Vertex { get; set; }
} }
public static class ImportedHelpers public static class ImportedHelpers
-17
View File
@@ -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) { }
}
}
+29 -51
View File
@@ -1,16 +1,11 @@
using System.Collections.Generic; using Org.Brotli.Dec;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
namespace AssetStudio namespace AssetStudio
{ {
public enum FileType
{
AssetsFile,
BundleFile,
WebFile
}
public static class ImportHelper public static class ImportHelper
{ {
public static void MergeSplitAssets(string path, bool allDirectories = false) public static void MergeSplitAssets(string path, bool allDirectories = false)
@@ -19,8 +14,8 @@ namespace AssetStudio
foreach (var splitFile in splitFiles) foreach (var splitFile in splitFiles)
{ {
var destFile = Path.GetFileNameWithoutExtension(splitFile); var destFile = Path.GetFileNameWithoutExtension(splitFile);
var destPath = Path.GetDirectoryName(splitFile) + "\\"; var destPath = Path.GetDirectoryName(splitFile);
var destFull = destPath + destFile; var destFull = Path.Combine(destPath, destFile);
if (!File.Exists(destFull)) if (!File.Exists(destFull))
{ {
var splitParts = Directory.GetFiles(destPath, destFile + ".split*"); var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
@@ -42,7 +37,7 @@ namespace AssetStudio
public static string[] ProcessingSplitFiles(List<string> selectFile) public static string[] ProcessingSplitFiles(List<string> selectFile)
{ {
var splitFiles = selectFile.Where(x => x.Contains(".split")) 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() .Distinct()
.ToList(); .ToList();
selectFile.RemoveAll(x => x.Contains(".split")); selectFile.RemoveAll(x => x.Contains(".split"));
@@ -56,48 +51,31 @@ namespace AssetStudio
return selectFile.Distinct().ToArray(); return selectFile.Distinct().ToArray();
} }
public static FileType CheckFileType(Stream stream, out EndianBinaryReader reader) public static FileReader DecompressGZip(FileReader reader)
{ {
reader = new EndianBinaryReader(stream); using (reader)
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)
{ {
case "UnityWeb": var stream = new MemoryStream();
case "UnityRaw": using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": {
case "UnityFS": gs.CopyTo(stream);
return FileType.BundleFile; }
case "UnityWebData1.0": stream.Position = 0;
return FileType.WebFile; return new FileReader(reader.FullPath, stream);
default: }
{ }
var magic = reader.ReadBytes(2);
reader.Position = 0; public static FileReader DecompressBrotli(FileReader reader)
if (WebFile.gzipMagic.SequenceEqual(magic)) {
{ using (reader)
return FileType.WebFile; {
} var stream = new MemoryStream();
reader.Position = 0x20; using (var brotliStream = new BrotliInputStream(reader.BaseStream))
magic = reader.ReadBytes(6); {
reader.Position = 0; brotliStream.CopyTo(stream);
if (WebFile.brotliMagic.SequenceEqual(magic)) }
{ stream.Position = 0;
return FileType.WebFile; return new FileReader(reader.FullPath, stream);
}
return FileType.AssetsFile;
}
} }
} }
} }
+8
View File
@@ -14,5 +14,13 @@ namespace AssetStudio
public static void Info(string message) => Default.Log(LoggerEvent.Info, message); 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 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) => Default.Log(LoggerEvent.Error, message);
public static void Error(string message, Exception e)
{
var sb = new StringBuilder();
sb.AppendLine(message);
sb.AppendLine(e.ToString());
Default.Log(LoggerEvent.Error, sb.ToString());
}
} }
} }
-540
View File
@@ -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
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
using System.Diagnostics; using System;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices;
namespace System namespace AssetStudio
{ {
/// <summary> /// <summary>
/// Represents a half-precision floating point number. /// Represents a half-precision floating point number.
+3 -2
View File
@@ -1,6 +1,7 @@
using System.Runtime.InteropServices; using System;
using System.Runtime.InteropServices;
namespace System namespace AssetStudio
{ {
/// <summary> /// <summary>
/// Helper class for Half conversions and some low level operations. /// Helper class for Half conversions and some low level operations.
+2
View File
@@ -89,6 +89,8 @@ namespace AssetStudio
public static Vector3 Zero => new Vector3(); public static Vector3 Zero => new Vector3();
public static Vector3 One => new Vector3(1.0f, 1.0f, 1.0f);
public static Vector3 operator +(Vector3 a, Vector3 b) public static Vector3 operator +(Vector3 a, Vector3 b)
{ {
return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
+3 -1
View File
@@ -7,10 +7,12 @@ namespace AssetStudio
{ {
public class ObjectInfo public class ObjectInfo
{ {
public uint byteStart; public long byteStart;
public uint byteSize; public uint byteSize;
public int typeID; public int typeID;
public int classID; public int classID;
public ushort isDestroyed;
public byte stripped;
public long m_PathID; public long m_PathID;
public SerializedType serializedType; public SerializedType serializedType;
+3 -3
View File
@@ -10,17 +10,17 @@ namespace AssetStudio
{ {
public SerializedFile assetsFile; public SerializedFile assetsFile;
public long m_PathID; public long m_PathID;
public uint byteStart; public long byteStart;
public uint byteSize; public uint byteSize;
public ClassIDType type; public ClassIDType type;
public SerializedType serializedType; public SerializedType serializedType;
public BuildTarget platform; public BuildTarget platform;
public uint m_Version; public SerializedFileFormatVersion m_Version;
public int[] version => assetsFile.version; public int[] version => assetsFile.version;
public BuildType buildType => assetsFile.buildType; 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; this.assetsFile = assetsFile;
m_PathID = objectInfo.m_PathID; m_PathID = objectInfo.m_PathID;
+4 -2
View File
@@ -1,8 +1,10 @@
namespace AssetStudio using System;
namespace AssetStudio
{ {
public static class Progress public static class Progress
{ {
public static IProgress Default = new DummyProgress(); public static IProgress<int> Default = new Progress<int>();
private static int preValue; private static int preValue;
public static void Reset() public static void Reset()
-36
View File
@@ -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 © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("af56b63c-1764-41b7-9e60-8d485422ac3b")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+42 -20
View File
@@ -8,11 +8,12 @@ namespace AssetStudio
private string path; private string path;
private SerializedFile assetsFile; private SerializedFile assetsFile;
private long offset; private long offset;
private int size; private long size;
private BinaryReader reader; 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; needSearch = true;
this.path = path; this.path = path;
@@ -21,30 +22,28 @@ namespace AssetStudio
this.size = size; this.size = size;
} }
public ResourceReader(BinaryReader reader, long offset, int size) public ResourceReader(BinaryReader reader, long offset, long size)
{ {
this.reader = reader; this.reader = reader;
this.offset = offset; this.offset = offset;
this.size = size; this.size = size;
} }
public byte[] GetData() private BinaryReader GetReader()
{ {
if (needSearch) if (needSearch)
{ {
var resourceFileName = Path.GetFileName(path); var resourceFileName = Path.GetFileName(path);
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName, out reader))
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName.ToUpper(), out var reader))
{ {
reader.Position = offset; needSearch = false;
return reader.ReadBytes(size); return reader;
} }
var assetsFileDirectory = Path.GetDirectoryName(assetsFile.fullName);
var currentDirectory = Path.GetDirectoryName(assetsFile.fullName); var resourceFilePath = Path.Combine(assetsFileDirectory, resourceFileName);
var resourceFilePath = currentDirectory + "\\" + resourceFileName;
if (!File.Exists(resourceFilePath)) if (!File.Exists(resourceFilePath))
{ {
var findFiles = Directory.GetFiles(currentDirectory, resourceFileName, SearchOption.AllDirectories); var findFiles = Directory.GetFiles(assetsFileDirectory, resourceFileName, SearchOption.AllDirectories);
if (findFiles.Length > 0) if (findFiles.Length > 0)
{ {
resourceFilePath = findFiles[0]; resourceFilePath = findFiles[0];
@@ -52,18 +51,41 @@ namespace AssetStudio
} }
if (File.Exists(resourceFilePath)) if (File.Exists(resourceFilePath))
{ {
using (var resourceReader = new BinaryReader(File.OpenRead(resourceFilePath))) needSearch = false;
{ reader = new BinaryReader(File.OpenRead(resourceFilePath));
resourceReader.BaseStream.Position = offset; assetsFile.assetsManager.resourceFileReaders.Add(resourceFileName, reader);
return resourceReader.ReadBytes(size); return reader;
}
} }
throw new FileNotFoundException($"Can't find the resource file {resourceFileName}"); throw new FileNotFoundException($"Can't find the resource file {resourceFileName}");
} }
else
{
return reader;
}
}
reader.BaseStream.Position = offset; public byte[] GetData()
return reader.ReadBytes(size); {
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);
}
} }
} }
} }
+154 -88
View File
@@ -9,63 +9,73 @@ namespace AssetStudio
public class SerializedFile public class SerializedFile
{ {
public AssetsManager assetsManager; public AssetsManager assetsManager;
public EndianBinaryReader reader; public FileReader reader;
public string fullName; public string fullName;
public string originalPath; public string originalPath;
public string fileName; public string fileName;
public string upperFileName;
public int[] version = { 0, 0, 0, 0 }; public int[] version = { 0, 0, 0, 0 };
public BuildType buildType; public BuildType buildType;
public Dictionary<long, Object> Objects; public List<Object> Objects;
public Dictionary<long, Object> ObjectsDic;
public SerializedFileHeader header; public SerializedFileHeader header;
private EndianType m_FileEndianess; private byte m_FileEndianess;
public string unityVersion = "2.5.0f5"; public string unityVersion = "2.5.0f5";
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform; public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
private bool m_EnableTypeTree = true; private bool m_EnableTypeTree = true;
public List<SerializedType> m_Types; public List<SerializedType> m_Types;
public int bigIDEnabled = 0;
public List<ObjectInfo> m_Objects; public List<ObjectInfo> m_Objects;
private List<LocalSerializedObjectIdentifier> m_ScriptTypes; private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
public List<FileIdentifier> m_Externals; 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.assetsManager = assetsManager;
this.reader = reader; this.reader = reader;
this.fullName = fullName; fullName = reader.FullPath;
fileName = Path.GetFileName(fullName); fileName = reader.FileName;
upperFileName = fileName.ToUpper();
//ReadHeader // ReadHeader
header = new SerializedFileHeader(); header = new SerializedFileHeader();
header.m_MetadataSize = reader.ReadUInt32(); header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadUInt32(); header.m_FileSize = reader.ReadUInt32();
header.m_Version = reader.ReadUInt32(); header.m_Version = (SerializedFileFormatVersion)reader.ReadUInt32();
header.m_DataOffset = 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_Endianess = reader.ReadByte();
header.m_Reserved = reader.ReadBytes(3); header.m_Reserved = reader.ReadBytes(3);
m_FileEndianess = (EndianType)header.m_Endianess; m_FileEndianess = header.m_Endianess;
} }
else else
{ {
reader.Position = header.m_FileSize - header.m_MetadataSize; reader.Position = header.m_FileSize - header.m_MetadataSize;
m_FileEndianess = (EndianType)reader.ReadByte(); m_FileEndianess = reader.ReadByte();
} }
//ReadMetadata if (header.m_Version >= SerializedFileFormatVersion.LargeFilesSupport)
if (m_FileEndianess == EndianType.LittleEndian)
{ {
reader.endian = EndianType.LittleEndian; header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadInt64();
header.m_DataOffset = reader.ReadInt64();
reader.ReadInt64(); // unknown
} }
if (header.m_Version >= 7)
// ReadMetadata
if (m_FileEndianess == 0)
{
reader.Endian = EndianType.LittleEndian;
}
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7)
{ {
unityVersion = reader.ReadStringToNull(); unityVersion = reader.ReadStringToNull();
SetVersion(unityVersion); SetVersion(unityVersion);
} }
if (header.m_Version >= 8) if (header.m_Version >= SerializedFileFormatVersion.Unknown_8)
{ {
m_TargetPlatform = (BuildTarget)reader.ReadInt32(); m_TargetPlatform = (BuildTarget)reader.ReadInt32();
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform)) if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
@@ -73,31 +83,37 @@ namespace AssetStudio
m_TargetPlatform = BuildTarget.UnknownPlatform; m_TargetPlatform = BuildTarget.UnknownPlatform;
} }
} }
if (header.m_Version >= 13) if (header.m_Version >= SerializedFileFormatVersion.HasTypeTreeHashes)
{ {
m_EnableTypeTree = reader.ReadBoolean(); m_EnableTypeTree = reader.ReadBoolean();
} }
//ReadTypes // Read Types
int typeCount = reader.ReadInt32(); int typeCount = reader.ReadInt32();
m_Types = new List<SerializedType>(typeCount); m_Types = new List<SerializedType>(typeCount);
for (int i = 0; i < typeCount; i++) for (int i = 0; i < typeCount; i++)
{ {
m_Types.Add(ReadSerializedType()); m_Types.Add(ReadSerializedType(false));
} }
if (header.m_Version >= 7 && header.m_Version < 14) if (header.m_Version >= SerializedFileFormatVersion.Unknown_7 && header.m_Version < SerializedFileFormatVersion.Unknown_14)
{ {
var bigIDEnabled = reader.ReadInt32(); bigIDEnabled = reader.ReadInt32();
} }
//ReadObjects // Read Objects
int objectCount = reader.ReadInt32(); int objectCount = reader.ReadInt32();
m_Objects = new List<ObjectInfo>(objectCount); m_Objects = new List<ObjectInfo>(objectCount);
Objects = new List<Object>(objectCount);
ObjectsDic = new Dictionary<long, Object>(objectCount);
for (int i = 0; i < objectCount; i++) for (int i = 0; i < objectCount; i++)
{ {
var objectInfo = new ObjectInfo(); var objectInfo = new ObjectInfo();
if (header.m_Version < 14) if (bigIDEnabled != 0)
{
objectInfo.m_PathID = reader.ReadInt64();
}
else if (header.m_Version < SerializedFileFormatVersion.Unknown_14)
{ {
objectInfo.m_PathID = reader.ReadInt32(); objectInfo.m_PathID = reader.ReadInt32();
} }
@@ -106,15 +122,19 @@ namespace AssetStudio
reader.AlignStream(); reader.AlignStream();
objectInfo.m_PathID = reader.ReadInt64(); objectInfo.m_PathID = reader.ReadInt64();
} }
objectInfo.byteStart = reader.ReadUInt32();
if (header.m_Version >= SerializedFileFormatVersion.LargeFilesSupport)
objectInfo.byteStart = reader.ReadInt64();
else
objectInfo.byteStart = reader.ReadUInt32();
objectInfo.byteStart += header.m_DataOffset; objectInfo.byteStart += header.m_DataOffset;
objectInfo.byteSize = reader.ReadUInt32(); objectInfo.byteSize = reader.ReadUInt32();
objectInfo.typeID = reader.ReadInt32(); objectInfo.typeID = reader.ReadInt32();
if (header.m_Version < 16) if (header.m_Version < SerializedFileFormatVersion.RefactoredClassId)
{ {
objectInfo.classID = reader.ReadUInt16(); objectInfo.classID = reader.ReadUInt16();
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID); objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
var isDestroyed = reader.ReadUInt16();
} }
else else
{ {
@@ -122,14 +142,24 @@ namespace AssetStudio
objectInfo.serializedType = type; objectInfo.serializedType = type;
objectInfo.classID = type.classID; objectInfo.classID = type.classID;
} }
if (header.m_Version == 15 || header.m_Version == 16) if (header.m_Version < SerializedFileFormatVersion.HasScriptTypeIndex)
{ {
var stripped = reader.ReadByte(); objectInfo.isDestroyed = reader.ReadUInt16();
}
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 == SerializedFileFormatVersion.SupportsStrippedObject || header.m_Version == SerializedFileFormatVersion.RefactoredClassId)
{
objectInfo.stripped = reader.ReadByte();
} }
m_Objects.Add(objectInfo); m_Objects.Add(objectInfo);
} }
if (header.m_Version >= 11) if (header.m_Version >= SerializedFileFormatVersion.HasScriptTypeIndex)
{ {
int scriptCount = reader.ReadInt32(); int scriptCount = reader.ReadInt32();
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount); m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
@@ -137,7 +167,7 @@ namespace AssetStudio
{ {
var m_ScriptType = new LocalSerializedObjectIdentifier(); var m_ScriptType = new LocalSerializedObjectIdentifier();
m_ScriptType.localSerializedFileIndex = reader.ReadInt32(); m_ScriptType.localSerializedFileIndex = reader.ReadInt32();
if (header.m_Version < 14) if (header.m_Version < SerializedFileFormatVersion.Unknown_14)
{ {
m_ScriptType.localIdentifierInFile = reader.ReadInt32(); m_ScriptType.localIdentifierInFile = reader.ReadInt32();
} }
@@ -155,11 +185,11 @@ namespace AssetStudio
for (int i = 0; i < externalsCount; i++) for (int i = 0; i < externalsCount; i++)
{ {
var m_External = new FileIdentifier(); var m_External = new FileIdentifier();
if (header.m_Version >= 6) if (header.m_Version >= SerializedFileFormatVersion.Unknown_6)
{ {
var tempEmpty = reader.ReadStringToNull(); 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.guid = new Guid(reader.ReadBytes(16));
m_External.type = reader.ReadInt32(); m_External.type = reader.ReadInt32();
@@ -169,83 +199,114 @@ namespace AssetStudio
m_Externals.Add(m_External); m_Externals.Add(m_External);
} }
if (header.m_Version >= 5) if (header.m_Version >= SerializedFileFormatVersion.SupportsRefObject)
{ {
//var userInformation = reader.ReadStringToNull(); int refTypesCount = reader.ReadInt32();
m_RefTypes = new List<SerializedType>(refTypesCount);
for (int i = 0; i < refTypesCount; i++)
{
m_RefTypes.Add(ReadSerializedType(true));
}
} }
if (header.m_Version >= SerializedFileFormatVersion.Unknown_5)
{
userInformation = reader.ReadStringToNull();
}
//reader.AlignStream(16);
} }
public void SetVersion(string stringVersion) public void SetVersion(string stringVersion)
{ {
unityVersion = stringVersion; if (stringVersion != strippedVersion)
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries); {
buildType = new BuildType(buildSplit[0]); unityVersion = stringVersion;
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries); var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
version = versionSplit.Select(int.Parse).ToArray(); 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(); var type = new SerializedType();
type.classID = reader.ReadInt32(); type.classID = reader.ReadInt32();
if (header.m_Version >= 16) if (header.m_Version >= SerializedFileFormatVersion.RefactoredClassId)
{ {
type.m_IsStrippedType = reader.ReadBoolean(); type.m_IsStrippedType = reader.ReadBoolean();
} }
if (header.m_Version >= 17) if (header.m_Version >= SerializedFileFormatVersion.RefactorTypeData)
{ {
type.m_ScriptTypeIndex = reader.ReadInt16(); 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) if (m_EnableTypeTree)
{ {
var typeTree = new List<TypeTreeNode>(); type.m_Type = new TypeTree();
if (header.m_Version >= 12 || header.m_Version == 10) type.m_Type.m_Nodes = new List<TypeTreeNode>();
if (header.m_Version >= SerializedFileFormatVersion.Unknown_12 || header.m_Version == SerializedFileFormatVersion.Unknown_10)
{ {
ReadTypeTree5(typeTree); TypeTreeBlobRead(type.m_Type);
} }
else else
{ {
ReadTypeTree(typeTree); ReadTypeTree(type.m_Type);
}
if (header.m_Version >= SerializedFileFormatVersion.StoresTypeDependencies)
{
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; return type;
} }
private void ReadTypeTree(List<TypeTreeNode> typeTree, int level = 0) private void ReadTypeTree(TypeTree m_Type, int level = 0)
{ {
var typeTreeNode = new TypeTreeNode(); var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode); m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Level = level; typeTreeNode.m_Level = level;
typeTreeNode.m_Type = reader.ReadStringToNull(); typeTreeNode.m_Type = reader.ReadStringToNull();
typeTreeNode.m_Name = reader.ReadStringToNull(); typeTreeNode.m_Name = reader.ReadStringToNull();
typeTreeNode.m_ByteSize = reader.ReadInt32(); typeTreeNode.m_ByteSize = reader.ReadInt32();
if (header.m_Version == 2) if (header.m_Version == SerializedFileFormatVersion.Unknown_2)
{ {
var variableCount = reader.ReadInt32(); var variableCount = reader.ReadInt32();
} }
if (header.m_Version != 3) if (header.m_Version != SerializedFileFormatVersion.Unknown_3)
{ {
typeTreeNode.m_Index = reader.ReadInt32(); typeTreeNode.m_Index = reader.ReadInt32();
} }
typeTreeNode.m_IsArray = reader.ReadInt32(); typeTreeNode.m_TypeFlags = reader.ReadInt32();
typeTreeNode.m_Version = reader.ReadInt32(); typeTreeNode.m_Version = reader.ReadInt32();
if (header.m_Version != 3) if (header.m_Version != SerializedFileFormatVersion.Unknown_3)
{ {
typeTreeNode.m_MetaFlag = reader.ReadInt32(); typeTreeNode.m_MetaFlag = reader.ReadInt32();
} }
@@ -253,46 +314,41 @@ namespace AssetStudio
int childrenCount = reader.ReadInt32(); int childrenCount = reader.ReadInt32();
for (int i = 0; i < childrenCount; i++) for (int i = 0; i < childrenCount; i++)
{ {
ReadTypeTree(typeTree, level + 1); ReadTypeTree(m_Type, level + 1);
} }
} }
private void ReadTypeTree5(List<TypeTreeNode> typeTree) private void TypeTreeBlobRead(TypeTree m_Type)
{ {
int numberOfNodes = reader.ReadInt32(); int numberOfNodes = reader.ReadInt32();
int stringBufferSize = reader.ReadInt32(); int stringBufferSize = reader.ReadInt32();
for (int i = 0; i < numberOfNodes; i++)
var nodeSize = 24;
if (header.m_Version > 17)
{ {
nodeSize = 32; var typeTreeNode = new TypeTreeNode();
m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Version = reader.ReadUInt16();
typeTreeNode.m_Level = reader.ReadByte();
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 >= SerializedFileFormatVersion.TypeTreeNodeWithTypeFlags)
{
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
}
} }
reader.Position += numberOfNodes * nodeSize; m_Type.m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringBufferSize))))
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_Type.m_StringBuffer)))
{ {
reader.Position -= numberOfNodes * nodeSize + stringBufferSize;
for (int i = 0; i < numberOfNodes; i++) for (int i = 0; i < numberOfNodes; i++)
{ {
var typeTreeNode = new TypeTreeNode(); var m_Node = m_Type.m_Nodes[i];
typeTree.Add(typeTreeNode); m_Node.m_Type = ReadString(stringBufferReader, m_Node.m_TypeStrOffset);
typeTreeNode.m_Version = reader.ReadUInt16(); m_Node.m_Name = ReadString(stringBufferReader, m_Node.m_NameStrOffset);
typeTreeNode.m_Level = reader.ReadByte();
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
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 > 17)
{
reader.Position += 8;
}
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
} }
reader.Position += stringBufferSize;
} }
string ReadString(BinaryReader stringBufferReader, uint value) string ReadString(BinaryReader stringBufferReader, uint value)
@@ -311,5 +367,15 @@ namespace AssetStudio
return offset.ToString(); return offset.ToString();
} }
} }
public void AddObject(Object obj)
{
Objects.Add(obj);
ObjectsDic.Add(obj.m_PathID, obj);
}
public bool IsVersionStripped => unityVersion == strippedVersion;
private const string strippedVersion = "0.0.0";
} }
} }
@@ -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
}
}
+3 -3
View File
@@ -8,9 +8,9 @@ namespace AssetStudio
public class SerializedFileHeader public class SerializedFileHeader
{ {
public uint m_MetadataSize; public uint m_MetadataSize;
public uint m_FileSize; public long m_FileSize;
public uint m_Version; public SerializedFileFormatVersion m_Version;
public uint m_DataOffset; public long m_DataOffset;
public byte m_Endianess; public byte m_Endianess;
public byte[] m_Reserved; public byte[] m_Reserved;
} }
+5 -1
View File
@@ -10,8 +10,12 @@ namespace AssetStudio
public int classID; public int classID;
public bool m_IsStrippedType; public bool m_IsStrippedType;
public short m_ScriptTypeIndex = -1; public short m_ScriptTypeIndex = -1;
public List<TypeTreeNode> m_Nodes; public TypeTree m_Type;
public byte[] m_ScriptID; //Hash128 public byte[] m_ScriptID; //Hash128
public byte[] m_OldTypeHash; //Hash128 public byte[] m_OldTypeHash; //Hash128
public int[] m_TypeDependencies;
public string m_KlassName;
public string m_NameSpace;
public string m_AsmName;
} }
} }
+5 -4
View File
@@ -34,15 +34,16 @@ namespace AssetStudio
return newOutStream; 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 decoder = new Decoder();
var properties = new byte[5]; 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"); throw new Exception("input .lzma is too short");
decoder.SetDecoderProperties(properties); decoder.SetDecoderProperties(properties);
inSize -= 5L; decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
decoder.Code(inStream, outStream, inSize, outSize, null); compressedStream.Position = basePosition + compressedSize;
} }
} }
} }
+11
View File
@@ -0,0 +1,11 @@
using System.IO;
namespace AssetStudio
{
public class StreamFile
{
public string path;
public string fileName;
public Stream stream;
}
}
+14
View 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;
}
}
+104 -220
View File
@@ -1,30 +1,39 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
namespace AssetStudio namespace AssetStudio
{ {
public static class TypeTreeHelper 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 m_Node = m_Nodes[i];
var level = member.m_Level; var level = m_Node.m_Level;
var varTypeStr = member.m_Type; var varTypeStr = m_Node.m_Type;
var varNameStr = member.m_Name; var varNameStr = m_Node.m_Name;
object value = null; object value = null;
var append = true; var append = true;
var align = (member.m_MetaFlag & 0x4000) != 0; var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr) switch (varTypeStr)
{ {
case "SInt8": case "SInt8":
@@ -33,6 +42,9 @@ namespace AssetStudio
case "UInt8": case "UInt8":
value = reader.ReadByte(); value = reader.ReadByte();
break; break;
case "char":
value = BitConverter.ToChar(reader.ReadBytes(2), 0);
break;
case "short": case "short":
case "SInt16": case "SInt16":
value = reader.ReadInt16(); value = reader.ReadInt16();
@@ -56,6 +68,7 @@ namespace AssetStudio
break; break;
case "UInt64": case "UInt64":
case "unsigned long long": case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64(); value = reader.ReadUInt64();
break; break;
case "float": case "float":
@@ -71,43 +84,23 @@ namespace AssetStudio
append = false; append = false;
var str = reader.ReadAlignedString(); var str = reader.ReadAlignedString();
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str); 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; break;
case "vector":
{
if ((members[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, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
int tmp = 0;
ReadStringValue(sb, vector, reader, ref tmp);
}
break;
}
case "map": case "map":
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
append = false; 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)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array"); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
var size = reader.ReadInt32(); var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size); sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var map = GetMembers(members, level, i); var map = GetNodes(m_Nodes, i);
i += map.Count - 1; i += map.Count - 1;
map.RemoveRange(0, 4); var first = GetNodes(map, 4);
var first = GetMembers(map, map[0].m_Level, 0); var next = 4 + first.Count;
map.RemoveRange(0, first.Count); var second = GetNodes(map, next);
var second = map;
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j); sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
@@ -131,20 +124,37 @@ namespace AssetStudio
} }
default: default:
{ {
if (i != members.Count && members[i + 1].m_Type == "Array") if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
{ {
goto case "vector"; 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 = GetNodes(m_Nodes, i);
i += vector.Count - 1;
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
int tmp = 3;
ReadStringValue(sb, vector, reader, ref tmp);
}
break;
} }
append = false; else //Class
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
for (int j = 0; j < @class.Count; j++)
{ {
ReadStringValue(sb, @class, reader, ref j); append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetNodes(m_Nodes, i);
i += @class.Count - 1;
for (int j = 1; j < @class.Count; j++)
{
ReadStringValue(sb, @class, reader, ref j);
}
break;
} }
break;
} }
} }
if (append) if (append)
@@ -153,25 +163,31 @@ namespace AssetStudio
reader.AlignStream(); reader.AlignStream();
} }
public static UType ReadUType(List<TypeTreeNode> members, BinaryReader reader) public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader)
{ {
var obj = new UType(); reader.Reset();
for (int i = 1; i < members.Count; i++) 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 m_Node = m_Nodes[i];
var varNameStr = member.m_Name; var varNameStr = m_Node.m_Name;
obj[varNameStr] = ReadValue(members, reader, ref i); 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; 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 m_Node = m_Nodes[i];
var level = member.m_Level; var varTypeStr = m_Node.m_Type;
var varTypeStr = member.m_Type;
object value; object value;
var align = (member.m_MetaFlag & 0x4000) != 0; var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr) switch (varTypeStr)
{ {
case "SInt8": case "SInt8":
@@ -180,6 +196,9 @@ namespace AssetStudio
case "UInt8": case "UInt8":
value = reader.ReadByte(); value = reader.ReadByte();
break; break;
case "char":
value = BitConverter.ToChar(reader.ReadBytes(2), 0);
break;
case "short": case "short":
case "SInt16": case "SInt16":
value = reader.ReadInt16(); value = reader.ReadInt16();
@@ -203,6 +222,7 @@ namespace AssetStudio
break; break;
case "UInt64": case "UInt64":
case "unsigned long long": case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64(); value = reader.ReadUInt64();
break; break;
case "float": case "float":
@@ -216,20 +236,20 @@ namespace AssetStudio
break; break;
case "string": case "string":
value = reader.ReadAlignedString(); value = reader.ReadAlignedString();
i += 3; var toSkip = GetNodes(m_Nodes, i);
i += toSkip.Count - 1;
break; break;
case "map": case "map":
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
var map = GetNodes(m_Nodes, i);
i += map.Count - 1;
var first = GetNodes(map, 4);
var next = 4 + first.Count;
var second = GetNodes(map, next);
var size = reader.ReadInt32(); var size = reader.ReadInt32();
var dic = new List<KeyValuePair<object, object>>(size); var dic = new List<KeyValuePair<object, object>>(size);
var map = GetMembers(members, level, i);
i += map.Count - 1;
map.RemoveRange(0, 4);
var first = GetMembers(map, map[0].m_Level, 0);
map.RemoveRange(0, first.Count);
var second = map;
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
int tmp1 = 0; int tmp1 = 0;
@@ -248,18 +268,17 @@ namespace AssetStudio
} }
default: default:
{ {
if (i != members.Count && 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; align = true;
var vector = GetNodes(m_Nodes, i);
i += vector.Count - 1;
var size = reader.ReadInt32(); var size = reader.ReadInt32();
var list = new List<object>(size); var list = new List<object>(size);
var vector = GetMembers(members, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
int tmp = 0; int tmp = 3;
list.Add(ReadValue(vector, reader, ref tmp)); list.Add(ReadValue(vector, reader, ref tmp));
} }
value = list; value = list;
@@ -267,11 +286,10 @@ namespace AssetStudio
} }
else //Class else //Class
{ {
var @class = GetMembers(members, level, i); var @class = GetNodes(m_Nodes, i);
@class.RemoveAt(0); i += @class.Count - 1;
i += @class.Count; var obj = new OrderedDictionary();
var obj = new UType(); for (int j = 1; j < @class.Count; j++)
for (int j = 0; j < @class.Count; j++)
{ {
var classmember = @class[j]; var classmember = @class[j];
var name = classmember.m_Name; var name = classmember.m_Name;
@@ -287,156 +305,22 @@ namespace AssetStudio
return value; return value;
} }
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int level, int index) private static List<TypeTreeNode> GetNodes(List<TypeTreeNode> m_Nodes, int index)
{ {
var member2 = new List<TypeTreeNode>(); var nodes = new List<TypeTreeNode>();
member2.Add(members[0]); nodes.Add(m_Nodes[index]);
for (int i = index + 1; i < members.Count; i++) 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; var level2 = member.m_Level;
if (level2 <= level) if (level2 <= level)
{ {
return member2; return nodes;
} }
member2.Add(member); nodes.Add(member);
} }
return member2; return nodes;
}
public static byte[] WriteUType(UType obj, List<TypeTreeNode> members)
{
var stream = new MemoryStream();
var write = new BinaryWriter(stream);
for (int i = 0; i < members.Count; i++)
{
var member = members[i];
var varNameStr = member.m_Name;
WriteValue(obj[varNameStr], members, write, ref i);
}
return stream.ToArray();
}
private static void WriteValue(object value, List<TypeTreeNode> members, BinaryWriter write, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
var align = (member.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
write.Write((sbyte)value);
break;
case "UInt8":
write.Write((byte)value);
break;
case "short":
case "SInt16":
write.Write((short)value);
break;
case "UInt16":
case "unsigned short":
write.Write((ushort)value);
break;
case "int":
case "SInt32":
write.Write((int)value);
break;
case "UInt32":
case "unsigned int":
case "Type*":
write.Write((uint)value);
break;
case "long long":
case "SInt64":
write.Write((long)value);
break;
case "UInt64":
case "unsigned long long":
write.Write((ulong)value);
break;
case "float":
write.Write((float)value);
break;
case "double":
write.Write((double)value);
break;
case "bool":
write.Write((bool)value);
break;
case "string":
write.WriteAlignedString((string)value);
i += 3;
break;
case "map":
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var dic = (List<KeyValuePair<object, object>>)value;
var size = dic.Count;
write.Write(size);
var map = GetMembers(members, level, i);
i += map.Count - 1;
map.RemoveRange(0, 4);
var first = GetMembers(map, map[0].m_Level, 0);
map.RemoveRange(0, first.Count);
var second = map;
for (int j = 0; j < size; j++)
{
int tmp1 = 0;
int tmp2 = 0;
WriteValue(dic[j].Key, first, write, ref tmp1);
WriteValue(dic[j].Value, second, write, ref tmp2);
}
break;
}
case "TypelessData":
{
var bytes = ((object[])value).Cast<byte>().ToArray();
var size = bytes.Length;
write.Write(size);
write.Write(bytes);
i += 2;
break;
}
default:
{
if (i != members.Count && members[i + 1].m_Type == "Array") //Array
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var list = (List<object>)value;
var size = list.Count;
write.Write(size);
var vector = GetMembers(members, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++)
{
int tmp = 0;
WriteValue(list[j], vector, write, ref tmp);
}
break;
}
else //Class
{
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
var obj = (UType)value;
for (int j = 0; j < @class.Count; j++)
{
var classmember = @class[j];
var name = classmember.m_Name;
WriteValue(obj[name], @class, write, ref j);
}
break;
}
}
}
if (align)
write.AlignStream(4);
} }
} }
} }
+12 -1
View File
@@ -11,11 +11,22 @@ namespace AssetStudio
public string m_Name; public string m_Name;
public int m_ByteSize; public int m_ByteSize;
public int m_Index; public int m_Index;
public int m_IsArray; public int m_TypeFlags; //m_IsArray
public int m_Version; public int m_Version;
public int m_MetaFlag; public int m_MetaFlag;
public int m_Level; public int m_Level;
public uint m_TypeStrOffset; public uint m_TypeStrOffset;
public uint m_NameStrOffset; 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;
}
} }
} }
-155
View File
@@ -1,155 +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 List<object> values;
public UType()
{
keys = new List<string>();
values = new List<object>();
}
private int GetValueIndex(string name)
{
for (int i = 0, n = keys.Count; i < n; i++)
{
if (string.Equals(keys[i], name, StringComparison.Ordinal))
{
return i;
}
}
return -1;
}
public bool TryGetValue<T>(string key, out T value)
{
var index = GetValueIndex(key);
if (index != -1)
{
value = (T)values[index];
return true;
}
else
{
value = default(T);
return false;
}
}
public object this[string key]
{
get
{
var index = GetValueIndex(key);
if (index != -1)
{
return values[index];
}
else
{
return null;
}
}
set
{
var index = GetValueIndex(key);
if (index == -1)
{
keys.Add(key);
values.Add(value);
}
else
{
values[index] = value;
}
}
}
public ICollection<string> Keys => keys;
public ICollection<object> Values => values;
public int Count => keys.Count;
public bool IsReadOnly => false;
public void Add(string key, object value)
{
keys.Add(key);
values.Add(value);
}
public void Add(KeyValuePair<string, object> item)
{
keys.Add(item.Key);
values.Add(item.Value);
}
public void Clear()
{
keys.Clear();
values.Clear();
}
public bool Contains(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
public bool ContainsKey(string key)
{
return GetValueIndex(key) != -1;
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
for (int i = 0, n = keys.Count; i < n; i++)
{
yield return new KeyValuePair<string, object>(keys[i], values[i]);
}
}
public bool Remove(string key)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
public bool TryGetValue(string key, out object value)
{
var index = GetValueIndex(key);
if (index != -1)
{
value = values[index];
return true;
}
else
{
value = null;
return false;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
+8 -54
View File
@@ -1,18 +1,12 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text; using System.Text;
using Org.Brotli.Dec;
namespace AssetStudio namespace AssetStudio
{ {
public class WebFile public class WebFile
{ {
public static byte[] gzipMagic = { 0x1f, 0x8b }; public StreamFile[] fileList;
public static byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
public List<StreamFile> fileList = new List<StreamFile>();
private class WebData private class WebData
{ {
@@ -23,50 +17,8 @@ namespace AssetStudio
public WebFile(EndianBinaryReader reader) public WebFile(EndianBinaryReader reader)
{ {
var magic = reader.ReadBytes(2); reader.Endian = EndianType.LittleEndian;
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)
{
var signature = reader.ReadStringToNull(); var signature = reader.ReadStringToNull();
if (signature != "UnityWebData1.0")
return;
var headLength = reader.ReadInt32(); var headLength = reader.ReadInt32();
var dataList = new List<WebData>(); var dataList = new List<WebData>();
while (reader.BaseStream.Position < headLength) while (reader.BaseStream.Position < headLength)
@@ -78,14 +30,16 @@ namespace AssetStudio
data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength)); data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength));
dataList.Add(data); dataList.Add(data);
} }
fileList = new StreamFile[dataList.Count];
foreach (var data in dataList) for (int i = 0; i < dataList.Count; i++)
{ {
var data = dataList[i];
var file = new StreamFile(); var file = new StreamFile();
file.path = data.path;
file.fileName = Path.GetFileName(data.path); file.fileName = Path.GetFileName(data.path);
reader.BaseStream.Position = data.dataOffset; reader.BaseStream.Position = data.dataOffset;
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength)); file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));
fileList.Add(file); fileList[i] = file;
} }
} }
} }
-20
View File
@@ -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")];
[assembly:AssemblyTrademarkAttribute(L"")];
[assembly:AssemblyCultureAttribute(L"")];
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
-38
View File
@@ -1,38 +0,0 @@
#include "AssetStudioFBX.h"
namespace AssetStudio
{
char* Fbx::StringToCharArray(String^ s)
{
return (char*)(void*)Marshal::StringToHGlobalAnsi(s);
}
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]);
}
}
-86
View File
@@ -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;
using namespace System::Runtime::InteropServices;
#define WITH_MARSHALLED_STRING(name,str,block)\
{ \
char* name; \
try \
{ \
name = StringToCharArray(str); \
block \
} \
finally \
{ \
Marshal::FreeHGlobal((IntPtr)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* StringToCharArray(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 allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, 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^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, 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^ meshList);
FbxFileTexture* ExportTexture(ImportedTexture^ matTex);
void ExportAnimations(bool eulerFilter, float filterValue, bool flatInbetween);
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween);
void ExportMorphs(bool morphMask, bool flatInbetween);
};
};
}
-154
View File
@@ -1,154 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}</ProjectGuid>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>AssetStudioFBX</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<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>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<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|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\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\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp" />
<ClCompile Include="AssetStudioFBX.cpp" />
<ClCompile Include="AssetStudioFBXExporter.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AssetStudioFBX.h" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,29 +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;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="AssetStudioFBX.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="AssetStudioFBXExporter.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AssetStudioFBX.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>
-969
View File
@@ -1,969 +0,0 @@
#include "AssetStudioFBX.h"
namespace AssetStudio
{
void Fbx::Exporter::Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, 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);
path = Path::GetFileName(path);
Exporter^ exporter = gcnew Exporter(path, imported, allFrames, allBones, skins, boneSize, scaleFactor, versionIndex, isAscii);
//TODO exporter->ExportMorphs(false, flatInbetween);
exporter->ExportAnimations(eulerFilter, filterPrecision, flatInbetween);
exporter->pExporter->Export(exporter->pScene);
delete exporter;
Directory::SetCurrentDirectory(currentDir);
}
Fbx::Exporter::Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, 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));
cDest = StringToCharArray(path);
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 (!allFrames)
{
framePaths = SearchHierarchy();
if (!framePaths)
{
return;
}
}
pBindPose = FbxPose::Create(pScene, "BindPose");
pBindPose->SetIsBindPose(true);
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
ExportFrame(pScene->GetRootNode(), imported->RootFrame);
if (imported->MeshList != nullptr)
{
SetJointsFromImportedMeshes(allBones);
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)
{
Marshal::FreeHGlobal((IntPtr)cDest);
}
}
void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones)
{
size_t pointer;
if (frameToNode->TryGetValue(frame, pointer))
{
auto pNode = (FbxNode*)pointer;
if (allBones || bonePaths->Contains(frame->Path))
{
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->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, allBones);
}
}
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 allBones)
{
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, allBones);
}
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^ meshList)
{
List<ImportedBone^>^ boneList = meshList->BoneList;
bool hasBones;
if (exportSkins && boneList != nullptr)
{
hasBones = boneList->Count > 0;
}
else
{
hasBones = false;
}
FbxArray<FbxNode*>* pBoneNodeList = nullptr;
FbxArray<FbxCluster*>* pClusterArray = nullptr;
try
{
if (hasBones)
{
pBoneNodeList = new FbxArray<FbxNode*>();
pBoneNodeList->Reserve(boneList->Count);
for (int i = 0; i < boneList->Count; i++)
{
auto bone = boneList[i];
auto frame = imported->RootFrame->FindFrameByPath(bone->Path);
auto frameNode = (FbxNode*)frameToNode[frame];
pBoneNodeList->Add(frameNode);
}
pClusterArray = new FbxArray<FbxCluster*>();
pClusterArray->Reserve(boneList->Count);
for (int i = 0; i < boneList->Count; i++)
{
FbxNode* pNode = pBoneNodeList->GetAt(i);
FbxString lClusterName = pNode->GetNameOnly() + FbxString("Cluster");
FbxCluster* pCluster = FbxCluster::Create(pScene, lClusterName.Buffer());
pCluster->SetLink(pNode);
pCluster->SetLinkMode(FbxCluster::eTotalOne);
pClusterArray->Add(pCluster);
}
}
FbxMesh* pMesh = FbxMesh::Create(pScene, "");
pFrameNode->SetNodeAttribute(pMesh);
int vertexCount = 0;
for (int i = 0; i < meshList->SubmeshList->Count; i++)
{
vertexCount += meshList->SubmeshList[i]->VertexList->Count;
}
pMesh->InitControlPoints(vertexCount);
FbxVector4* pControlPoints = pMesh->GetControlPoints();
FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementUV* lGeometryElementUV = pMesh->CreateElementUV("UV0");
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementTangent* lGeometryElementTangent = pMesh->CreateElementTangent();
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementVertexColor* lGeometryElementVertexColor = nullptr;
bool vertexColours = vertexCount > 0 && dynamic_cast<ImportedVertexWithColour^>(meshList->SubmeshList[0]->VertexList[0]) != nullptr;
if (vertexColours)
{
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 < meshList->SubmeshList->Count; i++)
{
ImportedSubmesh^ meshObj = meshList->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 = StringToCharArray(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
{
Marshal::FreeHGlobal((IntPtr)pMatName);
}
}
for (int j = 0; j < vertexList->Count; j++)
{
ImportedVertex^ vertex = vertexList[j];
Vector3 coords = vertex->Position;
pControlPoints[j + firstVertex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
Vector3 normal = vertex->Normal;
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
array<float>^ uv = vertex->UV;
if (uv != nullptr)
{
lGeometryElementUV->GetDirectArray().Add(FbxVector2(uv[0], uv[1]));
}
Vector4 tangent = vertex->Tangent;
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
if (vertexColours)
{
ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j];
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A));
}
if (hasBones && vertex->BoneIndices != nullptr)
{
auto boneIndices = vertex->BoneIndices;
auto weights4 = vertex->Weights;
for (int k = 0; k < 4; k++)
{
if (boneIndices[k] < boneList->Count && weights4[k] > 0)
{
FbxCluster* pCluster = pClusterArray->GetAt(boneIndices[k]);
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->GetControlPointIndicesCount() > 0)
{
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 (pBoneNodeList != NULL)
{
delete pBoneNodeList;
}
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 = StringToCharArray(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);
String^ path = Path::GetDirectoryName(gcnew String(pExporter->GetFileName().Buffer()));
if (path == String::Empty)
{
path = ".";
}
FileInfo^ file = gcnew FileInfo(path + Path::DirectorySeparatorChar + Path::GetFileName(matTex->Name));
DirectoryInfo^ dir = file->Directory;
if (!dir->Exists)
{
dir->Create();
}
BinaryWriter^ writer = gcnew BinaryWriter(file->Create());
writer->Write(matTex->Data);
writer->Close();
}
}
finally
{
Marshal::FreeHGlobal((IntPtr)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, bool flatInbetween)
{
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, flatInbetween);
}
}
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween)
{
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);
}
}
}
}
void Fbx::Exporter::ExportMorphs(bool morphMask, bool flatInbetween)
{
/*if (imported->MeshList == nullptr)
{
return;
}
for (int meshIdx = 0; meshIdx < imported->MeshList->Count; meshIdx++)
{
ImportedMesh^ meshList = imported->MeshList[meshIdx];
FbxNode* pBaseNode = NULL;
for (int nodeIdx = 0; nodeIdx < pMeshNodes->GetCount(); nodeIdx++)
{
FbxNode* pMeshNode = pMeshNodes->GetAt(nodeIdx);
String^ framePath = gcnew String(pMeshNode->GetName());
FbxNode* rootNode = pMeshNode;
while ((rootNode = rootNode->GetParent()) != pScene->GetRootNode())
{
framePath = gcnew String(rootNode->GetName()) + "/" + framePath;
}
if (framePath == meshList->Path)
{
pBaseNode = pMeshNode;
break;
}
}
if (pBaseNode == NULL)
{
continue;
}
for each (ImportedMorph^ morph in imported->MorphList)
{
if (morph->Path != meshList->Path)
{
continue;
}
int meshVertexIndex = 0;
for (int meshObjIdx = pBaseNode->GetChildCount() - meshList->SubmeshList->Count; meshObjIdx < meshList->SubmeshList->Count; meshObjIdx++)
{
List<ImportedVertex^>^ vertList = meshList->SubmeshList[meshObjIdx]->VertexList;
FbxNode* pBaseMeshNode = pBaseNode->GetChild(meshObjIdx);
FbxMesh* pBaseMesh = pBaseMeshNode->GetMesh();
int numColourSets = pBaseMesh->GetElementVertexColorCount();
FbxBlendShape* lBlendShape;
WITH_MARSHALLED_STRING
(
pShapeName,
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty),
lBlendShape = FbxBlendShape::Create(pScene, pShapeName);
);
FbxProperty rootGroupProp = FbxProperty::Create(lBlendShape, FbxStringDT, "RootGroup");
pBaseMesh->AddDeformer(lBlendShape);
List<ImportedMorphKeyframe^>^ keyframes = morph->KeyframeList;
for (int i = 0; i < morph->Channels->Count; i++)
{
FbxBlendShapeChannel* lBlendShapeChannel;
if (!flatInbetween)
{
WITH_MARSHALLED_STRING
(
pChannelName,
gcnew String(lBlendShape->GetName()) + "." + keyframes[morph->Channels[i]->Item2]->Name->Substring(0, keyframes[morph->Channels[i]->Item2]->Name->LastIndexOf("_")),
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, pChannelName);
);
lBlendShapeChannel->DeformPercent = morph->Channels[i]->Item1;
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
}
for (int frameIdx = 0; frameIdx < morph->Channels[i]->Item3; frameIdx++)
{
int shapeIdx = morph->Channels[i]->Item2 + frameIdx;
ImportedMorphKeyframe^ keyframe = keyframes[shapeIdx];
FbxShape* pShape;
if (!flatInbetween)
{
char* pMorphShapeName;
try
{
pMorphShapeName = StringToCharArray(keyframe->Name);
if (pScene->FindMember<FbxShape>(pMorphShapeName))
{
Marshal::FreeHGlobal((IntPtr)pMorphShapeName);
pMorphShapeName = StringToCharArray(morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "__" + keyframe->Name);
}
pShape = FbxShape::Create(pScene, pMorphShapeName);
}
finally
{
Marshal::FreeHGlobal((IntPtr)pMorphShapeName);
}
if (frameIdx == morph->Channels[i]->Item3 - 1)
{
FbxProperty::Create(lBlendShape, FbxStringDT, rootGroupProp.GetName() + "|" + pShape->GetName());
}
lBlendShapeChannel->AddTargetShape(pShape, keyframe->Weight);
}
else
{
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, "");
lBlendShapeChannel->DeformPercent = morph->Channels[i]->Item1;
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
WITH_MARSHALLED_STRING
(
pMorphShapeName,
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "." + keyframe->Name,
pShape = FbxShape::Create(pScene, pMorphShapeName);
);
lBlendShapeChannel->AddTargetShape(pShape, 100);
FbxProperty weightProp;
WITH_MARSHALLED_STRING
(
pWeightName,
gcnew String(pShape->GetName()) + ".Weight",
weightProp = FbxProperty::Create(pBaseMesh, FbxDoubleDT, pWeightName);
);
weightProp.ModifyFlag(FbxPropertyFlags::eUserDefined, true);
weightProp.Set<double>(keyframe->Weight);
}
pShape->InitControlPoints(vertList->Count);
FbxVector4* pControlPoints = pShape->GetControlPoints();
for (int j = 0; j < vertList->Count; j++)
{
ImportedVertex^ vertex = vertList[j];
Vector3 coords = vertex->Position;
pControlPoints[j] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
}
List<unsigned short>^ meshIndices = keyframe->MorphedVertexIndices;
for (int j = 0; j < meshIndices->Count; j++)
{
int controlPointIndex = meshIndices[j] - meshVertexIndex;
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
{
Vector3 coords = keyframe->VertexList[j]->Position;
pControlPoints[controlPointIndex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
}
}
if (flatInbetween && meshIndices->Count == 0)
{
Vector3 coords = vertList[0]->Position;
pControlPoints[0] = FbxVector4(coords.X - 1.0e-6, coords.Y, coords.Z, 0);
}
if (flatInbetween && frameIdx > 0)
{
int shapeIdx = morph->Channels[i]->Item2 + frameIdx - 1;
ImportedMorphKeyframe^ keyframe = keyframes[shapeIdx];
List<unsigned short>^ meshIndices = keyframe->MorphedVertexIndices;
for (int j = 0; j < meshIndices->Count; j++)
{
int controlPointIndex = meshIndices[j] - meshVertexIndex;
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
{
Vector3 coords = keyframe->VertexList[j]->Position - vertList[controlPointIndex]->Position;
pControlPoints[controlPointIndex] -= FbxVector4(coords.X, coords.Y, coords.Z, 0);
}
}
}
if (morphMask && frameIdx == 0)
{
int colourSetIdx = numColourSets + shapeIdx;
FbxGeometryElementVertexColor* lGeometryElementVertexColor = pBaseMesh->GetElementVertexColor(colourSetIdx);
if (lGeometryElementVertexColor == NULL)
{
lGeometryElementVertexColor = pBaseMesh->CreateElementVertexColor();
}
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
WITH_MARSHALLED_STRING
(
pColourLayerName, morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "." + keyframe->Name,
lGeometryElementVertexColor->SetName(pColourLayerName);
);
for (int j = 0; j < vertList->Count; j++)
{
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(1, 1, 1));
}
for (int j = 0; j < meshIndices->Count; j++)
{
int controlPointIndex = meshIndices[j] - meshVertexIndex;
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
{
lGeometryElementVertexColor->GetDirectArray().SetAt(controlPointIndex, FbxColor(0, 0, 1));
}
}
}
}
}
meshVertexIndex += meshList->SubmeshList[meshObjIdx]->VertexList->Count;
}
}
}*/
}
}
@@ -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
@@ -0,0 +1,202 @@
<?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>
</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>
</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>
@@ -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>
File diff suppressed because it is too large Load Diff
+161
View 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);
@@ -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
View 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
View 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
View 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();
};
@@ -0,0 +1,9 @@
#include "asfbx_morph_context.h"
AsFbxMorphContext::AsFbxMorphContext()
{
pMesh = nullptr;
lBlendShape = nullptr;
lBlendShapeChannel = nullptr;
lShape = nullptr;
}
@@ -0,0 +1,16 @@
#pragma once
#include <fbxsdk.h>
struct AsFbxMorphContext
{
FbxMesh* pMesh;
FbxBlendShape* lBlendShape;
FbxBlendShapeChannel* lBlendShapeChannel;
FbxShape* lShape;
AsFbxMorphContext();
~AsFbxMorphContext() = default;
};
@@ -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
View 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;
};
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include <cstdint>
typedef uint32_t bool32_t;
+1
View File
@@ -0,0 +1 @@
#define AS_API(ret_type)
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#if defined(_MSC_VER)
#if _MSC_VER < 1910 // MSVC 2017-
#error MSVC 2017 or later is required.
#endif
#endif
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW__)
#ifdef _AS_DLL
#ifdef __GNUC__
#define _AS_EXPORT __attribute__ ((dllexport))
#else
#define _AS_EXPORT __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#define _AS_EXPORT __attribute__ ((dllimport))
#else
#define _AS_EXPORT __declspec(dllimport)
#endif
#endif
#define _AS_LOCAL
#else
#if __GNUC__ >= 4
#define _AS_EXPORT __attribute__ ((visibility ("default")))
#define _AS_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define _AS_EXPORT
#define _AS_LOCAL
#endif
#endif
#ifdef __cplusplus
#ifndef _EXTERN_C_STMT
#define _EXTERN_C_STMT extern "C"
#endif
#else
#ifndef _EXTERN_C_STMT
#define _EXTERN_C_STMT
#endif
#endif
#ifndef _AS_CALL
#if defined(WIN32) || defined(_WIN32)
#define _AS_CALL __stdcall
#else
#define _AS_CALL /* __cdecl */
#endif
#endif
#if defined(_MSC_VER)
#define AS_API(ret_type) _EXTERN_C_STMT _AS_EXPORT ret_type _AS_CALL
#else
#define AS_API(ret_type) _EXTERN_C_STMT _AS_EXPORT _AS_CALL ret_type
#endif
+14
View File
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by AssetStudioFBXNative.rc
// 新对象的下一组默认值
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+43
View File
@@ -0,0 +1,43 @@
#include <fbxsdk.h>
#include <cassert>
#include "utils.h"
Vector3::Vector3()
: X(0), Y(0), Z(0)
{
}
Vector3::Vector3(float x, float y, float z)
: X(x), Y(y), Z(z)
{
}
Quaternion::Quaternion()
: X(0), Y(0), Z(0), W(1)
{
}
Quaternion::Quaternion(float x, float y, float z)
: X(x), Y(y), Z(z), W(1)
{
}
Quaternion::Quaternion(float x, float y, float z, float w)
: X(x), Y(y), Z(z), W(w)
{
}
Vector3 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 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]);
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
struct Vector3 {
float X;
float Y;
float Z;
Vector3();
Vector3(float x, float y, float z);
};
struct Quaternion {
float X;
float Y;
float Z;
float W;
Quaternion();
Quaternion(float x, float y, float z);
Quaternion(float x, float y, float z, float w);
};
Vector3 QuaternionToEuler(Quaternion q);
Quaternion EulerToQuaternion(Vector3 v);
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;net5.0;net6.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>0.16.0.0</Version>
<AssemblyVersion>0.16.0.0</AssemblyVersion>
<FileVersion>0.16.0.0</FileVersion>
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj" />
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
</ItemGroup>
</Project>
+16
View File
@@ -0,0 +1,16 @@
using System.Runtime.InteropServices;
using AssetStudio.FbxInterop;
namespace AssetStudio
{
partial class Fbx
{
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsUtilQuaternionToEuler(float qx, float qy, float qz, float qw, out float vx, out float vy, out float vz);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsUtilEulerToQuaternion(float vx, float vy, float vz, out float qx, out float qy, out float qz, out float qw);
}
}
+58
View File
@@ -0,0 +1,58 @@
using AssetStudio.FbxInterop;
using AssetStudio.PInvoke;
using System.IO;
namespace AssetStudio
{
public static partial class Fbx
{
static Fbx()
{
DllLoader.PreloadDll(FbxDll.DllName);
}
public static Vector3 QuaternionToEuler(Quaternion q)
{
AsUtilQuaternionToEuler(q.X, q.Y, q.Z, q.W, out var x, out var y, out var z);
return new Vector3(x, y, z);
}
public static Quaternion EulerToQuaternion(Vector3 v)
{
AsUtilEulerToQuaternion(v.X, v.Y, v.Z, out var x, out var y, out var z, out var w);
return new Quaternion(x, y, z, w);
}
public static 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, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
{
var file = new FileInfo(path);
var dir = file.Directory;
if (!dir.Exists)
{
dir.Create();
}
var currentDir = Directory.GetCurrentDirectory();
Directory.SetCurrentDirectory(dir.FullName);
var name = Path.GetFileName(path);
using (var exporter = new FbxExporter(name, imported, allNodes, skins, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, versionIndex, isAscii))
{
exporter.Initialize();
exporter.ExportAll(blendShape, animation, eulerFilter, filterPrecision);
}
Directory.SetCurrentDirectory(currentDir);
}
}
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace AssetStudio.FbxInterop
{
internal static class FbxDll
{
internal const string DllName = "AssetStudioFBXNative";
internal const string FbxsdkDllName = "libfbxsdk";
}
}
+244
View File
@@ -0,0 +1,244 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace AssetStudio.FbxInterop
{
internal sealed class FbxExporter : IDisposable
{
private FbxExporterContext _context;
private readonly string _fileName;
private readonly IImported _imported;
private readonly bool _allNodes;
private readonly bool _exportSkins;
private readonly bool _castToBone;
private readonly float _boneSize;
private readonly bool _exportAllUvsAsDiffuseMaps;
private readonly float _scaleFactor;
private readonly int _versionIndex;
private readonly bool _isAscii;
internal FbxExporter(string fileName, IImported imported, bool allNodes, bool exportSkins, bool castToBone, float boneSize, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
{
_context = new FbxExporterContext();
_fileName = fileName;
_imported = imported;
_allNodes = allNodes;
_exportSkins = exportSkins;
_castToBone = castToBone;
_boneSize = boneSize;
_exportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps;
_scaleFactor = scaleFactor;
_versionIndex = versionIndex;
_isAscii = isAscii;
}
~FbxExporter()
{
Dispose(false);
}
public void Dispose()
{
if (IsDisposed)
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
public bool IsDisposed { get; private set; }
private void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
IsDisposed = true;
}
internal void Initialize()
{
var is60Fps = _imported.AnimationList.Count > 0 && _imported.AnimationList[0].SampleRate.Equals(60.0f);
_context.Initialize(_fileName, _scaleFactor, _versionIndex, _isAscii, is60Fps);
if (!_allNodes)
{
var framePaths = SearchHierarchy();
_context.SetFramePaths(framePaths);
}
}
internal void ExportAll(bool blendShape, bool animation, bool eulerFilter, float filterPrecision)
{
var meshFrames = new List<ImportedFrame>();
ExportRootFrame(meshFrames);
if (_imported.MeshList != null)
{
SetJointsFromImportedMeshes();
PrepareMaterials();
ExportMeshFrames(_imported.RootFrame, meshFrames);
}
else
{
SetJointsNode(_imported.RootFrame, null, true);
}
if (blendShape)
{
ExportMorphs();
}
if (animation)
{
ExportAnimations(eulerFilter, filterPrecision);
}
ExportScene();
}
private void ExportMorphs()
{
_context.ExportMorphs(_imported.RootFrame, _imported.MorphList);
}
private void ExportAnimations(bool eulerFilter, float filterPrecision)
{
_context.ExportAnimations(_imported.RootFrame, _imported.AnimationList, eulerFilter, filterPrecision);
}
private void ExportRootFrame(List<ImportedFrame> meshFrames)
{
_context.ExportFrame(_imported.MeshList, meshFrames, _imported.RootFrame);
}
private void ExportScene()
{
_context.ExportScene();
}
private void SetJointsFromImportedMeshes()
{
if (!_exportSkins)
{
return;
}
Debug.Assert(_imported.MeshList != null);
var bonePaths = new HashSet<string>();
foreach (var mesh in _imported.MeshList)
{
var boneList = mesh.BoneList;
if (boneList != null)
{
foreach (var bone in boneList)
{
bonePaths.Add(bone.Path);
}
}
}
SetJointsNode(_imported.RootFrame, bonePaths, _castToBone);
}
private void SetJointsNode(ImportedFrame rootFrame, HashSet<string> bonePaths, bool castToBone)
{
_context.SetJointsNode(rootFrame, bonePaths, castToBone, _boneSize);
}
private void PrepareMaterials()
{
_context.PrepareMaterials(_imported.MaterialList.Count, _imported.TextureList.Count);
}
private void ExportMeshFrames(ImportedFrame rootFrame, List<ImportedFrame> meshFrames)
{
foreach (var meshFrame in meshFrames)
{
_context.ExportMeshFromFrame(rootFrame, meshFrame, _imported.MeshList, _imported.MaterialList, _imported.TextureList, _exportSkins, _exportAllUvsAsDiffuseMaps);
}
}
private HashSet<string> SearchHierarchy()
{
if (_imported.MeshList == null || _imported.MeshList.Count == 0)
{
return null;
}
var exportFrames = new HashSet<string>();
SearchHierarchy(_imported.RootFrame, _imported.MeshList, exportFrames);
return exportFrames;
}
private static void SearchHierarchy(ImportedFrame rootFrame, List<ImportedMesh> meshList, HashSet<string> exportFrames)
{
var frameStack = new Stack<ImportedFrame>();
frameStack.Push(rootFrame);
while (frameStack.Count > 0)
{
var frame = frameStack.Pop();
var meshListSome = ImportedHelpers.FindMesh(frame.Path, meshList);
if (meshListSome != null)
{
var parent = frame;
while (parent != null)
{
exportFrames.Add(parent.Path);
parent = parent.Parent;
}
var boneList = meshListSome.BoneList;
if (boneList != null)
{
foreach (var bone in boneList)
{
if (!exportFrames.Contains(bone.Path))
{
var boneParent = rootFrame.FindFrameByPath(bone.Path);
while (boneParent != null)
{
exportFrames.Add(boneParent.Path);
boneParent = boneParent.Parent;
}
}
}
}
}
for (var i = frame.Count - 1; i >= 0; i -= 1)
{
frameStack.Push(frame[i]);
}
}
}
}
}
@@ -0,0 +1,325 @@
using System;
using System.Runtime.InteropServices;
using AssetStudio.PInvoke;
namespace AssetStudio.FbxInterop
{
partial class FbxExporterContext
{
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxCreateContext();
private static bool AsFbxInitializeContext(IntPtr context, string fileName, float scaleFactor, int versionIndex, bool isAscii, bool is60Fps, out string errorMessage)
{
bool b;
IntPtr pErrMsg;
using (var fileNameUtf8 = new Utf8StringHandle(fileName))
{
b = AsFbxInitializeContext(context, fileNameUtf8.DangerousGetHandle(), scaleFactor, versionIndex, isAscii, is60Fps, out pErrMsg);
}
errorMessage = Utf8StringHandle.ReadUtf8StringFromPointer(pErrMsg);
return b;
}
// Do not free the pointer strErrorMessage
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AsFbxInitializeContext(IntPtr context, IntPtr strFileName, float scaleFactor, int versionIndex, [MarshalAs(UnmanagedType.Bool)] bool isAscii, [MarshalAs(UnmanagedType.Bool)] bool is60Fps, out IntPtr strErrorMessage);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxDisposeContext(ref IntPtr ppContext);
private static void AsFbxSetFramePaths(IntPtr context, string[] framePaths)
{
var framePathCount = framePaths.Length;
if (framePathCount == 0)
{
AsFbxSetFramePaths(context, Array.Empty<IntPtr>(), 0);
}
else
{
var utf8Paths = new Utf8StringHandle[framePathCount];
try
{
for (var i = 0; i < framePathCount; i += 1)
{
utf8Paths[i] = new Utf8StringHandle(framePaths[i]);
}
var pathPointers = new IntPtr[framePathCount];
for (var i = 0; i < framePathCount; i += 1)
{
pathPointers[i] = utf8Paths[i].DangerousGetHandle();
}
AsFbxSetFramePaths(context, pathPointers, framePathCount);
}
finally
{
foreach (var path in utf8Paths)
{
path?.Dispose();
}
}
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxSetFramePaths(IntPtr context, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] strFramePaths, int count);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxExportScene(IntPtr context);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxGetSceneRootNode(IntPtr context);
private static IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, string framePath, string frameName, in Vector3 localPosition, in Vector3 localRotation, in Vector3 localScale)
{
using (var framePathUtf8 = new Utf8StringHandle(framePath))
{
using (var frameNameUtf8 = new Utf8StringHandle(frameName))
{
return AsFbxExportSingleFrame(context, parentNode, framePathUtf8.DangerousGetHandle(), frameNameUtf8.DangerousGetHandle(), localPosition.X, localPosition.Y, localPosition.Z, localRotation.X, localRotation.Y, localRotation.Z, localScale.X, localScale.Y, localScale.Z);
}
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, IntPtr strFramePath, IntPtr strFrameName, float localPositionX, float localPositionY, float localPositionZ, float localRotationX, float localRotationY, float localRotationZ, float localScaleX, float localScaleY, float localScaleZ);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxSetJointsNode_CastToBone(IntPtr context, IntPtr node, float boneSize);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxSetJointsNode_BoneInPath(IntPtr context, IntPtr node, float boneSize);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxSetJointsNode_Generic(IntPtr context, IntPtr node);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxPrepareMaterials(IntPtr context, int materialCount, int textureCount);
private static IntPtr AsFbxCreateTexture(IntPtr context, string matTexName)
{
using (var matTexNameUtf8 = new Utf8StringHandle(matTexName))
{
return AsFbxCreateTexture(context, matTexNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxCreateTexture(IntPtr context, IntPtr strMatTexName);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxLinkTexture(int dest, IntPtr texture, IntPtr material, float offsetX, float offsetY, float scaleX, float scaleY);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxMeshCreateClusterArray(int boneCount);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshDisposeClusterArray(ref IntPtr ppArray);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxMeshCreateCluster(IntPtr context, IntPtr boneNode);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshAddCluster(IntPtr array, IntPtr cluster);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxMeshCreateMesh(IntPtr context, IntPtr frameNode);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshInitControlPoints(IntPtr mesh, int vertexCount);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateElementNormal(IntPtr mesh);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateDiffuseUV(IntPtr mesh, int uv);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateNormalMapUV(IntPtr mesh, int uv);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateElementTangent(IntPtr mesh);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateElementVertexColor(IntPtr mesh);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshCreateElementMaterial(IntPtr mesh);
private static IntPtr AsFbxCreateMaterial(IntPtr pContext, string matName, in Color diffuse, in Color ambient, in Color emissive, in Color specular, in Color reflection, float shininess, float transparency)
{
using (var matNameUtf8 = new Utf8StringHandle(matName))
{
return AsFbxCreateMaterial(pContext, matNameUtf8.DangerousGetHandle(), diffuse.R, diffuse.G, diffuse.B, ambient.R, ambient.G, ambient.B, emissive.R, emissive.G, emissive.B, specular.R, specular.G, specular.B, reflection.R, reflection.G, reflection.B, shininess, transparency);
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxCreateMaterial(IntPtr pContext, IntPtr 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);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern int AsFbxAddMaterialToFrame(IntPtr frameNode, IntPtr material);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxSetFrameShadingModeToTextureShading(IntPtr frameNode);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshSetControlPoint(IntPtr mesh, int index, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshAddPolygon(IntPtr mesh, int materialIndex, int index0, int index1, int index2);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshElementNormalAdd(IntPtr mesh, int elementIndex, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshElementUVAdd(IntPtr mesh, int elementIndex, float u, float v);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshElementTangentAdd(IntPtr mesh, int elementIndex, float x, float y, float z, float w);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshElementVertexColorAdd(IntPtr mesh, int elementIndex, float r, float g, float b, float a);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshSetBoneWeight(IntPtr pClusterArray, int boneIndex, int vertexIndex, float weight);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxMeshCreateSkinContext(IntPtr context, IntPtr frameNode);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshDisposeSkinContext(ref IntPtr ppSkinContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FbxClusterArray_HasItemAt(IntPtr pClusterArray, int index);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private unsafe static extern void AsFbxMeshSkinAddCluster(IntPtr pSkinContext, IntPtr pClusterArray, int index, float* pBoneMatrix);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMeshAddDeformer(IntPtr pSkinContext, IntPtr pMesh);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxAnimCreateContext([MarshalAs(UnmanagedType.Bool)] bool eulerFilter);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimDisposeContext(ref IntPtr ppAnimContext);
private static void AsFbxAnimPrepareStackAndLayer(IntPtr pContext, IntPtr pAnimContext, string takeName)
{
using (var takeNameUtf8 = new Utf8StringHandle(takeName))
{
AsFbxAnimPrepareStackAndLayer(pContext, pAnimContext, takeNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimPrepareStackAndLayer(IntPtr pContext, IntPtr pAnimContext, IntPtr strTakeName);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimLoadCurves(IntPtr pNode, IntPtr pAnimContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimBeginKeyModify(IntPtr pAnimContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimEndKeyModify(IntPtr pAnimContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimAddScalingKey(IntPtr pAnimContext, float time, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimAddRotationKey(IntPtr pAnimContext, float time, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimAddTranslationKey(IntPtr pAnimContext, float time, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimApplyEulerFilter(IntPtr pAnimContext, float filterPrecision);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern int AsFbxAnimGetCurrentBlendShapeChannelCount(IntPtr pAnimContext, IntPtr pNode);
private static bool AsFbxAnimIsBlendShapeChannelMatch(IntPtr pAnimContext, int channelIndex, string channelName)
{
using (var channelNameUtf8 = new Utf8StringHandle(channelName))
{
return AsFbxAnimIsBlendShapeChannelMatch(pAnimContext, channelIndex, channelNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AsFbxAnimIsBlendShapeChannelMatch(IntPtr pAnimContext, int channelIndex, IntPtr strChannelName);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimBeginBlendShapeAnimCurve(IntPtr pAnimContext, int channelIndex);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimEndBlendShapeAnimCurve(IntPtr pAnimContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxAnimAddBlendShapeKeyframe(IntPtr pAnimContext, float time, float value);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern IntPtr AsFbxMorphCreateContext();
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphInitializeContext(IntPtr pContext, IntPtr pMorphContext, IntPtr pNode);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphDisposeContext(ref IntPtr ppMorphContext);
private static void AsFbxMorphAddBlendShapeChannel(IntPtr pContext, IntPtr pMorphContext, string channelName)
{
using (var channelNameUtf8 = new Utf8StringHandle(channelName))
{
AsFbxMorphAddBlendShapeChannel(pContext, pMorphContext, channelNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphAddBlendShapeChannel(IntPtr pContext, IntPtr pMorphContext, IntPtr strChannelName);
private static void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, string shapeName)
{
using (var shapeNameUtf8 = new Utf8StringHandle(shapeName))
{
AsFbxMorphAddBlendShapeChannelShape(pContext, pMorphContext, weight, shapeNameUtf8.DangerousGetHandle());
}
}
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, IntPtr strShapeName);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphCopyBlendShapeControlPoints(IntPtr pMorphContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphSetBlendShapeVertex(IntPtr pMorphContext, uint index, float x, float y, float z);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphCopyBlendShapeControlPointsNormal(IntPtr pMorphContext);
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
private static extern void AsFbxMorphSetBlendShapeVertexNormal(IntPtr pMorphContext, uint index, float x, float y, float z);
}
}
+643
View File
@@ -0,0 +1,643 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
namespace AssetStudio.FbxInterop
{
internal sealed partial class FbxExporterContext : IDisposable
{
private IntPtr _pContext;
private readonly Dictionary<ImportedFrame, IntPtr> _frameToNode;
private readonly List<KeyValuePair<string, IntPtr>> _createdMaterials;
private readonly Dictionary<string, IntPtr> _createdTextures;
public FbxExporterContext()
{
_pContext = AsFbxCreateContext();
_frameToNode = new Dictionary<ImportedFrame, IntPtr>();
_createdMaterials = new List<KeyValuePair<string, IntPtr>>();
_createdTextures = new Dictionary<string, IntPtr>();
}
~FbxExporterContext()
{
Dispose(false);
}
public void Dispose()
{
if (IsDisposed)
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}
public bool IsDisposed { get; private set; }
private void Dispose(bool disposing)
{
IsDisposed = true;
_frameToNode.Clear();
_createdMaterials.Clear();
_createdTextures.Clear();
AsFbxDisposeContext(ref _pContext);
}
private void EnsureNotDisposed()
{
if (IsDisposed)
{
throw new ObjectDisposedException(nameof(FbxExporterContext));
}
}
internal void Initialize(string fileName, float scaleFactor, int versionIndex, bool isAscii, bool is60Fps)
{
EnsureNotDisposed();
var b = AsFbxInitializeContext(_pContext, fileName, scaleFactor, versionIndex, isAscii, is60Fps, out var errorMessage);
if (!b)
{
var fullMessage = $"Failed to initialize FbxExporter: {errorMessage}";
throw new ApplicationException(fullMessage);
}
}
internal void SetFramePaths(HashSet<string> framePaths)
{
EnsureNotDisposed();
if (framePaths == null || framePaths.Count == 0)
{
return;
}
var framePathList = new List<string>(framePaths);
var framePathArray = framePathList.ToArray();
AsFbxSetFramePaths(_pContext, framePathArray);
}
internal void ExportScene()
{
EnsureNotDisposed();
AsFbxExportScene(_pContext);
}
internal void ExportFrame(List<ImportedMesh> meshList, List<ImportedFrame> meshFrames, ImportedFrame rootFrame)
{
var rootNode = AsFbxGetSceneRootNode(_pContext);
Debug.Assert(rootNode != IntPtr.Zero);
var nodeStack = new Stack<IntPtr>();
var frameStack = new Stack<ImportedFrame>();
nodeStack.Push(rootNode);
frameStack.Push(rootFrame);
while (nodeStack.Count > 0)
{
var parentNode = nodeStack.Pop();
var frame = frameStack.Pop();
var childNode = AsFbxExportSingleFrame(_pContext, parentNode, frame.Path, frame.Name, frame.LocalPosition, frame.LocalRotation, frame.LocalScale);
if (meshList != null && ImportedHelpers.FindMesh(frame.Path, meshList) != null)
{
meshFrames.Add(frame);
}
_frameToNode.Add(frame, childNode);
for (var i = frame.Count - 1; i >= 0; i -= 1)
{
nodeStack.Push(childNode);
frameStack.Push(frame[i]);
}
}
}
internal void SetJointsNode(ImportedFrame rootFrame, HashSet<string> bonePaths, bool castToBone, float boneSize)
{
var frameStack = new Stack<ImportedFrame>();
frameStack.Push(rootFrame);
while (frameStack.Count > 0)
{
var frame = frameStack.Pop();
if (_frameToNode.TryGetValue(frame, out var node))
{
Debug.Assert(node != IntPtr.Zero);
if (castToBone)
{
AsFbxSetJointsNode_CastToBone(_pContext, node, boneSize);
}
else
{
Debug.Assert(bonePaths != null);
if (bonePaths.Contains(frame.Path))
{
AsFbxSetJointsNode_BoneInPath(_pContext, node, boneSize);
}
else
{
AsFbxSetJointsNode_Generic(_pContext, node);
}
}
}
for (var i = frame.Count - 1; i >= 0; i -= 1)
{
frameStack.Push(frame[i]);
}
}
}
internal void PrepareMaterials(int materialCount, int textureCount)
{
AsFbxPrepareMaterials(_pContext, materialCount, textureCount);
}
internal void ExportMeshFromFrame(ImportedFrame rootFrame, ImportedFrame meshFrame, List<ImportedMesh> meshList, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
{
var meshNode = _frameToNode[meshFrame];
var mesh = ImportedHelpers.FindMesh(meshFrame.Path, meshList);
ExportMesh(rootFrame, materialList, textureList, meshNode, mesh, exportSkins, exportAllUvsAsDiffuseMaps);
}
private IntPtr ExportTexture(ImportedTexture texture)
{
if (texture == null)
{
return IntPtr.Zero;
}
if (_createdTextures.ContainsKey(texture.Name))
{
return _createdTextures[texture.Name];
}
var pTex = AsFbxCreateTexture(_pContext, texture.Name);
_createdTextures.Add(texture.Name, pTex);
var file = new FileInfo(texture.Name);
using (var writer = new BinaryWriter(file.Create()))
{
writer.Write(texture.Data);
}
return pTex;
}
private void ExportMesh(ImportedFrame rootFrame, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, IntPtr frameNode, ImportedMesh importedMesh, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
{
var boneList = importedMesh.BoneList;
var totalBoneCount = 0;
var hasBones = false;
if (exportSkins && boneList?.Count > 0)
{
totalBoneCount = boneList.Count;
hasBones = true;
}
var pClusterArray = IntPtr.Zero;
try
{
if (hasBones)
{
pClusterArray = AsFbxMeshCreateClusterArray(totalBoneCount);
foreach (var bone in boneList)
{
if (bone.Path != null)
{
var frame = rootFrame.FindFrameByPath(bone.Path);
var boneNode = _frameToNode[frame];
var cluster = AsFbxMeshCreateCluster(_pContext, boneNode);
AsFbxMeshAddCluster(pClusterArray, cluster);
}
else
{
AsFbxMeshAddCluster(pClusterArray, IntPtr.Zero);
}
}
}
var mesh = AsFbxMeshCreateMesh(_pContext, frameNode);
AsFbxMeshInitControlPoints(mesh, importedMesh.VertexList.Count);
if (importedMesh.hasNormal)
{
AsFbxMeshCreateElementNormal(mesh);
}
for (int i = 0; i < importedMesh.hasUV.Length; i++)
{
if (!importedMesh.hasUV[i]) { continue; }
if (i == 1 && !exportAllUvsAsDiffuseMaps)
{
AsFbxMeshCreateNormalMapUV(mesh, 1);
}
else
{
AsFbxMeshCreateDiffuseUV(mesh, i);
}
}
if (importedMesh.hasTangent)
{
AsFbxMeshCreateElementTangent(mesh);
}
if (importedMesh.hasColor)
{
AsFbxMeshCreateElementVertexColor(mesh);
}
AsFbxMeshCreateElementMaterial(mesh);
foreach (var meshObj in importedMesh.SubmeshList)
{
var materialIndex = 0;
var mat = ImportedHelpers.FindMaterial(meshObj.Material, materialList);
if (mat != null)
{
var foundMat = _createdMaterials.FindIndex(kv => kv.Key == mat.Name);
IntPtr pMat;
if (foundMat >= 0)
{
pMat = _createdMaterials[foundMat].Value;
}
else
{
var diffuse = mat.Diffuse;
var ambient = mat.Ambient;
var emissive = mat.Emissive;
var specular = mat.Specular;
var reflection = mat.Reflection;
pMat = AsFbxCreateMaterial(_pContext, mat.Name, in diffuse, in ambient, in emissive, in specular, in reflection, mat.Shininess, mat.Transparency);
_createdMaterials.Add(new KeyValuePair<string, IntPtr>(mat.Name, pMat));
}
materialIndex = AsFbxAddMaterialToFrame(frameNode, pMat);
var hasTexture = false;
foreach (var texture in mat.Textures)
{
var tex = ImportedHelpers.FindTexture(texture.Name, textureList);
var pTexture = ExportTexture(tex);
if (pTexture != IntPtr.Zero)
{
switch (texture.Dest)
{
case 0:
case 1:
case 2:
case 3:
{
AsFbxLinkTexture(texture.Dest, pTexture, pMat, texture.Offset.X, texture.Offset.Y, texture.Scale.X, texture.Scale.Y);
hasTexture = true;
break;
}
default:
break;
}
}
}
if (hasTexture)
{
AsFbxSetFrameShadingModeToTextureShading(frameNode);
}
}
foreach (var face in meshObj.FaceList)
{
var index0 = face.VertexIndices[0] + meshObj.BaseVertex;
var index1 = face.VertexIndices[1] + meshObj.BaseVertex;
var index2 = face.VertexIndices[2] + meshObj.BaseVertex;
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
}
}
var vertexList = importedMesh.VertexList;
var vertexCount = vertexList.Count;
for (var j = 0; j < vertexCount; j += 1)
{
var importedVertex = vertexList[j];
var vertex = importedVertex.Vertex;
AsFbxMeshSetControlPoint(mesh, j, vertex.X, vertex.Y, vertex.Z);
if (importedMesh.hasNormal)
{
var normal = importedVertex.Normal;
AsFbxMeshElementNormalAdd(mesh, 0, normal.X, normal.Y, normal.Z);
}
for (var uvIndex = 0; uvIndex < importedMesh.hasUV.Length; uvIndex += 1)
{
if (importedMesh.hasUV[uvIndex])
{
var uv = importedVertex.UV[uvIndex];
AsFbxMeshElementUVAdd(mesh, uvIndex, uv[0], uv[1]);
}
}
if (importedMesh.hasTangent)
{
var tangent = importedVertex.Tangent;
AsFbxMeshElementTangentAdd(mesh, 0, tangent.X, tangent.Y, tangent.Z, tangent.W);
}
if (importedMesh.hasColor)
{
var color = importedVertex.Color;
AsFbxMeshElementVertexColorAdd(mesh, 0, color.R, color.G, color.B, color.A);
}
if (hasBones && importedVertex.BoneIndices != null)
{
var boneIndices = importedVertex.BoneIndices;
var boneWeights = importedVertex.Weights;
for (var k = 0; k < 4; k += 1)
{
if (boneIndices[k] < totalBoneCount && boneWeights[k] > 0)
{
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j, boneWeights[k]);
}
}
}
}
if (hasBones)
{
IntPtr pSkinContext = IntPtr.Zero;
try
{
pSkinContext = AsFbxMeshCreateSkinContext(_pContext, frameNode);
unsafe
{
var boneMatrix = stackalloc float[16];
for (var j = 0; j < totalBoneCount; j += 1)
{
if (!FbxClusterArray_HasItemAt(pClusterArray, j))
{
continue;
}
var m = boneList[j].Matrix;
CopyMatrix4x4(in m, boneMatrix);
AsFbxMeshSkinAddCluster(pSkinContext, pClusterArray, j, boneMatrix);
}
}
AsFbxMeshAddDeformer(pSkinContext, mesh);
}
finally
{
AsFbxMeshDisposeSkinContext(ref pSkinContext);
}
}
}
finally
{
AsFbxMeshDisposeClusterArray(ref pClusterArray);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CopyMatrix4x4(in Matrix4x4 matrix, float* buffer)
{
for (var m = 0; m < 4; m += 1)
{
for (var n = 0; n < 4; n += 1)
{
var index = IndexFrom4x4(m, n);
buffer[index] = matrix[m, n];
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int IndexFrom4x4(int m, int n)
{
return 4 * m + n;
}
internal void ExportAnimations(ImportedFrame rootFrame, List<ImportedKeyframedAnimation> animationList, bool eulerFilter, float filterPrecision)
{
if (animationList == null || animationList.Count == 0)
{
return;
}
var pAnimContext = IntPtr.Zero;
try
{
pAnimContext = AsFbxAnimCreateContext(eulerFilter);
for (int i = 0; i < animationList.Count; i++)
{
var importedAnimation = animationList[i];
string takeName;
if (importedAnimation.Name != null)
{
takeName = importedAnimation.Name;
}
else
{
takeName = $"Take{i.ToString()}";
}
AsFbxAnimPrepareStackAndLayer(_pContext, pAnimContext, takeName);
ExportKeyframedAnimation(rootFrame, importedAnimation, pAnimContext, filterPrecision);
}
}
finally
{
AsFbxAnimDisposeContext(ref pAnimContext);
}
}
private void ExportKeyframedAnimation(ImportedFrame rootFrame, ImportedKeyframedAnimation parser, IntPtr pAnimContext, float filterPrecision)
{
foreach (var track in parser.TrackList)
{
if (track.Path == null)
{
continue;
}
var frame = rootFrame.FindFrameByPath(track.Path);
if (frame == null)
{
continue;
}
var pNode = _frameToNode[frame];
AsFbxAnimLoadCurves(pNode, pAnimContext);
AsFbxAnimBeginKeyModify(pAnimContext);
foreach (var scaling in track.Scalings)
{
var value = scaling.value;
AsFbxAnimAddScalingKey(pAnimContext, scaling.time, value.X, value.Y, value.Z);
}
foreach (var rotation in track.Rotations)
{
var value = rotation.value;
AsFbxAnimAddRotationKey(pAnimContext, rotation.time, value.X, value.Y, value.Z);
}
foreach (var translation in track.Translations)
{
var value = translation.value;
AsFbxAnimAddTranslationKey(pAnimContext, translation.time, value.X, value.Y, value.Z);
}
AsFbxAnimEndKeyModify(pAnimContext);
AsFbxAnimApplyEulerFilter(pAnimContext, filterPrecision);
var blendShape = track.BlendShape;
if (blendShape != null)
{
var channelCount = AsFbxAnimGetCurrentBlendShapeChannelCount(pAnimContext, pNode);
if (channelCount > 0)
{
for (var channelIndex = 0; channelIndex < channelCount; channelIndex += 1)
{
if (!AsFbxAnimIsBlendShapeChannelMatch(pAnimContext, channelIndex, blendShape.ChannelName))
{
continue;
}
AsFbxAnimBeginBlendShapeAnimCurve(pAnimContext, channelIndex);
foreach (var keyframe in blendShape.Keyframes)
{
AsFbxAnimAddBlendShapeKeyframe(pAnimContext, keyframe.time, keyframe.value);
}
AsFbxAnimEndBlendShapeAnimCurve(pAnimContext);
}
}
}
}
}
internal void ExportMorphs(ImportedFrame rootFrame, List<ImportedMorph> morphList)
{
if (morphList == null || morphList.Count == 0)
{
return;
}
foreach (var morph in morphList)
{
var frame = rootFrame.FindFrameByPath(morph.Path);
if (frame == null)
{
continue;
}
var pNode = _frameToNode[frame];
var pMorphContext = IntPtr.Zero;
try
{
pMorphContext = AsFbxMorphCreateContext();
AsFbxMorphInitializeContext(_pContext, pMorphContext, pNode);
foreach (var channel in morph.Channels)
{
AsFbxMorphAddBlendShapeChannel(_pContext, pMorphContext, channel.Name);
for (var i = 0; i < channel.KeyframeList.Count; i++)
{
var keyframe = channel.KeyframeList[i];
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight, i == 0 ? channel.Name : $"{channel.Name}_{i + 1}");
AsFbxMorphCopyBlendShapeControlPoints(pMorphContext);
foreach (var vertex in keyframe.VertexList)
{
var v = vertex.Vertex.Vertex;
AsFbxMorphSetBlendShapeVertex(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
}
if (keyframe.hasNormals)
{
AsFbxMorphCopyBlendShapeControlPointsNormal(pMorphContext);
foreach (var vertex in keyframe.VertexList)
{
var v = vertex.Vertex.Normal;
AsFbxMorphSetBlendShapeVertexNormal(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
}
}
}
}
}
finally
{
AsFbxMorphDisposeContext(ref pMorphContext);
}
}
}
}
}
+83 -191
View File
@@ -1,192 +1,84 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <OutputType>WinExe</OutputType>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <TargetFrameworks>net472;net5.0-windows;net6.0-windows</TargetFrameworks>
<ProductVersion>8.0.30703</ProductVersion> <UseWindowsForms>true</UseWindowsForms>
<SchemaVersion>2.0</SchemaVersion> <ApplicationIcon>Resources\as.ico</ApplicationIcon>
<ProjectGuid>{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}</ProjectGuid> <Version>0.16.0.0</Version>
<OutputType>WinExe</OutputType> <AssemblyVersion>0.16.0.0</AssemblyVersion>
<AppDesignerFolder>Properties</AppDesignerFolder> <FileVersion>0.16.0.0</FileVersion>
<RootNamespace>AssetStudioGUI</RootNamespace> <Copyright>Copyright © Perfare 2018-2022</Copyright>
<AssemblyName>AssetStudioGUI</AssemblyName> <DebugType>embedded</DebugType>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> </PropertyGroup>
<TargetFrameworkProfile>
</TargetFrameworkProfile> <ItemGroup>
<FileAlignment>512</FileAlignment> <ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj" />
<IsWebBootstrapper>false</IsWebBootstrapper> <ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
<PublishUrl>publish\</PublishUrl> </ItemGroup>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom> <ItemGroup>
<UpdateEnabled>false</UpdateEnabled> <None Include="Properties\Settings.settings">
<UpdateMode>Foreground</UpdateMode> <Generator>SettingsSingleFileGenerator</Generator>
<UpdateInterval>7</UpdateInterval> <LastGenOutput>Settings.Designer.cs</LastGenOutput>
<UpdateIntervalUnits>Days</UpdateIntervalUnits> </None>
<UpdatePeriodically>false</UpdatePeriodically> <Compile Update="Properties\Settings.Designer.cs">
<UpdateRequired>false</UpdateRequired> <AutoGen>True</AutoGen>
<MapFileExtensions>true</MapFileExtensions> <DependentUpon>Settings.settings</DependentUpon>
<ApplicationRevision>0</ApplicationRevision> <DesignTimeSharedInput>True</DesignTimeSharedInput>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion> </Compile>
<UseApplicationTrust>false</UseApplicationTrust> </ItemGroup>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup> <ItemGroup>
<PropertyGroup> <EmbeddedResource Update="Properties\Resources.resx">
<ApplicationIcon>Resources\as.ico</ApplicationIcon> <Generator>ResXFileCodeGenerator</Generator>
</PropertyGroup> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> </EmbeddedResource>
<DebugSymbols>true</DebugSymbols> <Compile Update="Properties\Resources.Designer.cs">
<OutputPath>bin\x64\Debug\</OutputPath> <AutoGen>True</AutoGen>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DependentUpon>Resources.resx</DependentUpon>
<DebugType>full</DebugType> <DesignTime>True</DesignTime>
<PlatformTarget>x64</PlatformTarget> </Compile>
<ErrorReport>prompt</ErrorReport> </ItemGroup>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> <ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <ContentWithTargetPath Include="Libraries\x86\fmod.dll">
<OutputPath>bin\x64\Release\</OutputPath> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DefineConstants>TRACE</DefineConstants> <TargetPath>x86\fmod.dll</TargetPath>
<Optimize>true</Optimize> </ContentWithTargetPath>
<DebugType>pdbonly</DebugType> <ContentWithTargetPath Include="Libraries\x64\fmod.dll">
<PlatformTarget>x64</PlatformTarget> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ErrorReport>prompt</ErrorReport> <TargetPath>x64\fmod.dll</TargetPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> </ContentWithTargetPath>
</PropertyGroup> </ItemGroup>
<PropertyGroup>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent> <ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
</PropertyGroup> <PackageReference Include="OpenTK" Version="4.6.7" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> <Reference Include="OpenTK.WinForms">
<DebugSymbols>true</DebugSymbols> <HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
<OutputPath>bin\x86\Debug\</OutputPath> </Reference>
<DefineConstants>DEBUG;TRACE</DefineConstants> </ItemGroup>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget> <ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
<ErrorReport>prompt</ErrorReport> <PackageReference Include="OpenTK" Version="3.1.0" />
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <PackageReference Include="OpenTK.GLControl" Version="3.1.0" />
</PropertyGroup> </ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath> <ItemGroup>
<DefineConstants>TRACE</DefineConstants> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<Optimize>true</Optimize> </ItemGroup>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget> <Target Name="CopyExtraFiles" AfterTargets="AfterBuild">
<ErrorReport>prompt</ErrorReport> <Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
</PropertyGroup> <Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
<ItemGroup> <Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
<Reference Include="OpenTK"> </Target>
<HintPath>Libraries\OpenTK.dll</HintPath>
</Reference> <Target Name="PublishExtraFiles" AfterTargets="Publish">
<Reference Include="OpenTK.GLControl"> <Copy SourceFiles="$(TargetDir)x86\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
<HintPath>Libraries\OpenTK.GLControl.dll</HintPath> <Copy SourceFiles="$(TargetDir)x64\AssetStudioFBXNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
</Reference> <Copy SourceFiles="$(TargetDir)x86\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x86" ContinueOnError="true" />
<Reference Include="System" /> <Copy SourceFiles="$(TargetDir)x64\Texture2DDecoderNative.dll" DestinationFolder="$(PublishDir)x64" ContinueOnError="true" />
<Reference Include="System.Core" /> </Target>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="GUILogger.cs" />
<Compile Include="GUIProgress.cs" />
<Compile Include="Components\GameObjectTreeNode.cs" />
<Compile Include="Components\OpenFolderDialog.cs" />
<Compile Include="Components\AssetItem.cs" />
<Compile Include="Exporter.cs" />
<Compile Include="Studio.cs" />
<Compile Include="ExportOptions.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ExportOptions.Designer.cs">
<DependentUpon>ExportOptions.cs</DependentUpon>
</Compile>
<Compile Include="Components\GOHierarchy.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AssetStudioGUIForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="AssetStudioGUIForm.Designer.cs">
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
</Compile>
<Compile Include="Components\TypeTreeItem.cs" />
<Compile Include="Components\TreeViewExtensions.cs" />
<EmbeddedResource Include="ExportOptions.resx">
<DependentUpon>ExportOptions.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="AssetStudioGUIForm.resx">
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<None Include="Resources\preview.png" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\as.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
<Name>AssetStudioUtility</Name>
</ProjectReference>
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
<Name>AssetStudio</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy /y "$(ProjectDir)Libraries" "$(TargetDir)"
xcopy /y "$(ProjectDir)Libraries\$(PlatformName)" "$(TargetDir)"</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project> </Project>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-3
View File
@@ -147,9 +147,6 @@ The quick brown fox jumps over the lazy dog. 1234567890</value>
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>636, 17</value> <value>636, 17</value>
</metadata> </metadata>
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>784, 17</value>
</metadata>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>147, 17</value> <value>147, 17</value>
</metadata> </metadata>
+16 -4
View File
@@ -7,11 +7,11 @@ namespace AssetStudioGUI
{ {
public Object Asset; public Object Asset;
public SerializedFile SourceFile; public SerializedFile SourceFile;
public string Container = string.Empty;
public string TypeString;
public long m_PathID;
public long FullSize; public long FullSize;
public ClassIDType Type; public ClassIDType Type;
public string TypeString;
public string Extension;
public string InfoText; public string InfoText;
public string UniqueID; public string UniqueID;
public GameObjectTreeNode TreeNode; public GameObjectTreeNode TreeNode;
@@ -20,9 +20,21 @@ namespace AssetStudioGUI
{ {
Asset = asset; Asset = asset;
SourceFile = asset.assetsFile; SourceFile = asset.assetsFile;
FullSize = asset.byteSize;
Type = asset.type; Type = asset.type;
TypeString = Type.ToString(); TypeString = Type.ToString();
m_PathID = asset.m_PathID;
FullSize = asset.byteSize;
}
public void SetSubItems()
{
SubItems.AddRange(new[]
{
Container, //Container
TypeString, //Type
m_PathID.ToString(), //PathID
FullSize.ToString(), //Size
});
} }
} }
} }
@@ -7,11 +7,6 @@ namespace AssetStudioGUI
{ {
public GameObject gameObject; public GameObject gameObject;
public GameObjectTreeNode(string name)
{
Text = name;
}
public GameObjectTreeNode(GameObject gameObject) public GameObjectTreeNode(GameObject gameObject)
{ {
this.gameObject = gameObject; this.gameObject = gameObject;
+21 -12
View File
@@ -1,5 +1,4 @@
using System; using System;
using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
@@ -15,12 +14,13 @@ namespace AssetStudioGUI
internal DialogResult ShowDialog(IWin32Window owner = null) internal DialogResult ShowDialog(IWin32Window owner = null)
{ {
//#if NETFRAMEWORK
if (Environment.OSVersion.Version.Major >= 6) if (Environment.OSVersion.Version.Major >= 6)
{ {
return ShowVistaDialog(owner); return ShowVistaDialog(owner);
} }
//#endif
return ShowLegacyDialog(owner); return ShowFolderBrowserDialog(owner);
} }
private DialogResult ShowVistaDialog(IWin32Window owner) private DialogResult ShowVistaDialog(IWin32Window owner)
@@ -29,9 +29,11 @@ namespace AssetStudioGUI
frm.GetOptions(out var options); frm.GetOptions(out var options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT; options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options); frm.SetOptions(options);
if (Title != null) if (!string.IsNullOrEmpty(Title))
{
frm.SetTitle(Title); frm.SetTitle(Title);
if (InitialFolder != null) }
if (!string.IsNullOrEmpty(InitialFolder))
{ {
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK) if (NativeMethods.SHCreateItemFromParsingName(InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
@@ -39,7 +41,7 @@ namespace AssetStudioGUI
frm.SetFolder(directoryShellItem); frm.SetFolder(directoryShellItem);
} }
} }
if (DefaultFolder != null) if (!string.IsNullOrEmpty(DefaultFolder))
{ {
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK) if (NativeMethods.SHCreateItemFromParsingName(DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
@@ -72,7 +74,7 @@ namespace AssetStudioGUI
return DialogResult.Cancel; return DialogResult.Cancel;
} }
private DialogResult ShowLegacyDialog(IWin32Window owner) private DialogResult ShowFolderBrowserDialog(IWin32Window owner)
{ {
using (var frm = new FolderBrowserDialog()) using (var frm = new FolderBrowserDialog())
{ {
@@ -80,13 +82,20 @@ namespace AssetStudioGUI
{ {
frm.SelectedPath = InitialFolder; frm.SelectedPath = InitialFolder;
} }
if ((owner == null ? frm.ShowDialog() : frm.ShowDialog(owner)) == DialogResult.OK) #if !NETFRAMEWORK
if (Title != null)
{ {
Folder = Path.GetDirectoryName(frm.SelectedPath); frm.Description = Title;
return DialogResult.OK; frm.UseDescriptionForTitle = true;
} }
#endif
return DialogResult.Cancel; var result = owner == null ? frm.ShowDialog() : frm.ShowDialog(owner);
if (result == DialogResult.OK)
{
Folder = frm.SelectedPath;
return result;
}
return result;
} }
} }
} }
@@ -1,48 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AssetStudioGUI
{
internal static class TreeViewExtensions
{
private const int TVIF_STATE = 0x8;
private const int TVIS_STATEIMAGEMASK = 0xF000;
private const int TV_FIRST = 0x1100;
private const int TVM_SETITEM = TV_FIRST + 63;
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
private struct TVITEM
{
public int mask;
public IntPtr hItem;
public int state;
public int stateMask;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref TVITEM lParam);
/// <summary>
/// Hides the checkbox for the specified node on a TreeView control.
/// </summary>
public static void HideCheckBox(this TreeNode node)
{
var tvi = new TVITEM
{
hItem = node.Handle,
mask = TVIF_STATE,
stateMask = TVIS_STATEIMAGEMASK,
state = 0
};
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}
}
}

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