Compare commits

..

15 Commits

12 changed files with 885 additions and 251 deletions

View File

@ -1,5 +1,17 @@
# Changelog
## [0.4.1]
### Fixed
- Improved material parsing, big thanks to [bevity](https://github.com/gamedolphin/bevity).
## [0.4.0]
### Added
- New flag `--get_materials_from_prefabs` for updating model textures based on prefabs and materials.
## [0.3.0]
### Added

553
Cargo.lock generated
View File

@ -1,84 +1,88 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "adler"
version = "1.0.2"
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "ahash"
version = "0.8.6"
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "anstream"
version = "0.6.5"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "autocfg"
version = "1.1.0"
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bitflags"
@ -88,9 +92,27 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bytemuck"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "cfg-if"
@ -100,9 +122,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.11"
version = "4.5.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
dependencies = [
"clap_builder",
"clap_derive",
@ -110,9 +132,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.11"
version = "4.5.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
dependencies = [
"anstream",
"anstyle",
@ -122,9 +144,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.4.7"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
@ -134,182 +156,301 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.6.0"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "colorchoice"
version = "1.0.0"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "crc32fast"
version = "1.3.2"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.4"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.16"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.17"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
dependencies = [
"cfg-if",
]
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "either"
version = "1.9.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "filetime"
version = "0.2.23"
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "filetime"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"libredox",
"windows-sys",
]
[[package]]
name = "flate2"
version = "1.0.28"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
name = "gltf"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7"
dependencies = [
"ahash",
"allocator-api2",
"rayon",
"base64",
"byteorder",
"gltf-json",
"image",
"lazy_static",
"serde_json",
"urlencoding",
]
[[package]]
name = "heck"
version = "0.4.1"
name = "gltf-derive"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51"
dependencies = [
"inflections",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gltf-json"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14"
dependencies = [
"gltf-derive",
"serde",
"serde_derive",
"serde_json",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "image"
version = "0.25.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
dependencies = [
"bytemuck",
"byteorder-lite",
"num-traits",
"png",
"zune-core",
"zune-jpeg",
]
[[package]]
name = "indexmap"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "inflections"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.6.0",
"libc",
"redox_syscall",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "lwa_unity_unpack"
version = "0.2.1"
version = "0.4.1"
dependencies = [
"anyhow",
"clap",
"flate2",
"hashbrown",
"gltf",
"rayon",
"regex",
"serde",
"serde_yaml",
"tar",
]
[[package]]
name = "memoffset"
version = "0.9.0"
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"adler",
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.70"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
@ -317,9 +458,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.12.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
@ -327,20 +468,49 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.4.1"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.6.0",
]
[[package]]
name = "rustix"
version = "0.38.28"
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"bitflags 2.4.1",
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustix"
version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
@ -348,16 +518,73 @@ dependencies = [
]
[[package]]
name = "strsim"
version = "0.10.0"
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.41"
version = "2.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
dependencies = [
"proc-macro2",
"quote",
@ -366,9 +593,9 @@ dependencies = [
[[package]]
name = "tar"
version = "0.4.40"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb"
checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6"
dependencies = [
"filetime",
"libc",
@ -377,40 +604,47 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf8parse"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.52.0"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
@ -419,51 +653,57 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "xattr"
version = "1.1.3"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
dependencies = [
"libc",
"linux-raw-sys",
@ -471,21 +711,16 @@ dependencies = [
]
[[package]]
name = "zerocopy"
version = "0.7.32"
name = "zune-core"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
name = "zune-jpeg"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
dependencies = [
"proc-macro2",
"quote",
"syn",
"zune-core",
]

View File

@ -1,6 +1,6 @@
[package]
name = "lwa_unity_unpack"
version = "0.3.0"
version = "0.4.1"
edition = "2021"
repository = "https://github.com/Leinnan/lwa_unity_unpack"
homepage = "https://github.com/Leinnan/lwa_unity_unpack"
@ -20,8 +20,12 @@ lto = true
opt-level = 2
[dependencies]
clap = { version = "4.4", features = ["derive"] }
flate2 = "1.0"
hashbrown = { version ="0.14.3", features = ["ahash","allocator-api2","inline-more","rayon"] }
rayon = "1.8.0"
clap = { version = "4.5", features = ["derive"] }
flate2 = "1"
gltf = "1"
rayon = "1"
regex = "1"
tar = "0.4"
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
anyhow = "1"

View File

@ -16,6 +16,8 @@ Options:
-i, --input <INPUT> .unitypackage file to extract
-o, --output <OUTPUT> target directory
-f, --fbx-to-gltf <FBX_TO_GLTF> optional- path to the tool that will auto convert fbx files to gltf during unpacking
--get-materials-from-prefabs
checks if material base texture in prefabs differ from the one specified in fbx model that is converted to GLTF and overrides it with the one from prefab and copy texture to models folder
--ignore-extensions <IGNORE_EXTENSIONS>
optional- extensions that will be ignored during unpacking
--copy-meta-files

View File

@ -13,9 +13,14 @@ pub struct Args {
pub output: PathBuf,
/// optional- path to the tool that will auto convert fbx files to gltf during unpacking
#[arg(short, long)]
#[arg(long)]
pub fbx_to_gltf: Option<PathBuf>,
/// checks if material base texture in prefabs differ from the one specified in fbx model
/// that is converted to GLTF and overrides it with the one from prefab and copy texture to models folder
#[arg(long, default_value = "false", default_missing_value = "true")]
pub get_materials_from_prefabs: bool,
/// optional- extensions that will be ignored during unpacking
#[arg(long, action = clap::ArgAction::Append)]
pub ignore_extensions: Option<Vec<String>>,
@ -24,3 +29,34 @@ pub struct Args {
#[arg(long, default_value = "false", default_missing_value = "true")]
pub copy_meta_files: bool,
}
impl Args {
pub fn check(&self) {
if let Some(path) = &self.fbx_to_gltf {
assert!(
is_executable(&path),
"fbx_to_gltf require a path to executable"
)
}
}
}
#[cfg(target_os = "windows")]
fn is_executable(path: &PathBuf) -> bool {
if let Some(extension) = path.extension() {
extension.to_str().unwrap().ends_with("exe")
} else {
false
}
}
#[cfg(not(target_os = "windows"))]
fn is_executable(path: &PathBuf) -> bool {
use std::os::unix::fs::PermissionsExt;
if let Ok(metadata) = std::fs::metadata(path) {
let permissions = metadata.permissions();
permissions.mode() & 0o111 != 0
} else {
false
}
}

View File

@ -1,26 +1,75 @@
use crate::primitives::materials::read_single_material;
use std::ffi::OsStr;
use std::fs;
use std::fs::DirEntry;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::path::Path;
#[derive(Clone)]
pub struct Asset {
pub extension: Option<String>,
pub hash: String,
pub path_name: String,
pub guid: String,
pub path: String,
pub has_meta: bool,
pub asset_type: AssetType,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum AssetType {
FbxModel,
Material,
Prefab,
Scene,
Other(String),
}
impl Asset {
pub fn from_path(entry: &DirEntry) -> Option<Asset> {
pub fn try_get_mat_texture_guid(&self) -> Option<String> {
match &self.asset_type {
AssetType::Material => {}
_ => return None,
}
let content = fs::read_to_string(&self.path).unwrap();
let material = read_single_material(&content);
if let Ok(mat) = material {
return mat
.properties
.tex_envs
.iter()
.find_map(|tex| tex.get("_MainTex"))
.and_then(|t| t.texture.guid.clone());
}
None
}
pub fn prepare_directory(&self) {
println!("{}: {:?}", self.guid, self.path);
let base_path = Path::new(&self.path);
let result_dir = base_path.parent();
if result_dir.is_none() {
eprintln!("{} is none", &self.path);
}
let result_dir = result_dir.unwrap();
if !result_dir.exists() {
let result = fs::create_dir_all(result_dir);
if result.is_err() {
eprintln!(
"Error {}: {}",
result_dir.to_str().unwrap(),
result.err().unwrap()
);
}
}
}
pub fn from_path(entry: &DirEntry, output_dir: &Path) -> Option<Asset> {
let root_file = entry.path();
if !root_file.is_dir() {
return None;
}
let asset = entry.file_name().into_string().unwrap();
let guid = entry.file_name().into_string().unwrap();
let mut real_path = String::new();
let mut extension = None;
let mut has_asset = false;
@ -36,7 +85,7 @@ impl Asset {
let line = buf_reader.lines().next();
match line {
Some(Ok(path)) => {
real_path = path;
real_path = output_dir.join(path).to_str().unwrap().to_string();
if let Some(e) =
Path::new(&real_path).extension().and_then(OsStr::to_str)
{
@ -52,11 +101,22 @@ impl Asset {
}
}
if has_asset {
let asset_type = match &extension {
Some(str) => match str.as_str() {
"fbx" => AssetType::FbxModel,
"prefab" => AssetType::Prefab,
"unity" => AssetType::Scene,
"mat" => AssetType::Material,
_ => AssetType::Other(str.clone()),
},
_ => AssetType::Other(String::new()),
};
Some(Asset {
extension,
hash: asset,
path_name: real_path,
guid,
path: real_path,
has_meta,
asset_type,
})
} else {
None

View File

@ -1,13 +1,19 @@
mod args;
pub mod asset;
pub mod primitives;
mod unpacker;
mod yaml_helpers;
use clap::Parser;
fn main() {
let args = crate::args::Args::parse();
let unpacker = crate::unpacker::Unpacker { args };
let mut unpacker = crate::unpacker::Unpacker {
args,
assets: vec![],
};
unpacker.prepare_environment();
unpacker.extract();
unpacker.process_data();
unpacker.update_gltf_materials();
}

101
src/primitives/materials.rs Normal file
View File

@ -0,0 +1,101 @@
use crate::primitives::reference::FileReference;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// use bevy::prelude::*;
use crate::yaml_helpers::parse_unity_yaml;
use anyhow::{bail, Context, Result};
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct UnityMaterial {
#[serde(alias = "m_Name")]
pub name: String,
#[serde(alias = "m_Shader")]
pub shader: FileReference,
#[serde(alias = "m_SavedProperties")]
pub properties: SavedProperties,
#[serde(default, alias = "stringTagMap")]
pub string_tags: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct SavedProperties {
#[serde(alias = "serializedVersion")]
pub serialized_version: u64,
#[serde(alias = "m_TexEnvs")]
pub tex_envs: Vec<HashMap<String, TextureInfo>>,
#[serde(alias = "m_Floats")]
pub floats: Vec<HashMap<String, f32>>,
#[serde(alias = "m_Colors")]
pub colors: Vec<HashMap<String, UnityColor>>,
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TextureInfo {
#[serde(alias = "m_Texture")]
pub texture: FileReference,
#[serde(alias = "m_Scale")]
pub scale: UnityVector2,
#[serde(alias = "m_Offset")]
pub offset: UnityVector2,
}
#[derive(Serialize, Deserialize, Debug, Default, Copy, Clone)]
pub struct UnityVector2 {
pub x: f32,
pub y: f32,
}
#[derive(Serialize, Deserialize, Debug, Default, Copy, Clone)]
pub struct UnityColor {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
// impl From<UnityColor> for Color {
// fn from(value: UnityColor) -> Self {
// Color::Rgba {
// red: value.r,
// green: value.g,
// blue: value.b,
// alpha: value.a,
// }
// }
// }
//
// impl From<&UnityColor> for Color {
// fn from(value: &UnityColor) -> Self {
// Color::Rgba {
// red: value.r,
// green: value.g,
// blue: value.b,
// alpha: value.a,
// }
// }
// }
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "object_type")]
enum MaterialContainer {
Material(UnityMaterial),
#[serde(other)]
DontCare,
}
pub fn read_single_material(contents: &str) -> Result<UnityMaterial> {
let map = parse_unity_yaml(contents)?;
let (_, output) = map.into_iter().next().context("0 items in material file")?;
let MaterialContainer::Material(mat) = output else {
bail!("invalid material file");
};
Ok(mat)
}

2
src/primitives/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod materials;
pub mod reference;

View File

@ -0,0 +1,53 @@
use serde::{
de::{self, Visitor},
Deserialize, Deserializer, Serialize,
};
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct FileReference {
#[serde(alias = "fileID")]
pub file_id: i64,
#[serde(default, deserialize_with = "deserialize_option_string_or_float")]
pub guid: Option<String>,
}
fn deserialize_option_string_or_float<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
struct StringOrFloat;
impl<'de> Visitor<'de> for StringOrFloat {
type Value = Option<String>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string or a float")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Ok(Some(value.to_owned()))
}
fn visit_string<E: de::Error>(self, value: String) -> Result<Self::Value, E> {
Ok(Some(value))
}
fn visit_f64<E: de::Error>(self, _: f64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_f32<E: de::Error>(self, _: f32) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
}
deserializer.deserialize_any(StringOrFloat)
}

View File

@ -1,12 +1,11 @@
use crate::asset::Asset;
use crate::asset::{Asset, AssetType};
use flate2::read::GzDecoder;
use hashbrown::HashMap;
use gltf::{json, Document};
use rayon::prelude::*;
use std::ffi::OsStr;
use std::borrow::Cow;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process::Command;
use std::sync::mpsc::channel;
use std::sync::Arc;
@ -16,10 +15,12 @@ use tar::Archive;
#[derive(Clone)]
pub struct Unpacker {
pub args: crate::args::Args,
pub assets: Vec<Asset>,
}
impl Unpacker {
pub fn prepare_environment(&self) {
self.args.check();
let archive_path = Path::new(&self.args.input);
let output_dir = Path::new(&self.args.output);
let tmp_path = Path::new("./tmp_dir");
@ -36,11 +37,11 @@ impl Unpacker {
}
}
pub fn process_data(&self) {
pub fn extract(&mut self) {
let archive_path = Path::new(&self.args.input);
let output_dir = Path::new(&self.args.output);
let copy_meta_files = self.args.copy_meta_files;
let tmp_path = Path::new("./tmp_dir");
let output_dir = Path::new(&self.args.output);
if let Err(e) = Unpacker::extract_archive(archive_path, tmp_path) {
println!("Failed to extract archive: {}", e);
}
@ -53,7 +54,7 @@ impl Unpacker {
.par_bridge()
.for_each_with(sender, |s, entry| {
let entry = entry.unwrap();
let asset = crate::asset::Asset::from_path(&entry);
let asset = crate::asset::Asset::from_path(&entry, output_dir);
if let Some(asset) = asset {
let extension = &asset.extension.clone().unwrap_or_default();
if !ignored_extensions.contains(extension) {
@ -61,87 +62,168 @@ impl Unpacker {
}
}
});
self.assets = receiver.iter().collect();
}
let tmp_dir = Arc::new(tmp_path);
fs::create_dir(output_dir).unwrap();
let output_dir = Arc::new(output_dir);
let mapping: Vec<Asset> = receiver.iter().collect();
let mapping_arc = Arc::new(mapping);
pub fn assets_of_type(&self, asset_type: AssetType) -> Vec<Asset> {
self.assets
.clone()
.into_iter()
.filter(|a| a.asset_type == asset_type)
.collect()
}
mapping_arc.par_iter().for_each(|asset| {
let asset_hash = &asset.hash;
let path = Path::new(&asset.path_name);
let source_asset = Path::new(&*tmp_dir).join(asset_hash).join("asset");
let result_path = output_dir.join(path);
pub fn update_gltf_materials(&self) {
if self.args.fbx_to_gltf.is_none() || !self.args.get_materials_from_prefabs {
return;
}
let fbx_models = self.assets_of_type(AssetType::FbxModel);
let prefabs = self.assets_of_type(AssetType::Prefab);
let materials = self.assets_of_type(AssetType::Material);
println!(
"There are {} models, {} prefabs and {} materials",
fbx_models.len(),
prefabs.len(),
materials.len()
);
process_directory(asset_hash, &asset.path_name, &result_path);
if copy_meta_files && asset.has_meta {
let source_meta = Path::new(&*tmp_dir).join(asset_hash).join("asset.meta");
let mut meta_path = asset.path_name.clone();
meta_path.push_str(".meta");
let result_path = output_dir.join(meta_path);
fs::rename(source_meta, result_path).unwrap();
prefabs.par_iter().for_each(|prefab| {
let path = Path::new(&prefab.path);
let prefab_content = fs::read_to_string(path).unwrap();
let matching_materials: Vec<Asset> = materials
.clone()
.into_iter()
.filter(|a| prefab_content.contains(&a.guid))
.collect();
let matching_models: Vec<Asset> = fbx_models
.clone()
.into_iter()
.filter(|a| prefab_content.contains(&a.guid))
.collect();
if matching_materials.len() != 1 || 1 != matching_models.len() {
return;
}
check_source_asset_exists(&source_asset);
let material = matching_materials.first().unwrap();
let model: &Asset = matching_models.first().unwrap();
let texture_guid: Option<String> = material.try_get_mat_texture_guid();
if self.args.fbx_to_gltf.is_some() {
if let Some("fbx") = path.extension().and_then(OsStr::to_str) {
process_fbx_file(
&source_asset,
&result_path,
&self.args.fbx_to_gltf.clone().unwrap(),
);
let texture_asset: &Asset = match &texture_guid {
Some(guid) => self.assets.iter().find(|a| guid.eq(&a.guid)).unwrap(),
None => return,
};
// here we should read gltf file and replace material texture with Uri based on texture_asset
let model_path = Path::new(&model.path).with_extension("glb");
Self::update_material(&model_path, Path::new(&texture_asset.path));
});
}
fn align_to_multiple_of_four(n: &mut usize) {
*n = (*n + 3) & !3;
}
fn update_material(gltf_path: &Path, texture_asset: &Path) {
let file = fs::File::open(gltf_path).unwrap();
let reader = io::BufReader::new(file);
let mut gltf = gltf::Gltf::from_reader(reader).unwrap();
let mut json = gltf.document.into_json();
for image in json.images.iter_mut() {
let result = texture_asset
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string();
let required_file = gltf_path.with_file_name(&result);
if !required_file.exists() {
fs::copy(texture_asset, gltf_path.with_file_name(&result)).unwrap();
}
if let Some(old_path) = &image.uri {
if old_path.eq(&result) {
return;
}
}
process_non_fbx_file(&source_asset, &result_path);
});
fs::remove_dir_all(Path::new(&*tmp_dir)).unwrap();
fn process_directory(asset_hash: &str, asset_path: &str, result_path: &Path) {
println!("{}: {:?}", asset_hash, asset_path);
let result_dir = result_path.parent().unwrap();
if !result_dir.exists() {
fs::create_dir_all(result_dir).unwrap();
}
println!(
"Image{:?}: {:?} to be replaced with: {}",
image.name, image.uri, &result
);
image.uri = Some(result);
}
fn check_source_asset_exists(source_asset: &Path) {
gltf.document = Document::from_json(json.clone()).unwrap();
// Save the modified glTF
let json_string = json::serialize::to_string(&json).expect("Serialization error");
let mut json_offset = json_string.len();
Self::align_to_multiple_of_four(&mut json_offset);
let blob = gltf.blob.clone().unwrap_or_default();
let buffer_length = blob.len();
let glb = gltf::binary::Glb {
header: gltf::binary::Header {
magic: *b"glTF",
version: 2,
// N.B., the size of binary glTF file is limited to range of `u32`.
length: (json_offset + buffer_length)
.try_into()
.expect("file size exceeds binary glTF limit"),
},
bin: Some(Cow::Owned(gltf.blob.unwrap_or_default())),
json: Cow::Owned(json_string.into_bytes()),
};
let writer = std::fs::File::create(gltf_path).expect("I/O error");
glb.to_writer(writer).expect("glTF binary output error");
}
pub fn process_data(&self) {
let output_dir = Path::new(&self.args.output);
let copy_meta_files = self.args.copy_meta_files;
let tmp_path = Path::new("./tmp_dir");
let tmp_dir = Arc::new(tmp_path);
fs::create_dir(output_dir).unwrap();
self.assets.par_iter().for_each(|asset| {
let asset_hash = &asset.guid;
let path = Path::new(&asset.path);
let source_asset = Path::new(&*tmp_dir).join(asset_hash).join("asset");
asset.prepare_directory();
if copy_meta_files && asset.has_meta {
let source_meta = Path::new(&*tmp_dir).join(asset_hash).join("asset.meta");
let mut meta_path = asset.path.clone();
meta_path.push_str(".meta");
fs::rename(source_meta, meta_path).unwrap();
}
if !source_asset.exists() {
panic!("SOURCE ASSET DOES NOT EXIST: {}", source_asset.display());
}
}
fn process_fbx_file(source_asset: &Path, result_path: &Path, tool: &PathBuf) {
let out_path = result_path.with_extension("");
println!(
"{:?}",
&[
"--input",
source_asset.to_str().unwrap(),
"--output",
out_path.to_str().unwrap()
]
);
let output = Command::new(tool)
.args([
"--input",
source_asset.to_str().unwrap(),
"-b",
"--output",
out_path.to_str().unwrap(),
])
.output()
.unwrap();
let output_result = String::from_utf8_lossy(&output.stdout);
println!("output: {}", output_result);
}
if self.args.fbx_to_gltf.is_some() && asset.asset_type == AssetType::FbxModel {
self.process_fbx_file(&source_asset, path);
} else {
fs::rename(source_asset, path).unwrap();
}
});
fn process_non_fbx_file(source_asset: &Path, result_path: &Path) {
fs::rename(source_asset, result_path).unwrap();
}
fs::remove_dir_all(Path::new(&*tmp_dir)).unwrap();
}
fn process_fbx_file(&self, source_asset: &Path, result_path: &Path) {
let tool = self.args.fbx_to_gltf.clone().unwrap();
let out_path = result_path.with_extension("");
let _output = Command::new(tool)
.args([
"--input",
source_asset.to_str().unwrap(),
"-b",
"--output",
out_path.to_str().unwrap(),
])
.output()
.unwrap();
println!(
"Fbx converted to GLTF: {}",
out_path.with_extension("glb").to_str().unwrap()
);
}
fn extract_archive(archive_path: &Path, extract_to: &Path) -> io::Result<()> {

41
src/yaml_helpers.rs Normal file
View File

@ -0,0 +1,41 @@
use anyhow::Result;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
pub fn parse_unity_yaml<T: DeserializeOwned>(file: &str) -> Result<HashMap<i64, T>> {
let file = cleanup_unity_yaml(file)?;
let parse: HashMap<i64, T> = serde_yaml::from_str(&file)?;
Ok(parse)
}
fn cleanup_unity_yaml(yaml: &str) -> Result<String> {
let lines: Vec<String> = yaml
.lines()
.filter_map(|line| {
if line.starts_with("%YAML") || line.starts_with("%TAG") {
// unity specific headers. SKIP!
None
} else if line.starts_with("--- !u!") {
// unity object id declared on this line
// --- !u!104 &2 => 104 is object type and 2 is object id
let mut splits = line.split_whitespace();
let object_id: i64 = splits
.find(|&part| part.starts_with('&'))
.and_then(|num| num[1..].parse().ok())?;
Some(format!("{}:", object_id))
} else if line.starts_with(' ') {
Some(line.to_string())
} else {
Some(format!(" object_type: {}", line.replace(':', "")))
}
})
.collect();
let mut lines = lines.join("\n");
lines.push('\n'); // insert new line at the end
Ok(lines)
}