commit
b9729d8579
|
|
@ -1,5 +1,11 @@
|
|||
# Changelog
|
||||
|
||||
## [0.4.0]
|
||||
|
||||
### Added
|
||||
|
||||
- New flag `--get_materials_from_prefabs` for updating model textures based on prefabs and materials.
|
||||
|
||||
## [0.3.0]
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -9,23 +9,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
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"
|
||||
|
|
@ -80,6 +71,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
|
@ -92,6 +89,18 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
|
@ -100,9 +109,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.11"
|
||||
version = "4.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
|
||||
checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -110,9 +119,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.11"
|
||||
version = "4.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
|
||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -138,6 +147,12 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
|
|
@ -166,21 +181,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.16"
|
||||
version = "0.9.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
|
||||
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.17"
|
||||
version = "0.8.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
||||
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
|
@ -201,6 +215,15 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "209098dd6dfc4445aa6111f0e98653ac323eaa4dfd212c9ca3931bf9955c31bd"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.23"
|
||||
|
|
@ -224,14 +247,42 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
name = "gltf"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
checksum = "3b78f069cf941075835822953c345b9e1edd67ae347b81ace3aea9de38c2ef33"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"rayon",
|
||||
"base64",
|
||||
"byteorder",
|
||||
"gltf-json",
|
||||
"image",
|
||||
"lazy_static",
|
||||
"serde_json",
|
||||
"urlencoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gltf-derive"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "438ffe1a5540d75403feaf23636b164e816e93f6f03131674722b3886ce32a57"
|
||||
dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gltf-json"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655951ba557f2bc69ea4b0799446bae281fa78efae6319968bdd2c3e9a06d8e1"
|
||||
dependencies = [
|
||||
"gltf-derive",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -240,6 +291,45 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"jpeg-decoder",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inflections"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.151"
|
||||
|
|
@ -254,23 +344,21 @@ checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
|||
|
||||
[[package]]
|
||||
name = "lwa_unity_unpack"
|
||||
version = "0.2.1"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"flate2",
|
||||
"hashbrown",
|
||||
"gltf",
|
||||
"rayon",
|
||||
"regex",
|
||||
"tar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
|
|
@ -279,19 +367,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -334,6 +460,35 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.28"
|
||||
|
|
@ -347,6 +502,49 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[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.10.0"
|
||||
|
|
@ -355,9 +553,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.41"
|
||||
version = "2.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -381,18 +579,18 @@ version = "1.0.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[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"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
@ -461,31 +659,11 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
|||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.1.3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
|
||||
checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "lwa_unity_unpack"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/Leinnan/lwa_unity_unpack"
|
||||
homepage = "https://github.com/Leinnan/lwa_unity_unpack"
|
||||
|
|
@ -22,6 +22,7 @@ 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"] }
|
||||
gltf = "1.4.0"
|
||||
rayon = "1.8.0"
|
||||
regex = "1.10.2"
|
||||
tar = "0.4"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ pub struct Args {
|
|||
#[arg(short, 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>>,
|
||||
|
|
|
|||
82
src/asset.rs
82
src/asset.rs
|
|
@ -1,26 +1,75 @@
|
|||
use regex::Regex;
|
||||
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 file = File::open(&self.path).unwrap();
|
||||
let buf_reader = BufReader::new(file);
|
||||
let search = buf_reader.lines().find(|s| {
|
||||
let ss = s.as_ref().unwrap();
|
||||
ss.contains("m_Texture") && ss.contains("guid: ")
|
||||
});
|
||||
if let Some(line) = search {
|
||||
let line = line.unwrap_or_default();
|
||||
return extract_guid(&line);
|
||||
}
|
||||
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,14 +101,31 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_guid(text: &str) -> Option<String> {
|
||||
let re = Regex::new(r"guid: (?P<guid>[A-Za-z0-9]{32})").unwrap();
|
||||
re.captures(text)
|
||||
.and_then(|cap| cap.name("guid").map(|guid| guid.as_str().to_string()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,13 @@ 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();
|
||||
}
|
||||
|
|
|
|||
233
src/unpacker.rs
233
src/unpacker.rs
|
|
@ -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,6 +15,7 @@ use tar::Archive;
|
|||
#[derive(Clone)]
|
||||
pub struct Unpacker {
|
||||
pub args: crate::args::Args,
|
||||
pub assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
impl Unpacker {
|
||||
|
|
@ -36,11 +36,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 +53,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 +61,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<()> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue